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;fp=include%2Fc%2B%2B%2Futil%2Fradix.h;h=b75d27e79a5c06fcc1fad556505da6b70f9bd539;hp=0000000000000000000000000000000000000000;hb=0c52a8435aa399781856869daa7ef30cef14fad5;hpb=db11b9a38323d994d42303c6149c9e06ff29b7d2 diff --git a/include/c++/util/radix.h b/include/c++/util/radix.h new file mode 100644 index 0000000..b75d27e --- /dev/null +++ b/include/c++/util/radix.h @@ -0,0 +1,126 @@ +// Generic radix trees, which supports mapping integer keys to objects. +// +// Written by Scott Wood . +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors or contributors be held liable for any damages +// arising from the use of this software. +// +// This software is in the public domain. + +#ifndef _UTIL_RADIX_H +#define _UTIL_RADIX_H + +#include +#include +#include + +#include + +namespace Util { + // Each leaf node in the tree will contain 2**radix_bits handles. + // Each directory node will contain 2**dir_bits pointers. + template + class RadixTree { + typedef unsigned int Key; + + enum { + node_size = 1 << radix_bits, + dir_size = 1 << dir_bits, + long_bits = sizeof(unsigned long) * 8, + }; + + struct Node { + const int shift; + + protected: + Node(int SHIFT) : shift(SHIFT) + { + } + }; + + struct LeafNode : public Node { + T handles[node_size]; + + LeafNode() : Node(0) + { + shift = 0; + memset(handles, 0, sizeof(handles)); + } + }; + + struct DirNode : public Node { + Node *ptrs[node_size]; + + DirNode(int shift) : Node(shift) + { + memset(ptrs, 0, sizeof(ptrs)); + } + }; + + Node *toplevel; + + static int key_to_dir_offset(Key key, int shift) + { + return (key >> shift) & (dir_size - 1); + } + + static uint key_to_offset(Key key) + { + return key & (node_size - 1); + } + + public: + T *lookup(Key key, bool add = false) + { + int next_shift = toplevel->shift == 0 ? radix_bits : dir_bits; + + while (unlikely(key_to_dir_offset(key, toplevel->shift + + next_shift) != 0)) + { + 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; + } + + Node *node = toplevel; + + while (node->shift >= radix_bits) { + int off = key_to_dir_offset(key, node->shift); + NodeBase *new_node = node[off]; + + shift == 0 ? new LeafNode + : new DirNode(shift); + void *new_node = static_cast(node)[off]; + + if (!new_node) { + if (!add) + return NULL; + + new_node = Mem::alloc_pages(1); + memset(new_node, 0, Arch::page_size); + static_cast(node)[off] = new_node; + } + + shift -= dir_shift; + node = new_node; + } + + assert(shift == 0); + return static_cast(node) + key_to_offset(key, 0); + } + + RadixTree() + { + toplevel = new LeafNode; + memset(toplevel, 0, Arch::page_size); + depth = 0; + } + }; +} + +#endif