use reference counting to release the namespaces

This commit is contained in:
krangelov
2021-09-03 20:01:13 +02:00
parent fb2454767a
commit 4c5aad5883
2 changed files with 131 additions and 42 deletions

View File

@@ -10,91 +10,136 @@ template <class V>
using Namespace = ref<Node<V>>; using Namespace = ref<Node<V>>;
template <class V> template <class V>
class PGF_INTERNAL_DECL Node { class PGF_INTERNAL_DECL Node
{
public: public:
size_t ref_count;
size_t sz; size_t sz;
ref<V> value; ref<V> value;
ref<Node> left; ref<Node> left;
ref<Node> right; ref<Node> right;
static static
ref<Node> new_node(ref<V> value) { ref<Node> new_node(ref<V> value)
{
ref<Node> node = current_db->malloc<Node>(); ref<Node> node = current_db->malloc<Node>();
node->sz = 1; node->ref_count = 1;
node->value = value; node->sz = 1;
node->left = 0; node->value = value;
node->right = 0; node->left = 0;
node->right = 0;
return node; return node;
} }
static static
ref<Node> new_node(ref<V> value, ref<Node> left, ref<Node> right) { ref<Node> new_node(ref<V> value, ref<Node> left, ref<Node> right)
{
ref<Node> node = current_db->malloc<Node>(); ref<Node> node = current_db->malloc<Node>();
node->sz = 1+namespace_size(left)+namespace_size(right); node->ref_count = 1;
node->value = value; node->sz = 1+namespace_size(left)+namespace_size(right);
node->left = left; node->value = value;
node->right = right; node->left = left;
node->right = right;
return node; return node;
} }
static static
ref<Node> balanceL(ref<V> value, ref<Node> left, ref<Node> right) { ref<Node> balanceL(ref<V> value, ref<Node> left, ref<Node> right)
{
if (right == 0) { if (right == 0) {
if (left == 0) { if (left == 0) {
return new_node(value); return new_node(value);
} else { } else {
if (left->left == 0) { if (left->left == 0) {
if (left->right == 0) { if (left->right == 0) {
left->ref_count++;
return new_node(value,left,0); return new_node(value,left,0);
} else { } else {
Namespace<V> new_left = new_node(left->value);
Namespace<V> new_right = new_node(value);
return new_node(left->right->value, return new_node(left->right->value,
new_node(left->value), new_left,
new_node(value)); new_right);
} }
} else { } else {
if (left->right == 0) { if (left->right == 0) {
Namespace<V> new_right = new_node(value);
left->left->ref_count++;
return new_node(left->value, return new_node(left->value,
left->left, left->left,
new_node(value)); new_right);
} else { } else {
if (left->right->sz < 2 * left->left->sz) { if (left->right->sz < 2 * left->left->sz) {
left->left->ref_count++;
left->right->ref_count++;
Namespace<V> new_right =
new_node(value,
left->right,
0);
return new_node(left->value, return new_node(left->value,
left->left, left->left,
new_node(value, new_right);
left->right,
0));
} else { } else {
left->left->ref_count++;
if (left->right->left != 0)
left->right->left->ref_count++;
if (left->right->right != 0)
left->right->right->ref_count++;
Namespace<V> new_left =
new_node(left->value,
left->left,
left->right->left);
Namespace<V> new_right =
new_node(value,
left->right->right,
0);
return new_node(left->right->value, return new_node(left->right->value,
new_node(left->value, new_left,
left->left, new_right);
left->right->left),
new_node(value,
left->right->right,
0));
} }
} }
} }
} }
} else { } else {
if (left == 0) { if (left == 0) {
right->ref_count++;
return new_node(value,0,right); return new_node(value,0,right);
} else { } else {
if (left->sz > 3*right->sz) { if (left->sz > 3*right->sz) {
if (left->right->sz < 2*left->left->sz) if (left->right->sz < 2*left->left->sz) {
left->left->ref_count++;
left->right->ref_count++;
right->ref_count++;
Namespace<V> new_right =
new_node(value,
left->right,
right);
return new_node(left->value, return new_node(left->value,
left->left, left->left,
new_node(value, new_right);
left->right, } else {
right)); left->left->ref_count++;
else if (left->right->left != 0)
left->right->left->ref_count++;
if (left->right->right != 0)
left->right->right->ref_count++;
right->ref_count++;
Namespace<V> new_left =
new_node(left->value,
left->left,
left->right->left);
Namespace<V> new_right =
new_node(value,
left->right->right,
right);
return new_node(left->right->value, return new_node(left->right->value,
new_node(left->value, new_left,
left->left, new_right);
left->right->left), }
new_node(value,
left->right->right,
right));
} else { } else {
left->ref_count++;
right->ref_count++;
return new_node(value,left,right); return new_node(value,left,right);
} }
} }
@@ -102,15 +147,18 @@ public:
} }
static static
ref<Node> balanceR(ref<V> value, ref<Node> left, ref<Node> right) { ref<Node> balanceR(ref<V> value, ref<Node> left, ref<Node> right)
{
if (left == 0) { if (left == 0) {
if (right == 0) { if (right == 0) {
return new_node(value); return new_node(value);
} else { } else {
if (right->left == 0) { if (right->left == 0) {
if (right->right == 0) { if (right->right == 0) {
right->ref_count++;
return new_node(value,0,right); return new_node(value,0,right);
} else { } else {
right->right->ref_count++;
Namespace<V> new_left = Namespace<V> new_left =
new_node(value); new_node(value);
return new_node(right->value, return new_node(right->value,
@@ -128,6 +176,8 @@ public:
new_right); new_right);
} else { } else {
if (right->left->sz < 2 * right->right->sz) { if (right->left->sz < 2 * right->right->sz) {
right->left->ref_count++;
right->right->ref_count++;
Namespace<V> new_left = Namespace<V> new_left =
new_node(value, new_node(value,
0, 0,
@@ -136,6 +186,11 @@ public:
new_left, new_left,
right->right); right->right);
} else { } else {
if (right->left->left != 0)
right->left->left->ref_count++;
if (right->left->right != 0)
right->left->right->ref_count++;
right->right->ref_count++;
Namespace<V> new_left = Namespace<V> new_left =
new_node(value, new_node(value,
0, 0,
@@ -153,10 +208,14 @@ public:
} }
} else { } else {
if (right == 0) { if (right == 0) {
left->ref_count++;
return new_node(value,left,0); return new_node(value,left,0);
} else { } else {
if (right->sz > 3*left->sz) { if (right->sz > 3*left->sz) {
if (right->left->sz < 2*right->right->sz) { if (right->left->sz < 2*right->right->sz) {
left->ref_count++;
right->left->ref_count++;
right->right->ref_count++;
Namespace<V> new_left = Namespace<V> new_left =
new_node(value, new_node(value,
left, left,
@@ -165,6 +224,12 @@ public:
new_left, new_left,
right->right); right->right);
} else { } else {
left->ref_count++;
if (right->left->left != 0)
right->left->left->ref_count++;
if (right->left->right != 0)
right->left->right->ref_count++;
right->right->ref_count++;
Namespace<V> new_left = Namespace<V> new_left =
new_node(value, new_node(value,
left, left,
@@ -175,10 +240,11 @@ public:
right->right); right->right);
return new_node(right->left->value, return new_node(right->left->value,
new_left, new_left,
new_right new_right);
);
} }
} else { } else {
left->ref_count++;
right->ref_count++;
return new_node(value,left,right); return new_node(value,left,right);
} }
} }
@@ -207,12 +273,19 @@ Namespace<V> namespace_insert(Namespace<V> map, ref<V> value)
int cmp = textcmp(&value->name,&map->value->name); int cmp = textcmp(&value->name,&map->value->name);
if (cmp < 0) { if (cmp < 0) {
Namespace<V> left = namespace_insert(map->left, value); Namespace<V> left = namespace_insert(map->left, value);
return Node<V>::balanceL(map->value,left,map->right); Namespace<V> node = Node<V>::balanceL(map->value,left,map->right);
namespace_release(left);
return node;
} else if (cmp > 0) { } else if (cmp > 0) {
Namespace<V> right = namespace_insert(map->right, value); Namespace<V> right = namespace_insert(map->right, value);
return Node<V>::balanceR(map->value, map->left, right); Namespace<V> node = Node<V>::balanceR(map->value, map->left, right);
} else namespace_release(right);
return node;
} else {
map->left->ref_count++;
map->right->ref_count++;
return Node<V>::new_node(value,map->left,map->right); return Node<V>::new_node(value,map->left,map->right);
}
} }
template <class V> template <class V>
@@ -256,4 +329,18 @@ void namespace_iter(Namespace<V> map, PgfItor* itor, PgfExn *err)
if (err->type != PGF_EXN_NONE) if (err->type != PGF_EXN_NONE)
return; return;
} }
template <class V>
void namespace_release(Namespace<V> node)
{
if (node == 0)
return;
if (!(--node->ref_count)) {
namespace_release(node->left);
namespace_release(node->right);
DB::free(node);
}
}
#endif #endif

View File

@@ -154,7 +154,9 @@ Namespace<V> PgfReader::read_namespace(ref<V> (PgfReader::*read_value)())
Namespace<V> nmsp = 0; Namespace<V> nmsp = 0;
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
ref<V> value = (this->*read_value)(); ref<V> value = (this->*read_value)();
nmsp = namespace_insert(nmsp, value); Namespace<V> new_nmsp = namespace_insert(nmsp, value);
namespace_release(nmsp);
nmsp = new_nmsp;
} }
return nmsp; return nmsp;
} }