X-Git-Url: http://git.buserror.net/cgi-bin/gitweb.cgi?p=polintos%2Fscott%2Fpriv.git;a=blobdiff_plain;f=include%2Fc%2B%2B%2Futil%2Fradix.h;h=3dcaaaf993a156099a968b76517215449ac2d910;hp=48603f6aa012e4994a40458fa1e330aa9ea1ae71;hb=6ef00363db1c75274dfcc188c778cb437d896034;hpb=b23d2e75df5a92922637d3195ed38c5f06a0f68a diff --git a/include/c++/util/radix.h b/include/c++/util/radix.h index 48603f6..3dcaaaf 100644 --- a/include/c++/util/radix.h +++ b/include/c++/util/radix.h @@ -18,17 +18,17 @@ #include namespace Util { - // Each leaf node in the tree will contain 2**radix_bits handles. + // Each leaf node in the tree will contain 2**radix_bits nodes. // Each directory node will contain 2**dir_bits pointers. - - template - class RadixTree { - typedef unsigned int Key; + // Key must be an unsigned integer. + template + class RadixTree { enum { node_size = 1 << radix_bits, dir_size = 1 << dir_bits, - long_bits = sizeof(unsigned long) * 8, + key_bits = sizeof(Key) * 8, }; struct Node { @@ -41,17 +41,16 @@ namespace Util { }; struct LeafNode : public Node { - T handles[node_size]; + T nodes[node_size]; LeafNode() : Node(0) { - shift = 0; - memset(handles, 0, sizeof(handles)); + memset(nodes, 0, sizeof(nodes)); } }; struct DirNode : public Node { - Node *ptrs[node_size]; + Node *ptrs[dir_size]; DirNode(int shift) : Node(shift) { @@ -70,7 +69,7 @@ namespace Util { { return key & (node_size - 1); } - + public: // The tree depth is contained in each node, and nodes are never // removed from the tree, so lockless lookups are possible. @@ -78,52 +77,55 @@ namespace Util { T *lookup(Key key, bool add = false) { - int next_shift = toplevel->shift == 0 ? radix_bits : dir_bits; + Node *node = toplevel; + int next_shift = node->shift ? node->shift + dir_bits : radix_bits; - while (unlikely(key_to_dir_offset(key, toplevel->shift + - next_shift) != 0)) + while (unlikely(next_shift < key_bits && (key >> next_shift))) { if (!add) return NULL; - Node *new_node = new DirNode(toplevel->shift + next_shift); - new_node->ptrs[0] = toplevel; - toplevel = new_node; - next_shift = dir_bits; + DirNode *dn = new DirNode(next_shift); + dn->ptrs[0] = node; + toplevel = dn; + next_shift += dir_bits; } - Node *node = toplevel; + node = toplevel; while (node->shift > 0) { - assert(node->shift >= radix_bits); - int off = key_to_dir_offset(key, node->shift); - NodeBase *new_node = node[off]; + DirNode *dn = static_cast(node); + node = dn->ptrs[off]; - if (!new_node) { + if (!node) { if (!add) return NULL; - if (node->shift == radix_bits) - new_node = new LeafNode; + if (dn->shift == radix_bits) + node = new LeafNode; else - new_node = new DirNode(node->shift - dir_shift); + node = new DirNode(dn->shift == radix_bits ? + 0 : dn->shift - dir_bits); - node[off] = new_node; + dn->ptrs[off] = node; } - - node = new_node; } - assert(node->shift == 0); - return node[key_to_offset(key)]; + LeafNode *ln = static_cast(node); + return &ln->nodes[key_to_offset(key)]; } RadixTree() { + // OPT: start with a NULL toplevel. Besides avoiding wasting + // memory for empty trees, it avoids the need for a stack of + // trees down the ptr[0] path if there are no small keys. + toplevel = new LeafNode; } }; + } #endif