|
|
@@ -8,7 +8,7 @@
|
|
|
#include <anki/util/Allocator.h>
|
|
|
#include <anki/util/Functions.h>
|
|
|
#include <anki/util/NonCopyable.h>
|
|
|
-#include <anki/util/Forward.h>
|
|
|
+#include <anki/util/SparseArray.h>
|
|
|
|
|
|
namespace anki
|
|
|
{
|
|
|
@@ -16,206 +16,86 @@ namespace anki
|
|
|
/// @addtogroup util_containers
|
|
|
/// @{
|
|
|
|
|
|
-namespace detail
|
|
|
-{
|
|
|
-
|
|
|
-/// HashMap node. It's not a traditional bucket because it doesn't contain more than one values.
|
|
|
-/// @internal
|
|
|
-template<typename TValue>
|
|
|
-class HashMapNode
|
|
|
+/// Default hasher.
|
|
|
+template<typename TKey>
|
|
|
+class DefaultHasher
|
|
|
{
|
|
|
public:
|
|
|
- U64 m_hash = 0;
|
|
|
- HashMapNode* m_left = nullptr;
|
|
|
- HashMapNode* m_right = nullptr;
|
|
|
- TValue m_value;
|
|
|
- HashMapNode* m_parent = nullptr; ///< Used for iterating.
|
|
|
-
|
|
|
- template<typename... TArgs>
|
|
|
- HashMapNode(TArgs&&... args)
|
|
|
- : m_value(std::forward<TArgs>(args)...)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- TValue& getHashMapNodeValue()
|
|
|
- {
|
|
|
- return m_value;
|
|
|
- }
|
|
|
-
|
|
|
- const TValue& getHashMapNodeValue() const
|
|
|
+ U64 operator()(const TKey& a) const
|
|
|
{
|
|
|
- return m_value;
|
|
|
+ return a.computeHash();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-/// HashMap forward-only iterator.
|
|
|
-/// @internal
|
|
|
-template<typename TNodePointer, typename TValuePointer, typename TValueReference>
|
|
|
-class HashMapIterator
|
|
|
+/// Specialization for U64 keys.
|
|
|
+template<>
|
|
|
+class DefaultHasher<U64>
|
|
|
{
|
|
|
- template<typename, typename, typename>
|
|
|
- friend class anki::HashMap;
|
|
|
-
|
|
|
public:
|
|
|
- /// Default constructor.
|
|
|
- HashMapIterator()
|
|
|
- : m_node(nullptr)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- /// Copy.
|
|
|
- HashMapIterator(const HashMapIterator& b)
|
|
|
- : m_node(b.m_node)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- /// Allow conversion from iterator to const iterator.
|
|
|
- template<typename YNodePointer, typename YValuePointer, typename YValueReference>
|
|
|
- HashMapIterator(const HashMapIterator<YNodePointer, YValuePointer, YValueReference>& b)
|
|
|
- : m_node(b.m_node)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- HashMapIterator(TNodePointer node)
|
|
|
- : m_node(node)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- TValueReference operator*() const
|
|
|
+ U64 operator()(const U64 a) const
|
|
|
{
|
|
|
- ANKI_ASSERT(m_node);
|
|
|
- return m_node->getHashMapNodeValue();
|
|
|
+ return a;
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- TValuePointer operator->() const
|
|
|
- {
|
|
|
- ANKI_ASSERT(m_node);
|
|
|
- return &m_node->getHashMapNodeValue();
|
|
|
- }
|
|
|
+/// Hash map template.
|
|
|
+template<typename TKey, typename TValue, typename THasher = DefaultHasher<TKey>>
|
|
|
+class HashMap
|
|
|
+{
|
|
|
+public:
|
|
|
+ using SparseArrayType = SparseArray<TValue, U64>;
|
|
|
+ using Value = TValue;
|
|
|
+ using Key = TKey;
|
|
|
+ using Hasher = THasher;
|
|
|
+ using Iterator = typename SparseArrayType::Iterator;
|
|
|
+ using ConstIterator = typename SparseArrayType::ConstIterator;
|
|
|
|
|
|
- HashMapIterator& operator++()
|
|
|
+ /// Default constructor.
|
|
|
+ HashMap()
|
|
|
{
|
|
|
- ANKI_ASSERT(m_node);
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
- HashMapIterator operator++(int)
|
|
|
+ /// Move.
|
|
|
+ HashMap(HashMap&& b)
|
|
|
{
|
|
|
- ANKI_ASSERT(m_node);
|
|
|
- HashMapIterator out = *this;
|
|
|
- ++(*this);
|
|
|
- return out;
|
|
|
+ *this = std::move(b);
|
|
|
}
|
|
|
|
|
|
- HashMapIterator operator+(U n) const
|
|
|
+ /// You need to manually destroy the map.
|
|
|
+ /// @see HashMap::destroy
|
|
|
+ ~HashMap()
|
|
|
{
|
|
|
- HashMapIterator it = *this;
|
|
|
- while(n-- != 0)
|
|
|
- {
|
|
|
- ++it;
|
|
|
- }
|
|
|
- return it;
|
|
|
}
|
|
|
|
|
|
- HashMapIterator& operator+=(U n)
|
|
|
+ /// Move.
|
|
|
+ HashMap& operator=(HashMap&& b)
|
|
|
{
|
|
|
- while(n-- != 0)
|
|
|
- {
|
|
|
- ++(*this);
|
|
|
- }
|
|
|
+ m_sparseArr = std::move(b.m_sparseArr);
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- Bool operator==(const HashMapIterator& b) const
|
|
|
- {
|
|
|
- return m_node == b.m_node;
|
|
|
- }
|
|
|
-
|
|
|
- Bool operator!=(const HashMapIterator& b) const
|
|
|
- {
|
|
|
- return !(*this == b);
|
|
|
- }
|
|
|
-
|
|
|
-private:
|
|
|
- TNodePointer m_node;
|
|
|
-};
|
|
|
-
|
|
|
-/// Hash map base.
|
|
|
-/// @tparam TKey The key of the map.
|
|
|
-/// @tparam TValue The value of the map.
|
|
|
-/// @tparam THasher Functor to hash type of TKey.
|
|
|
-/// @internal
|
|
|
-template<typename TKey, typename TValue, typename THasher, typename TNode>
|
|
|
-class HashMapBase : public NonCopyable
|
|
|
-{
|
|
|
-public:
|
|
|
- using Key = TKey;
|
|
|
- using Value = TValue;
|
|
|
- using Reference = Value&;
|
|
|
- using ConstReference = const Value&;
|
|
|
- using Pointer = Value*;
|
|
|
- using ConstPointer = const Value*;
|
|
|
- using Iterator = HashMapIterator<TNode*, Pointer, Reference>;
|
|
|
- using ConstIterator = HashMapIterator<const TNode*, ConstPointer, ConstReference>;
|
|
|
-
|
|
|
- /// Default constructor.
|
|
|
- HashMapBase()
|
|
|
- : m_root(nullptr)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- ~HashMapBase() = default;
|
|
|
-
|
|
|
/// Get begin.
|
|
|
Iterator getBegin()
|
|
|
{
|
|
|
- return Iterator(m_root);
|
|
|
+ return m_sparseArr.getBegin();
|
|
|
}
|
|
|
|
|
|
/// Get begin.
|
|
|
ConstIterator getBegin() const
|
|
|
{
|
|
|
- return ConstIterator(m_root);
|
|
|
+ return m_sparseArr.getBegin();
|
|
|
}
|
|
|
|
|
|
/// Get end.
|
|
|
Iterator getEnd()
|
|
|
{
|
|
|
- return Iterator();
|
|
|
+ return m_sparseArr.getEnd();
|
|
|
}
|
|
|
|
|
|
/// Get end.
|
|
|
ConstIterator getEnd() const
|
|
|
{
|
|
|
- return ConstIterator();
|
|
|
+ return m_sparseArr.getEnd();
|
|
|
}
|
|
|
|
|
|
/// Get begin.
|
|
|
@@ -245,133 +125,48 @@ public:
|
|
|
/// Return true if map is empty.
|
|
|
Bool isEmpty() const
|
|
|
{
|
|
|
- return m_root == nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- /// Find item.
|
|
|
- Iterator find(const Key& key);
|
|
|
-
|
|
|
- /// Find item.
|
|
|
- ConstIterator find(const Key& key) const;
|
|
|
-
|
|
|
-protected:
|
|
|
- /// @privatesection
|
|
|
- TNode* m_root = nullptr;
|
|
|
-
|
|
|
- void move(HashMapBase& b)
|
|
|
- {
|
|
|
- m_root = b.m_root;
|
|
|
- b.m_root = nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add a node in the tree.
|
|
|
- void insertNode(TNode* node);
|
|
|
-
|
|
|
- /// Remove a node from the tree.
|
|
|
- void removeNode(TNode* node);
|
|
|
-};
|
|
|
-
|
|
|
-} // end namespace detail
|
|
|
-
|
|
|
-/// Default hasher.
|
|
|
-template<typename TKey>
|
|
|
-class DefaultHasher
|
|
|
-{
|
|
|
-public:
|
|
|
- U64 operator()(const TKey& a) const
|
|
|
- {
|
|
|
- return a.computeHash();
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-/// Specialization for U64 keys.
|
|
|
-template<>
|
|
|
-class DefaultHasher<U64>
|
|
|
-{
|
|
|
-public:
|
|
|
- U64 operator()(const U64 a) const
|
|
|
- {
|
|
|
- return a;
|
|
|
+ return m_sparseArr.isEmpty();
|
|
|
}
|
|
|
-};
|
|
|
|
|
|
-/// Hash map template.
|
|
|
-template<typename TKey, typename TValue, typename THasher = DefaultHasher<TKey>>
|
|
|
-class HashMap : public detail::HashMapBase<TKey, TValue, THasher, detail::HashMapNode<TValue>>
|
|
|
-{
|
|
|
-private:
|
|
|
- using Base = detail::HashMapBase<TKey, TValue, THasher, detail::HashMapNode<TValue>>;
|
|
|
- using Node = detail::HashMapNode<TValue>;
|
|
|
-
|
|
|
-public:
|
|
|
- using typename Base::Iterator;
|
|
|
-
|
|
|
- /// Default constructor.
|
|
|
- HashMap()
|
|
|
- : Base()
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- /// Move.
|
|
|
- HashMap(HashMap&& b)
|
|
|
- : Base()
|
|
|
- {
|
|
|
- Base::move(b);
|
|
|
- }
|
|
|
-
|
|
|
- /// You need to manually destroy the map.
|
|
|
- /// @see HashMap::destroy
|
|
|
- ~HashMap()
|
|
|
+ /// Destroy the list.
|
|
|
+ template<typename TAllocator>
|
|
|
+ void destroy(TAllocator alloc)
|
|
|
{
|
|
|
- ANKI_ASSERT(Base::m_root == nullptr && "Requires manual destruction");
|
|
|
+ m_sparseArr.destroy(alloc);
|
|
|
}
|
|
|
|
|
|
- /// Move.
|
|
|
- HashMap& operator=(HashMap&& b)
|
|
|
+ /// Construct an element inside the map.
|
|
|
+ template<typename TAllocator, typename... TArgs>
|
|
|
+ Iterator emplace(TAllocator alloc, const TKey& key, TArgs&&... args)
|
|
|
{
|
|
|
- Base::move(b);
|
|
|
- return *this;
|
|
|
+ const U64 hash = THasher()(key);
|
|
|
+ return m_sparseArr.emplace(alloc, hash, std::forward<TArgs>(args)...);
|
|
|
}
|
|
|
|
|
|
- /// Destroy the list.
|
|
|
- template<typename TAllocator>
|
|
|
- void destroy(TAllocator alloc);
|
|
|
-
|
|
|
- /// Copy an element in the map.
|
|
|
+ /// Erase element.
|
|
|
template<typename TAllocator>
|
|
|
- Iterator pushBack(TAllocator alloc, const TKey& key, const TValue& x)
|
|
|
+ void erase(TAllocator alloc, Iterator it)
|
|
|
{
|
|
|
- Node* node = alloc.template newInstance<Node>(x);
|
|
|
- node->m_hash = THasher()(key);
|
|
|
- Base::insertNode(node);
|
|
|
- return Iterator(node);
|
|
|
+ m_sparseArr.erase(alloc, it);
|
|
|
}
|
|
|
|
|
|
- /// Construct an element inside the map.
|
|
|
- template<typename TAllocator, typename... TArgs>
|
|
|
- Iterator emplaceBack(TAllocator alloc, const TKey& key, TArgs&&... args)
|
|
|
+ /// Find a value using a key.
|
|
|
+ Iterator find(const Key& key)
|
|
|
{
|
|
|
- Node* node = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
|
|
|
- node->m_hash = THasher()(key);
|
|
|
- Base::insertNode(node);
|
|
|
- return Iterator(node);
|
|
|
+ const U64 hash = THasher()(key);
|
|
|
+ return m_sparseArr.find(hash);
|
|
|
}
|
|
|
|
|
|
- /// Erase element.
|
|
|
- template<typename TAllocator>
|
|
|
- void erase(TAllocator alloc, typename Base::Iterator it)
|
|
|
+ /// Find a value using a key.
|
|
|
+ ConstIterator find(const Key& key) const
|
|
|
{
|
|
|
- Node* del = it.m_node;
|
|
|
- Base::removeNode(del);
|
|
|
- alloc.deleteInstance(del);
|
|
|
+ const U64 hash = THasher()(key);
|
|
|
+ return m_sparseArr.find(hash);
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- template<typename TAllocator>
|
|
|
- void destroyInternal(TAllocator alloc, Node* node);
|
|
|
+ SparseArrayType m_sparseArr;
|
|
|
};
|
|
|
/// @}
|
|
|
|
|
|
} // end namespace anki
|
|
|
-
|
|
|
-#include <anki/util/HashMap.inl.h>
|