#ifndef NAMESPACE_H #define NAMESPACE_H #include "db.h" // #define DEBUG_NAMESPACE /* Namespace expects that the class V contains: * * - A member 'size_t ref_count' which keeps track of the number of * references to the particular object. * - A member 'PgfText name' which contains the name of the object. * - A method: * static void release(ref object) * which is executed when ref_count becomes zero. After that the memory * for the object is released as well. */ template class Node; template using Namespace = ref>; template class PGF_INTERNAL_DECL Node { public: size_t ref_count; size_t sz; ref value; ref left; ref right; static ref new_node(ref value) { ref node = current_db->malloc(); node->ref_count = 1; node->sz = 1; node->value = value; node->left = 0; node->right = 0; #ifdef DEBUG_NAMESPACE printf("new node %6ld %s\n", node.as_object(), node->value->name.text); #endif return node; } static ref new_node(ref value, ref left, ref right) { ref node = current_db->malloc(); node->ref_count = 1; node->sz = 1+namespace_size(left)+namespace_size(right); node->value = value; node->left = left; node->right = right; #ifdef DEBUG_NAMESPACE printf("new node %6ld %s(%ld,%ld)\n", node.as_object(), node->value->name.text, left.as_object(), right.as_object()); #endif return node; } static void add_node_ref(ref node) { node->ref_count++; #ifdef DEBUG_NAMESPACE printf("add_ref node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count); #endif } static void add_value_ref(ref value) { value->ref_count++; #ifdef DEBUG_NAMESPACE printf("add_ref value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count); #endif } static ref balanceL(ref value, ref left, ref right) { if (right == 0) { if (left == 0) { value->ref_count++; return new_node(value); } else { if (left->left == 0) { if (left->right == 0) { add_value_ref(value); add_node_ref(left); return new_node(value,left,0); } else { add_value_ref(value); add_value_ref(left->value); add_value_ref(left->right->value); Namespace new_left = new_node(left->value); Namespace new_right = new_node(value); return new_node(left->right->value, new_left, new_right); } } else { if (left->right == 0) { add_value_ref(value); Namespace new_right = new_node(value); add_value_ref(left->value); add_node_ref(left->left); return new_node(left->value, left->left, new_right); } else { if (left->right->sz < 2 * left->left->sz) { add_value_ref(value); add_value_ref(left->value); add_node_ref(left->left); add_node_ref(left->right); Namespace new_right = new_node(value, left->right, 0); return new_node(left->value, left->left, new_right); } else { add_value_ref(value); add_value_ref(left->value); add_value_ref(left->right->value); add_node_ref(left->left); if (left->right->left != 0) add_node_ref(left->right->left); if (left->right->right != 0) add_node_ref(left->right->right); Namespace new_left = new_node(left->value, left->left, left->right->left); Namespace new_right = new_node(value, left->right->right, 0); return new_node(left->right->value, new_left, new_right); } } } } } else { if (left == 0) { add_value_ref(value); add_node_ref(right); return new_node(value,0,right); } else { if (left->sz > 3*right->sz) { if (left->right->sz < 2*left->left->sz) { add_value_ref(value); add_value_ref(left->value); add_node_ref(left->left); add_node_ref(left->right); add_node_ref(right); Namespace new_right = new_node(value, left->right, right); return new_node(left->value, left->left, new_right); } else { add_value_ref(value); add_value_ref(left->value); add_value_ref(left->right->value); add_node_ref(left->left); if (left->right->left != 0) add_node_ref(left->right->left); if (left->right->right != 0) add_node_ref(left->right->right); add_node_ref(right); Namespace new_left = new_node(left->value, left->left, left->right->left); Namespace new_right = new_node(value, left->right->right, right); return new_node(left->right->value, new_left, new_right); } } else { add_value_ref(value); add_node_ref(left); add_node_ref(right); return new_node(value,left,right); } } } } static ref balanceR(ref value, ref left, ref right) { if (left == 0) { if (right == 0) { add_value_ref(value); return new_node(value); } else { if (right->left == 0) { if (right->right == 0) { add_value_ref(value); add_node_ref(right); return new_node(value,0,right); } else { add_value_ref(value); add_value_ref(right->value); add_node_ref(right->right); Namespace new_left = new_node(value); return new_node(right->value, new_left, right->right); } } else { if (right->right == 0) { add_value_ref(value); add_value_ref(right->value); add_value_ref(right->left->value); Namespace new_left = new_node(value); Namespace new_right = new_node(right->value); return new_node(right->left->value, new_left, new_right); } else { if (right->left->sz < 2 * right->right->sz) { add_value_ref(value); add_value_ref(right->value); add_node_ref(right->left); add_node_ref(right->right); Namespace new_left = new_node(value, 0, right->left); return new_node(right->value, new_left, right->right); } else { add_value_ref(value); add_value_ref(right->value); add_value_ref(right->left->value); if (right->left->left != 0) add_node_ref(right->left->left); if (right->left->right != 0) add_node_ref(right->left->right); add_node_ref(right->right); Namespace new_left = new_node(value, 0, right->left->left); Namespace new_right = new_node(right->value, right->left->right, right->right); return new_node(right->left->value, new_left, new_right); } } } } } else { if (right == 0) { add_value_ref(value); add_node_ref(left); return new_node(value,left,0); } else { if (right->sz > 3*left->sz) { if (right->left->sz < 2*right->right->sz) { add_value_ref(value); add_value_ref(right->value); add_node_ref(left); add_node_ref(right->left); add_node_ref(right->right); Namespace new_left = new_node(value, left, right->left); return new_node(right->value, new_left, right->right); } else { add_value_ref(value); add_value_ref(right->value); add_value_ref(right->left->value); add_node_ref(left); if (right->left->left != 0) add_node_ref(right->left->left); if (right->left->right != 0) add_node_ref(right->left->right); add_node_ref(right->right); Namespace new_left = new_node(value, left, right->left->left); Namespace new_right = new_node(right->value, right->left->right, right->right); return new_node(right->left->value, new_left, new_right); } } else { add_value_ref(value); add_node_ref(left); add_node_ref(right); return new_node(value,left,right); } } } } }; template Namespace namespace_empty() { return 0; } template Namespace namespace_singleton(ref value) { return Node::new_node(value); } template Namespace namespace_insert(Namespace map, ref value) { if (map == 0) return Node::new_node(value); int cmp = textcmp(&value->name,&map->value->name); if (cmp < 0) { Namespace left = namespace_insert(map->left, value); Namespace node = Node::balanceL(map->value,left,map->right); namespace_release(left); return node; } else if (cmp > 0) { Namespace right = namespace_insert(map->right, value); Namespace node = Node::balanceR(map->value, map->left, right); namespace_release(right); return node; } else { if (map->left != 0) map->left->ref_count++; if (map->right != 0) map->right->ref_count++; return Node::new_node(value,map->left,map->right); } } template Namespace namespace_delete(Namespace map, PgfText* name) { if (map == 0) return 0; int cmp = textcmp(name,&map->value->name); if (cmp < 0) { Namespace left = namespace_delete(map->left, name); if (left == map->left) return map; Namespace node = Node::balanceR(map->value,left,map->right); namespace_release(left); return node; } else if (cmp > 0) { Namespace right = namespace_delete(map->right, name); if (right == map->right) return map; Namespace node = Node::balanceL(map->value,map->left,right); namespace_release(right); return node; } else { if (map->left == 0) { if (map->right != 0) map->right->ref_count++; return map->right; } else if (map->right == 0) { if (map->left != 0) map->left->ref_count++; return map->left; } else if (map->left->sz > map->right->sz) { ref value; Namespace new_left = namespace_pop_last(map->left, &value); Namespace node = Node::balanceR(value, new_left, map->right); namespace_release(new_left); return node; } else { ref value; Namespace new_right = namespace_pop_first(map->right, &value); Namespace node = Node::balanceL(value, map->left, new_right); namespace_release(new_right); return node; } } } template Namespace namespace_pop_first(Namespace map, ref *res) { if (map == 0) { return 0; } else if (map->left == 0) { *res = map->value; if (map->right != 0) map->right->ref_count++; return map->right; } else { Namespace new_left = namespace_pop_first(map->left, res); Namespace node = Node::balanceR(map->value, new_left, map->right); namespace_release(new_left); return node; } } template Namespace namespace_pop_last(Namespace map, ref *res) { if (map == 0) { return 0; } else if (map->right == 0) { *res = map->value; if (map->left != 0) map->left->ref_count++; return map->left; } else { Namespace new_right = namespace_pop_last(map->right, res); return Node::balanceR(map->value, map->left, new_right); } } template ref namespace_lookup(Namespace map, PgfText *name) { while (map != 0) { int cmp = textcmp(name,&map->value->name); if (cmp < 0) map = map->left; else if (cmp > 0) map = map->right; else return map->value; } return 0; } template size_t namespace_size(Namespace map) { if (map == 0) return 0; return map->sz; } template void namespace_iter(Namespace map, PgfItor* itor, PgfExn *err) { if (map == 0) return; namespace_iter(map->left, itor, err); if (err->type != PGF_EXN_NONE) return; itor->fn(itor, &map->value->name, map->value.as_object(), err); if (err->type != PGF_EXN_NONE) return; namespace_iter(map->right, itor, err); if (err->type != PGF_EXN_NONE) return; } template void namespace_release(Namespace node) { if (node == 0) return; #ifdef DEBUG_NAMESPACE printf("release node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count-1); #endif if (!(--node->ref_count)) { namespace_release(node->left); namespace_release(node->right); #ifdef DEBUG_NAMESPACE printf("release value %5ld %s (ref_count=%ld)\n", node->value.as_object(), node->value->name.text, node->value->ref_count-1); #endif if (!(--node->value->ref_count)) { V::release(node->value); PgfDB::free(node->value); } PgfDB::free(node); } } #endif