* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabe Black
*/
#ifndef __BASE_TRIE_HH__
#define __BASE_TRIE_HH__
#include <cassert>
+#include <iostream>
+#include <type_traits>
#include "base/cprintf.hh"
-#include "base/misc.hh"
+#include "base/logging.hh"
#include "base/types.hh"
-// Key has to be an integral type.
+/**
+ * A trie is a tree-based data structure used for data retrieval. It uses
+ * bits masked from the msb of the key to to determine a value's location,
+ * so its lookups have their worst case time dictated by the key's size.
+ *
+ * @tparam Key Type of the key of the tree nodes. Must be an integral type.
+ * @tparam Value Type of the values associated to the keys.
+ *
+ * @ingroup api_base_utils
+ */
template <class Key, class Value>
class Trie
{
protected:
+ static_assert(std::is_integral<Key>::value,
+ "Key has to be an integral type");
+
struct Node
{
Key key;
}
void
- dump(int level)
+ dump(std::ostream &os, int level)
{
for (int i = 1; i < level; i++) {
- cprintf("|");
+ ccprintf(os, "|");
}
if (level == 0)
- cprintf("Root ");
+ ccprintf(os, "Root ");
else
- cprintf("+ ");
- cprintf("(%p, %p, %#X, %#X, %p)\n", parent, this, key, mask, value);
+ ccprintf(os, "+ ");
+ ccprintf(os, "(%p, %p, %#X, %#X, %p)\n",
+ parent, this, key, mask, value);
if (kids[0])
- kids[0]->dump(level + 1);
+ kids[0]->dump(os, level + 1);
if (kids[1])
- kids[1]->dump(level + 1);
+ kids[1]->dump(os, level + 1);
}
};
Node head;
public:
+ /**
+ * @ingroup api_base_utils
+ */
typedef Node *Handle;
+ /**
+ * @ingroup api_base_utils
+ */
Trie() : head(0, 0, NULL)
{}
+ /**
+ * @ingroup api_base_utils
+ */
static const unsigned MaxBits = sizeof(Key) * 8;
private:
* @param width How many bits of the key (from msb) should be used.
* @param val A pointer to the value to store in the trie.
* @return A Handle corresponding to this value.
+ *
+ * @ingroup api_base_utils
*/
Handle
insert(Key key, unsigned width, Value *val)
{
+ // We use NULL value pointers to mark internal nodes of the trie, so
+ // we don't allow inserting them as real values.
+ assert(val);
+
// Build a mask which masks off all the bits we don't care about.
Key new_mask = ~(Key)0;
if (width < MaxBits)
* Method which looks up the Value corresponding to a particular key.
* @param key The key to look up.
* @return The first Value matching this key, or NULL if none was found.
+ *
+ * @ingroup api_base_utils
*/
Value *
lookup(Key key)
* Method to delete a value from the trie.
* @param node A Handle to remove.
* @return The Value pointer from the removed entry.
+ *
+ * @ingroup api_base_utils
*/
Value *
remove(Handle handle)
* Method to lookup a value from the trie and then delete it.
* @param key The key to look up and then remove.
* @return The Value pointer from the removed entry, if any.
+ *
+ * @ingroup api_base_utils
*/
Value *
remove(Key key)
/**
* A method which removes all key/value pairs from the trie. This is more
* efficient than trying to remove elements individually.
+ *
+ * @ingroup api_base_utils
*/
void
clear()
* @param title An identifying title to put in the dump header.
*/
void
- dump(const char *title)
+ dump(const char *title, std::ostream &os=std::cout)
{
- cprintf("**************************************************\n");
- cprintf("*** Start of Trie: %s\n", title);
- cprintf("*** (parent, me, key, mask, value pointer)\n");
- cprintf("**************************************************\n");
- head.dump(0);
+ ccprintf(os, "**************************************************\n");
+ ccprintf(os, "*** Start of Trie: %s\n", title);
+ ccprintf(os, "*** (parent, me, key, mask, value pointer)\n");
+ ccprintf(os, "**************************************************\n");
+ head.dump(os, 0);
}
};