|
|
@@ -3,16 +3,19 @@
|
|
|
// Code licensed under the BSD License.
|
|
|
// http://www.anki3d.org/LICENSE
|
|
|
|
|
|
-#ifndef ANKI_UTIL_HASH_MAP_H
|
|
|
-#define ANKI_UTIL_HASH_MAP_H
|
|
|
+#pragma once
|
|
|
|
|
|
#include "anki/util/Allocator.h"
|
|
|
#include "anki/util/NonCopyable.h"
|
|
|
+#include "anki/util/Ptr.h"
|
|
|
+
|
|
|
+namespace anki {
|
|
|
|
|
|
/// @addtogroup util_private
|
|
|
/// @{
|
|
|
|
|
|
-/// HashMap node.
|
|
|
+/// HashMap node. It's not a traditional bucket because it doesn't contain more
|
|
|
+/// than one node.
|
|
|
template<typename T>
|
|
|
class HashMapNode
|
|
|
{
|
|
|
@@ -21,46 +24,45 @@ public:
|
|
|
|
|
|
Value m_value;
|
|
|
U64 m_hash;
|
|
|
- HashMapNode* m_prev = nullptr;
|
|
|
- HashMapNode* m_next = nullptr;
|
|
|
+ HashMapNode* m_parent = nullptr;
|
|
|
+ HashMapNode* m_left = nullptr;
|
|
|
+ HashMapNode* m_right = nullptr;
|
|
|
|
|
|
template<typename... TArgs>
|
|
|
HashMapNode(TArgs&&... args)
|
|
|
- : m_value(std::forward<TArgs>(args)...)
|
|
|
+ : m_value(args...)
|
|
|
{}
|
|
|
};
|
|
|
|
|
|
-/// HashMap bidirectional iterator.
|
|
|
-template<typename TNodePointer, typename TValuePointer,
|
|
|
- typename TValueReference, typename THashMapPointer>
|
|
|
+/// HashMap forward-only iterator.
|
|
|
+template<typename TNodePointer, typename TValuePointer,
|
|
|
+ typename TValueReference>
|
|
|
class HashMapIterator
|
|
|
{
|
|
|
public:
|
|
|
- TNodePointer m_node = nullptr;
|
|
|
- THashMapPointer m_map = nullptr; ///< Used to go back from the end
|
|
|
+ TNodePointer m_node;
|
|
|
|
|
|
- HashMapIterator() = default;
|
|
|
+ /// Default constructor.
|
|
|
+ HashMapIterator()
|
|
|
+ : m_node(nullptr)
|
|
|
+ {}
|
|
|
|
|
|
+ /// Copy.
|
|
|
HashMapIterator(const HashMapIterator& b)
|
|
|
- : m_node(b.m_node),
|
|
|
- m_map(b.m_map)
|
|
|
+ : m_node(b.m_node)
|
|
|
{}
|
|
|
|
|
|
/// Allow conversion from iterator to const iterator.
|
|
|
- template<typename YNodePointer, typename YValuePointer,
|
|
|
- typename YValueReference, typename YHashMap>
|
|
|
- HashMapIterator(const HashMapIterator<YNodePointer,
|
|
|
- YValuePointer, YValueReference, YHashMap>& b)
|
|
|
- : m_node(b.m_node),
|
|
|
- m_map(b.m_map)
|
|
|
+ template<typename YNodePointer, typename YValuePointer,
|
|
|
+ typename YValueReference>
|
|
|
+ HashMapIterator(const HashMapIterator<YNodePointer, YValuePointer,
|
|
|
+ YValueReference>& b)
|
|
|
+ : m_node(b.m_node)
|
|
|
{}
|
|
|
|
|
|
- HashMapIterator(TNodePointer node, THashMapPointer list)
|
|
|
- : m_node(node),
|
|
|
- m_map(list)
|
|
|
- {
|
|
|
- ANKI_ASSERT(list);
|
|
|
- }
|
|
|
+ HashMapIterator(TNodePointer node)
|
|
|
+ : m_node(node)
|
|
|
+ {}
|
|
|
|
|
|
TValueReference operator*() const
|
|
|
{
|
|
|
@@ -77,7 +79,34 @@ public:
|
|
|
HashMapIterator& operator++()
|
|
|
{
|
|
|
ANKI_ASSERT(m_node);
|
|
|
- m_node = m_node->m_next;
|
|
|
+ TNodePointer node = m_node;
|
|
|
+
|
|
|
+ if(node->m_left)
|
|
|
+ {
|
|
|
+ node = node->m_left;
|
|
|
+ }
|
|
|
+ else if(node->m_right)
|
|
|
+ {
|
|
|
+ node = node->m_right;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Node without children
|
|
|
+ TNodePointer prevNode = node;
|
|
|
+ node = node->m_parent;
|
|
|
+ while(node)
|
|
|
+ {
|
|
|
+ if(node->m_right && node->m_right != prevNode)
|
|
|
+ {
|
|
|
+ node = node->m_right;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ prevNode = node;
|
|
|
+ node = node->m_parent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ m_node = node;
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
@@ -89,16 +118,6 @@ public:
|
|
|
return out;
|
|
|
}
|
|
|
|
|
|
- HashMapIterator& operator--();
|
|
|
-
|
|
|
- HashMapIterator operator--(int)
|
|
|
- {
|
|
|
- ANKI_ASSERT(m_node);
|
|
|
- HashMapIterator out = *this;
|
|
|
- --(*this);
|
|
|
- return out;
|
|
|
- }
|
|
|
-
|
|
|
HashMapIterator operator+(U n) const
|
|
|
{
|
|
|
HashMapIterator it = *this;
|
|
|
@@ -109,16 +128,6 @@ public:
|
|
|
return it;
|
|
|
}
|
|
|
|
|
|
- HashMapIterator operator-(U n) const
|
|
|
- {
|
|
|
- HashMapIterator it = *this;
|
|
|
- while(n-- != 0)
|
|
|
- {
|
|
|
- --it;
|
|
|
- }
|
|
|
- return it;
|
|
|
- }
|
|
|
-
|
|
|
HashMapIterator& operator+=(U n)
|
|
|
{
|
|
|
while(n-- != 0)
|
|
|
@@ -128,19 +137,8 @@ public:
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- HashMapIterator& operator-=(U n)
|
|
|
- {
|
|
|
- while(n-- != 0)
|
|
|
- {
|
|
|
- --(*this);
|
|
|
- }
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
Bool operator==(const HashMapIterator& b) const
|
|
|
{
|
|
|
- ANKI_ASSERT(m_list == b.m_list
|
|
|
- && "Comparing iterators from different lists");
|
|
|
return m_node == b.m_node;
|
|
|
}
|
|
|
|
|
|
@@ -155,22 +153,29 @@ public:
|
|
|
/// @{
|
|
|
|
|
|
/// Hash map template.
|
|
|
-template<typename T>
|
|
|
-class HashMap
|
|
|
+template<typename T, typename THasher, typename TCompare,
|
|
|
+ typename TNode = HashMapNode<T>>
|
|
|
+class HashMap: public NonCopyable
|
|
|
{
|
|
|
public:
|
|
|
using Value = T;
|
|
|
- using Node = HashMapNode<Value>;
|
|
|
+ using Node = TNode;
|
|
|
using Reference = Value&;
|
|
|
using ConstReference = const Value&;
|
|
|
using Pointer = Value*;
|
|
|
using ConstPointer = const Value*;
|
|
|
+ using Iterator = HashMapIterator<Node*, Pointer, Reference>;
|
|
|
+ using ConstIterator =
|
|
|
+ HashMapIterator<const Node*, ConstPointer, ConstReference>;
|
|
|
|
|
|
- HashMap() = default;
|
|
|
+ /// Default constructor.
|
|
|
+ HashMap()
|
|
|
+ : m_root(nullptr)
|
|
|
+ {}
|
|
|
|
|
|
/// Move.
|
|
|
HashMap(HashMap&& b)
|
|
|
- : HashMap()
|
|
|
+ : HashMap()
|
|
|
{
|
|
|
move(b);
|
|
|
}
|
|
|
@@ -189,12 +194,99 @@ public:
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
+ /// Destroy the list.
|
|
|
+ template<typename TAllocator>
|
|
|
+ void destroy(TAllocator alloc);
|
|
|
+
|
|
|
+ /// Get begin.
|
|
|
+ Iterator getBegin()
|
|
|
+ {
|
|
|
+ return Iterator(m_root);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get begin.
|
|
|
+ ConstIterator getBegin() const
|
|
|
+ {
|
|
|
+ return ConstIterator(m_root);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get end.
|
|
|
+ Iterator getEnd()
|
|
|
+ {
|
|
|
+ return Iterator();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get end.
|
|
|
+ ConstIterator getEnd() const
|
|
|
+ {
|
|
|
+ return ConstIterator();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get begin.
|
|
|
+ Iterator begin()
|
|
|
+ {
|
|
|
+ return getBegin();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get begin.
|
|
|
+ ConstIterator begin() const
|
|
|
+ {
|
|
|
+ return getBegin();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get end.
|
|
|
+ Iterator end()
|
|
|
+ {
|
|
|
+ return getEnd();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get end.
|
|
|
+ ConstIterator end() const
|
|
|
+ {
|
|
|
+ return getEnd();
|
|
|
+ }
|
|
|
+
|
|
|
/// Return true if map is empty.
|
|
|
Bool isEmpty() const
|
|
|
{
|
|
|
return m_root == nullptr;
|
|
|
}
|
|
|
|
|
|
+ /// Copy an element in the map.
|
|
|
+ template<typename TAllocator>
|
|
|
+ void pushBack(TAllocator alloc, ConstReference x)
|
|
|
+ {
|
|
|
+ Node* node = alloc.template newInstance<Node>(x);
|
|
|
+ node->m_hash = THasher()(node->m_value);
|
|
|
+ pushBackNode(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Copy an element in the map.
|
|
|
+ template<typename TAllocator>
|
|
|
+ void pushBack(Pointer x)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(x);
|
|
|
+ //static_assert(typeid(x) == );
|
|
|
+ pushBackNode(x);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Construct an element inside the map.
|
|
|
+ template<typename TAllocator, typename... TArgs>
|
|
|
+ void emplaceBack(TAllocator alloc, TArgs&&... args)
|
|
|
+ {
|
|
|
+ Node* node = alloc.template newInstance<Node>(
|
|
|
+ std::forward<TArgs>(args)...);
|
|
|
+ node->m_hash = THasher()(node->m_value);
|
|
|
+ pushBackNode(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Erase element.
|
|
|
+ template<typename TAllocator>
|
|
|
+ void erase(TAllocator alloc, Iterator it);
|
|
|
+
|
|
|
+ /// Find item.
|
|
|
+ Iterator find(const Value& a);
|
|
|
+
|
|
|
private:
|
|
|
Node* m_root = nullptr;
|
|
|
|
|
|
@@ -204,8 +296,16 @@ private:
|
|
|
m_root = b.m_root;
|
|
|
b.m_root = nullptr;
|
|
|
}
|
|
|
+
|
|
|
+ void pushBackNode(Node* node);
|
|
|
+
|
|
|
+ Node* findInternal(Node* node, const Value& a, U64 aHash);
|
|
|
+
|
|
|
+ template<typename TAllocator>
|
|
|
+ void destroyInternal(TAllocator alloc, Node* node);
|
|
|
};
|
|
|
/// @}
|
|
|
|
|
|
-#endif
|
|
|
+} // end namespace anki
|
|
|
|
|
|
+#include "anki/util/HashMap.inl.h"
|