From 856c114ca09d13d40c3504944e2d342cfe91095c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 5 Jul 2011 22:45:06 +0200 Subject: [PATCH] Add TwoKeyAVLTree to kernel utils This is a tree implementation with elements with primary and secondary key. The code is a cleaned up version of ramfs's implementation. ramfs doesn't use this version yet. --- headers/private/kernel/util/TwoKeyAVLTree.h | 513 ++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 headers/private/kernel/util/TwoKeyAVLTree.h diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/headers/private/kernel/util/TwoKeyAVLTree.h new file mode 100644 index 0000000000..9ab0525968 --- /dev/null +++ b/headers/private/kernel/util/TwoKeyAVLTree.h @@ -0,0 +1,513 @@ +/* + * Copyright 2003-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_UTIL_TWO_KEY_AVL_TREE_H +#define _KERNEL_UTIL_TWO_KEY_AVL_TREE_H + + +#include + + +// #pragma mark - TwoKeyAVLTreeKey + + +template +class TwoKeyAVLTreeKey { +public: + inline TwoKeyAVLTreeKey(const PrimaryKey& primary, + const SecondaryKey& secondary) + : + primary(primary), + secondary(secondary), + use_secondary(true) + { + } + + inline TwoKeyAVLTreeKey(const PrimaryKey* primary) + : + primary(primary), + secondary(NULL), + use_secondary(false) + { + } + + PrimaryKey primary; + SecondaryKey secondary; + bool use_secondary; +}; + + +// #pragma mark - TwoKeyAVLTreeKeyCompare + + +template +class TwoKeyAVLTreeKeyCompare { +private: + typedef TwoKeyAVLTreeKey Key; + +public: + inline TwoKeyAVLTreeKeyCompare(const PrimaryKeyCompare& primary, + const SecondaryKeyCompare& secondary) + : + fPrimaryKeyCompare(primary), + fSecondaryKeyCompare(secondary) + { + } + + inline int operator()(const Key& a, const Key& b) const + { + int result = fPrimaryKeyCompare(a.primary, b.primary); + if (result == 0 && a.use_secondary && b.use_secondary) + result = fSecondaryKeyCompare(a.secondary, b.secondary); + return result; + } + +private: + PrimaryKeyCompare fPrimaryKeyCompare; + SecondaryKeyCompare fSecondaryKeyCompare; +}; + + +// #pragma mark - TwoKeyAVLTreeGetKey + + +template +class TwoKeyAVLTreeGetKey { +private: + typedef TwoKeyAVLTreeKey Key; + +public: + TwoKeyAVLTreeGetKey(const GetPrimaryKey& getPrimary, + const GetSecondaryKey& getSecondary) + : + fGetPrimaryKey(getPrimary), + fGetSecondaryKey(getSecondary) + { + } + + inline Key operator()(const Value& a) const + { + return Key(fGetPrimaryKey(a), fGetSecondaryKey(a)); + } + +private: + GetPrimaryKey fGetPrimaryKey; + GetSecondaryKey fGetSecondaryKey; +}; + + +// #pragma mark - TwoKeyAVLTreeStandardCompare + + +template +class TwoKeyAVLTreeStandardCompare { +public: + inline int operator()(const Value& a, const Value& b) const + { + if (a < b) + return -1; + else if (a > b) + return 1; + return 0; + } +}; + + +// #pragma mark - TwoKeyAVLTreeStandardGetKey + + +template +class TwoKeyAVLTreeStandardGetKey { +public: + inline const Key& operator()(const Value& a) const + { + return a; + } + + inline Key& operator()(Value& a) const + { + return a; + } +}; + + +// #pragma mark - TwoKeyAVLTreeNodeStrategy + + +template +class TwoKeyAVLTreeNodeStrategy { +public: + typedef TwoKeyAVLTreeKey Key; + + TwoKeyAVLTreeNodeStrategy( + const PrimaryKeyCompare& primaryKeyCompare = PrimaryKeyCompare(), + const SecondaryKeyCompare& secondaryKeyCompare = SecondaryKeyCompare(), + const GetPrimaryKey& getPrimaryKey = GetPrimaryKey(), + const GetSecondaryKey& getSecondaryKey = GetSecondaryKey()) + : + fPrimaryKeyCompare(primaryKeyCompare), + fSecondaryKeyCompare(secondaryKeyCompare), + fGetPrimaryKey(getPrimaryKey), + fGetSecondaryKey(getSecondaryKey) + { + } + + struct Node : AVLTreeNode { + Node(const Value& value) + : + AVLTreeNode(), + value(value) + { + } + + Value value; + }; + + inline Node* Allocate(const Key& key, const Value& value) const + { + return new(nothrow) Node(value); + } + + inline void Free(Node* node) const + { + delete node; + } + + // internal use (not part of the strategy) + inline Key GetValueKey(const Value& value) const + { + return Key(fGetPrimaryKey(value), fGetSecondaryKey(value)); + } + + inline Key GetKey(Node* node) const + { + return GetValueKey(node->value); + } + + inline Value& GetValue(Node* node) const + { + return node->value; + } + + inline AVLTreeNode* GetAVLTreeNode(Node* node) const + { + return node; + } + + inline Node* GetNode(AVLTreeNode* node) const + { + return static_cast(node); + } + + inline int CompareKeyNode(const Key& a, const Node* b) const + { + return _CompareKeys(a, GetKey(const_cast(b))); + } + + inline int CompareNodes(const Node* a, const Node* b) const + { + return _CompareKeys(GetKey(const_cast(a)), + GetKey(const_cast(b))); + } + +private: + inline int _CompareKeys(const Key& a, const Key& b) const + { + int result = fPrimaryKeyCompare(a.primary, b.primary); + if (result == 0 && a.use_secondary && b.use_secondary) + result = fSecondaryKeyCompare(a.secondary, b.secondary); + return result; + } + + PrimaryKeyCompare fPrimaryKeyCompare; + SecondaryKeyCompare fSecondaryKeyCompare; + GetPrimaryKey fGetPrimaryKey; + GetSecondaryKey fGetSecondaryKey; +}; + + +// for convenience +#define TWO_KEY_AVL_TREE_TEMPLATE_LIST template +#define TWO_KEY_AVL_TREE_CLASS_NAME TwoKeyAVLTree + + +// #pragma mark - TwoKeyAVLTree + + +template, + typename GetSecondaryKey + = TwoKeyAVLTreeStandardGetKey > +class TwoKeyAVLTree { +public: + typedef TwoKeyAVLTreeKey Key; + typedef TwoKeyAVLTreeNodeStrategy NodeStrategy; + typedef AVLTreeMap TreeMap; + + typedef typename TreeMap::Iterator TreeMapIterator; + typedef typename NodeStrategy::Node Node; + + class Iterator; + +public: + TwoKeyAVLTree(); + TwoKeyAVLTree( + const PrimaryKeyCompare& primaryCompare, + const GetPrimaryKey& getPrimary, + const SecondaryKeyCompare& secondaryCompare, + const GetSecondaryKey& getSecondary); + ~TwoKeyAVLTree(); + + inline int CountItems() const { return fTreeMap.Count(); } + + Value* FindFirst(const PrimaryKey& key, + Iterator* iterator = NULL); + Value* FindLast(const PrimaryKey& key, + Iterator* iterator = NULL); + inline Value* Find(const PrimaryKey& primaryKey, + const SecondaryKey& secondaryKey, + Iterator* iterator = NULL); + + inline void GetIterator(Iterator* iterator); + + inline status_t Insert(const Value& value, + Iterator* iterator = NULL); + inline status_t Remove(const PrimaryKey& primaryKey, + const SecondaryKey& secondaryKey); + +private: + TreeMap fTreeMap; + PrimaryKeyCompare fPrimaryKeyCompare; + GetPrimaryKey fGetPrimaryKey; +}; + + +// #pragma mark - Iterator + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +class TWO_KEY_AVL_TREE_CLASS_NAME::Iterator { +public: + typedef typename TWO_KEY_AVL_TREE_CLASS_NAME::TreeMapIterator + TreeMapIterator; + + inline Iterator() + : + fIterator() + { + } + + inline ~Iterator() + { + } + + inline Value* Current() + { + return fIterator.CurrentValuePointer(); + } + + inline Value* Next() + { + fIterator.Next(); + return Current(); + } + + inline Value* Previous() + { + fIterator.Previous(); + return Current(); + } + + inline void Remove() + { + fIterator.Remove(); + } + +private: + friend class TWO_KEY_AVL_TREE_CLASS_NAME; + + Iterator(const Iterator& other) + : + fIterator(other.fIterator) + { + } + + Iterator& operator=(const Iterator& other) + { + fIterator = other.fIterator; + } + + Iterator(const TreeMapIterator& iterator) + : + fIterator() + { + } + + inline void _SetTo(const TreeMapIterator& iterator) + { + fIterator = iterator; + } + +private: + TWO_KEY_AVL_TREE_CLASS_NAME::TreeMapIterator fIterator; +}; + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +TWO_KEY_AVL_TREE_CLASS_NAME::TwoKeyAVLTree() + : + fTreeMap(NodeStrategy(PrimaryKeyCompare(), SecondaryKeyCompare(), + GetPrimaryKey(), GetSecondaryKey())), + fPrimaryKeyCompare(PrimaryKeyCompare()), + fGetPrimaryKey(GetPrimaryKey()) +{ +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +TWO_KEY_AVL_TREE_CLASS_NAME::TwoKeyAVLTree( + const PrimaryKeyCompare& primaryCompare, const GetPrimaryKey& getPrimary, + const SecondaryKeyCompare& secondaryCompare, + const GetSecondaryKey& getSecondary) + : + fTreeMap(NodeStrategy(primaryCompare, secondaryCompare, getPrimary, + getSecondary)), + fPrimaryKeyCompare(primaryCompare), + fGetPrimaryKey(getPrimary) +{ +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +TWO_KEY_AVL_TREE_CLASS_NAME::~TwoKeyAVLTree() +{ +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +Value* +TWO_KEY_AVL_TREE_CLASS_NAME::FindFirst(const PrimaryKey& key, + Iterator* iterator) +{ + const NodeStrategy& strategy = fTreeMap.GetNodeStrategy(); + Node* node = fTreeMap.RootNode(); + + while (node) { + int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey( + strategy.GetValue(node))); + if (cmp == 0) { + // found a matching node, now get the left-most node with that key + while (node->left && fPrimaryKeyCompare(key, + fGetPrimaryKey(strategy.GetValue( + strategy.GetNode(node->left)))) == 0) { + node = strategy.GetNode(node->left); + } + if (iterator) + iterator->_SetTo(fTreeMap.GetIterator(node)); + return &strategy.GetValue(node); + } + + if (cmp < 0) + node = strategy.GetNode(node->left); + else + node = strategy.GetNode(node->right); + } + return NULL; +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +Value* +TWO_KEY_AVL_TREE_CLASS_NAME::FindLast(const PrimaryKey& key, Iterator* iterator) +{ + const NodeStrategy& strategy = fTreeMap.GetNodeStrategy(); + Node* node = fTreeMap.RootNode(); + + while (node) { + int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey( + strategy.GetValue(node))); + if (cmp == 0) { + // found a matching node, now get the right-most node with that key + while (node->right && fPrimaryKeyCompare(key, + fGetPrimaryKey(strategy.GetValue( + strategy.GetNode(node->right)))) == 0) { + node = strategy.GetNode(node->right); + } + if (iterator) + iterator->_SetTo(fTreeMap.GetIterator(node)); + return &strategy.GetValue(node); + } + + if (cmp < 0) + node = strategy.GetNode(node->left); + else + node = strategy.GetNode(node->right); + } + return NULL; +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +Value* +TWO_KEY_AVL_TREE_CLASS_NAME::Find(const PrimaryKey& primaryKey, + const SecondaryKey& secondaryKey, Iterator* iterator) +{ + TreeMapIterator it = fTreeMap.Find(Key(primaryKey, secondaryKey)); + if (iterator) + iterator->_SetTo(it); + return it.CurrentValuePointer(); +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +void +TWO_KEY_AVL_TREE_CLASS_NAME::GetIterator(Iterator* iterator) +{ + TreeMapIterator it = fTreeMap.GetIterator(); + it.Next(); + // Our iterator needs to point to the first entry already. + iterator->_SetTo(it); +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +status_t +TWO_KEY_AVL_TREE_CLASS_NAME::Insert(const Value& value, Iterator* iterator) +{ + NodeStrategy& strategy + = const_cast(fTreeMap.GetNodeStrategy()); + + TreeMapIterator it; + status_t status = fTreeMap.Insert(strategy.GetValueKey(value), value, &it); + if (status != B_OK || !iterator) + return status; + + iterator->_SetTo(it); + return B_OK; +} + + +TWO_KEY_AVL_TREE_TEMPLATE_LIST +status_t +TWO_KEY_AVL_TREE_CLASS_NAME::Remove(const PrimaryKey& primaryKey, + const SecondaryKey& secondaryKey) +{ + return fTreeMap.Remove(Key(primaryKey, secondaryKey)); +} + + +#endif // _KERNEL_UTIL_TWO_KEY_AVL_TREE_H