#ifndef NAMESPACE_H #define NAMESPACE_H #include "db.h" // #define DEBUG_NAMESPACE /* Namespace expects that the class V contains, * a member 'PgfText name' which contains the name of the object. */ template class Node; template using Namespace = ref>>; template class PGF_INTERNAL_DECL Node { public: txn_t txn_id; size_t sz; V value; ref left; ref right; static ref new_node(V value) { ref node = PgfDB::malloc(); node->txn_id = PgfDB::get_txn_id(); 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 upd_node(ref node, ref left, ref right) { if (node->txn_id != PgfDB::get_txn_id()) { ref new_node = PgfDB::malloc(); new_node->txn_id = PgfDB::get_txn_id(); new_node->value = node->value; release(node); node = new_node; #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 } node->sz = 1+Node::size(left)+Node::size(right); node->left = left; node->right = right; return node; } static ref balanceL(ref node) { if (node->right == 0) { if (node->left == 0) { return node; } else { if (node->left->left == 0) { if (node->left->right == 0) { return node; } else { ref> left_right = node->left->right; ref> left = upd_node(node->left,0,0); ref> right = upd_node(node,0,0); return upd_node(left_right, left, right); } } else { if (node->left->right == 0) { ref> left = node->left; ref> right = upd_node(node,0,0); return upd_node(left, left->left, right); } else { if (node->left->right->sz < 2 * node->left->left->sz) { ref> left = node->left; ref> right = upd_node(node, left->right, 0); return upd_node(left, left->left, right); } else { ref> left_right = node->left->right; ref> left = upd_node(node->left, node->left->left, left_right->left); ref> right = upd_node(node, left_right->right, 0); return upd_node(left_right, left, right); } } } } } else { if (node->left == 0) { return node; } else { if (node->left->sz > 3*node->right->sz) { if (node->left->right->sz < 2*node->left->left->sz) { ref> left = node->left; ref> right = upd_node(node, left->right, node->right); return upd_node(left, left->left, right); } else { ref> left_right = node->left->right; ref> left = upd_node(node->left, node->left->left, left_right->left); ref> right = upd_node(node, left_right->right, node->right); return upd_node(left_right, left, right); } } else { return node; } } } } static ref balanceR(ref node) { if (node->left == 0) { if (node->right == 0) { return node; } else { if (node->right->left == 0) { if (node->right->right == 0) { return node; } else { ref> right = node->right; ref> left = upd_node(node, 0, 0); return upd_node(right, left, right->right); } } else { if (node->right->right == 0) { ref> right_left = node->right->left; ref> right = upd_node(node->right,0,0); ref> left = upd_node(node,0,0); return upd_node(right_left, left, right); } else { if (node->right->left->sz < 2 * node->right->right->sz) { ref> right = node->right; ref> left = upd_node(node, 0, right->left); return upd_node(right, left, right->right); } else { ref> right_left = node->right->left; ref> right = upd_node(node->right, right_left->right, node->right->right); ref> left = upd_node(node, 0, right_left->left); return upd_node(right_left, left, right); } } } } } else { if (node->right == 0) { return node; } else { if (node->right->sz > 3*node->left->sz) { if (node->right->left->sz < 2*node->right->right->sz) { ref> right = node->right; ref> left = upd_node(node, node->left, right->left); return upd_node(right, left, right->right); } else { ref> right_left = node->right->left; ref> right = upd_node(node->right, right_left->right, node->right->right); ref> left = upd_node(node, node->left, right_left->left); return upd_node(right_left, left, right); } } else { return node; } } } } static size_t size(ref node) { if (node == 0) return 0; return node->sz; } static ref pop_first(ref node, ref *res) { if (node == 0) { return 0; } else if (node->left == 0) { *res = node; return node->right; } else { ref left = pop_first(node->left, res); node = upd_node(node, left, node->right); return balanceR(node); } } static ref pop_last(ref node, ref *res) { if (node == 0) { return 0; } else if (node->right == 0) { *res = node; return node->left; } else { ref right = pop_last(node->right, res); node = upd_node(node, node->left, right); return balanceL(node); } } static void release(ref node) { #ifdef DEBUG_NAMESPACE printf("release node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count-1); #endif PgfDB::free(node); } }; 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); map = Node>::upd_node(map,left,map->right); return Node>::balanceL(map); } else if (cmp > 0) { Namespace right = namespace_insert(map->right, value); map = Node>::upd_node(map,map->left,right); return Node>::balanceR(map); } else { map = Node>::upd_node(map,map->left,map->right); map->value = value; return map; } } static constexpr char alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyz"; template class PgfNameAllocator { size_t available; size_t fixed; size_t base; ref value; PgfText *name; Namespace insert(Namespace map) { if (map == 0) { value = PgfDB::malloc(name->size+1); memcpy(&value->name, name, sizeof(PgfText)+name->size+1); return Node>::new_node(value); } int cmp = textcmp(name,&map->value->name); if (cmp < 0) { Namespace left = insert(map->left); if (left != 0) { map = Node>::upd_node(map,left,map->right); return Node>::balanceL(map); } } else if (cmp > 0) { Namespace right = insert(map->right); if (right != 0) { map = Node>::upd_node(map,map->left,right); return Node>::balanceR(map); } } return 0; } public: PgfNameAllocator(PgfText *name_pattern) { available = name_pattern->size; fixed = 0; base = 0; value = 0; name = (PgfText *) malloc(sizeof(PgfText)+name_pattern->size+1); if (name == NULL) throw pgf_systemerror(ENOMEM); size_t i = 0, j = 0; while (i < name_pattern->size) { if (name_pattern->text[i] == '%') { i++; if (name_pattern->text[i] == 'd') { base = 10; } else if (name_pattern->text[i] == 'x') { base = 16; } else if (name_pattern->text[i] == 'a') { base = 36; } else if (name_pattern->text[i] == '%') { name->text[j++] = '%'; i++; continue; } else { name->text[j++] = '%'; continue; } i++; name->text[j++] = '1' + PgfDB::rand() % 9; fixed = j; } else { name->text[j++] = name_pattern->text[i++]; } } name->size = j; name->text[j] = 0; } ~PgfNameAllocator() { if (name) free(name); } void fetch_name_value(PgfText **pname, ref *pvalue) { *pname = name; name = NULL; *pvalue = value; value = 0; } Namespace allocate(Namespace map) { for (;;) { Namespace new_map = insert(map); if (new_map != 0) return new_map; if (name->size >= available) { size_t new_size = name->size + 10; PgfText *new_name = (PgfText *) realloc(name, sizeof(PgfText)+new_size+1); if (new_name == NULL) { throw pgf_systemerror(ENOMEM); } name = new_name; available = new_size; } size_t i = name->size++; while (i >= fixed) { name->text[i+1] = name->text[i]; i--; } name->text[i+1] = alphabet[PgfDB::rand() % base]; fixed++; } } }; template Namespace namespace_delete(Namespace map, PgfText* name, ref *pvalue) { if (map == 0) { if (pvalue != NULL) *pvalue = 0; return 0; } int cmp = textcmp(name,&map->value->name); if (cmp < 0) { Namespace left = namespace_delete(map->left, name, pvalue); map = Node>::upd_node(map,left,map->right); return Node>::balanceR(map); } else if (cmp > 0) { Namespace right = namespace_delete(map->right, name, pvalue); map = Node>::upd_node(map,map->left,right); return Node>::balanceL(map); } else { if (pvalue != NULL) *pvalue = map->value; if (map->left == 0) { Node>::release(map); return map->right; } else if (map->right == 0) { Node>::release(map); return map->left; } else if (map->left->sz > map->right->sz) { Namespace node; Namespace left = Node>::pop_last(map->left, &node); node = Node>::upd_node(node, left, map->right); Node>::release(map); return Node>::balanceR(node); } else { Namespace node; Namespace right = Node>::pop_first(map->right, &node); node = Node>::upd_node(node, map->left, right); Node>::release(map); return Node>::balanceL(node); } } } 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) { return Node>::size(map); } 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_vec_fill_names(Namespace node, size_t offs, Vector *vec) { if (node == 0) return; namespace_vec_fill_names(node->left, offs, vec); offs += namespace_size(node->left); vector_elem(vec, offs++)->name = &node->value->name; namespace_vec_fill_names(node->right, offs, vec); } template Vector *namespace_to_sorted_names(Namespace node) { Vector *vec = (Vector *) malloc(sizeof(Vector)+node->sz*sizeof(A)); if (errno != 0) throw pgf_systemerror(errno); vec->len = node->sz; memset(vec->data, 0, node->sz*sizeof(A)); namespace_vec_fill_names(node, 0, vec); return vec; } template void namespace_release(Namespace node) { if (node == 0) return; namespace_release(node->left); namespace_release(node->right); Node>::release(node); } #endif