LockFreeHashMap.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Core/NonCopyable.h>
  5. #include <atomic>
  6. namespace JPH {
  7. /// Very simple lock free hash map that only allows insertion, retrieval and provides a fixed amount of buckets and fixed storage.
  8. /// Note: This class currently assumes key and value are simple types that need no calls to the destructor.
  9. template <class Key, class Value>
  10. class LockFreeHashMap : public NonCopyable
  11. {
  12. public:
  13. using MapType = LockFreeHashMap<Key, Value>;
  14. /// Destructor
  15. ~LockFreeHashMap();
  16. /// Initialization
  17. /// @param inObjectStoreSizeBytes Number of bytes to reserve for all key value pairs
  18. /// @param inMaxBuckets Max amount of buckets to use in the hashmap. Must be power of 2.
  19. void Init(uint32 inObjectStoreSizeBytes, uint32 inMaxBuckets);
  20. /// Remove all elements.
  21. /// Note that this cannot happen simultaneously with adding new elements.
  22. void Clear();
  23. /// Get the current amount of buckets that the map is using
  24. uint32 GetNumBuckets() const { return mNumBuckets; }
  25. /// Get the maximum amount of buckets that this map supports
  26. uint32 GetMaxBuckets() const { return mMaxBuckets; }
  27. /// Update the number of buckets. This must be done after clearing the map and cannot be done concurrently with any other operations on the map.
  28. /// Note that the number of buckets can never become bigger than the specified max buckets during initialization and that it must be a power of 2.
  29. void SetNumBuckets(uint32 inNumBuckets);
  30. /// A key / value pair that is inserted in the map
  31. class KeyValue
  32. {
  33. public:
  34. const Key & GetKey() const { return mKey; }
  35. Value & GetValue() { return mValue; }
  36. const Value & GetValue() const { return mValue; }
  37. private:
  38. template <class K, class V> friend class LockFreeHashMap;
  39. Key mKey; ///< Key for this entry
  40. uint32 mNextOffset; ///< Offset in mObjectStore of next KeyValue entry with same hash
  41. Value mValue; ///< Value for this entry + optionally extra bytes
  42. };
  43. /// Insert a new element, returns null if map full.
  44. /// Multiple threads can be inserting in the map at the same time.
  45. template <class... Params>
  46. inline KeyValue * Create(const Key &inKey, size_t inKeyHash, int inExtraBytes, Params &&... inConstructorParams);
  47. /// Find an element, returns null if not found
  48. inline const KeyValue * Find(const Key &inKey, size_t inKeyHash) const;
  49. /// Value of an invalid handle
  50. const static uint32 cInvalidHandle = uint32(-1);
  51. /// Get convert key value pair to uint32 handle
  52. inline uint32 ToHandle(const KeyValue *inKeyValue) const;
  53. /// Convert uint32 handle back to key and value
  54. inline const KeyValue * FromHandle(uint32 inHandle) const;
  55. /// Get the number of key value pairs that this map currently contains
  56. inline uint32 GetNumKeyValues() const { return mNumKeyValues; }
  57. /// Get all key/value pairs
  58. inline void GetAllKeyValues(vector<const KeyValue *> &outAll) const;
  59. /// Non-const iterator
  60. struct Iterator
  61. {
  62. /// Comparison
  63. bool operator == (const Iterator &inRHS) const { return mMap == inRHS.mMap && mBucket == inRHS.mBucket && mOffset == inRHS.mOffset; }
  64. bool operator != (const Iterator &inRHS) const { return !(*this == inRHS); }
  65. /// Convert to key value pair
  66. KeyValue & operator * ();
  67. /// Next item
  68. Iterator & operator ++ ();
  69. MapType * mMap;
  70. uint32 mBucket;
  71. uint32 mOffset;
  72. };
  73. /// Iterate over the map, note that it is not safe to do this in parallel to Clear().
  74. /// It is safe to do this while adding elements to the map, but newly added elements may or may not be returned by the iterator.
  75. Iterator begin();
  76. Iterator end();
  77. #ifdef _DEBUG
  78. /// Output stats about this map to the log
  79. void TraceStats() const;
  80. #endif
  81. private:
  82. uint8 * mObjectStore = nullptr; ///< This contains a contigous list of objects (possibly of varying size)
  83. uint32 mObjectStoreSizeBytes = 0; ///< The size of mObjectStore in bytes
  84. atomic<uint32> mWriteOffset { 0 }; ///< Next offset to write to in mObjectStore
  85. atomic<uint32> mNumKeyValues = 0; ///< Number of key value pairs in the store
  86. atomic<uint32> * mBuckets = nullptr; ///< This contains the offset in mObjectStore of the first object with a particular hash
  87. uint32 mNumBuckets = 0; ///< Current number of buckets
  88. uint32 mMaxBuckets = 0; ///< Maximum number of buckets
  89. };
  90. } // JPH
  91. #include <Core/LockFreeHashMap.inl>