HashCombine.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. JPH_NAMESPACE_BEGIN
  6. /// Implements the FNV-1a hash algorithm
  7. /// @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
  8. /// @param inData Data block of bytes
  9. /// @param inSize Number of bytes
  10. /// @param inSeed Seed of the hash (can be used to pass in the hash of a previous operation, otherwise leave default)
  11. /// @return Hash
  12. inline uint64 HashBytes(const void *inData, uint inSize, uint64 inSeed = 0xcbf29ce484222325UL)
  13. {
  14. uint64 hash = inSeed;
  15. for (const uint8 *data = reinterpret_cast<const uint8 *>(inData); data < reinterpret_cast<const uint8 *>(inData) + inSize; ++data)
  16. {
  17. hash ^= uint64(*data);
  18. hash *= 0x100000001b3UL;
  19. }
  20. return hash;
  21. }
  22. /// Calculate the FNV-1a hash of inString.
  23. /// @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
  24. constexpr uint64 HashString(const char *inString, uint64 inSeed = 0xcbf29ce484222325UL)
  25. {
  26. uint64 hash = inSeed;
  27. for (const char *c = inString; *c != 0; ++c)
  28. {
  29. hash ^= uint64(*c);
  30. hash *= 0x100000001b3UL;
  31. }
  32. return hash;
  33. }
  34. /// A 64 bit hash function by Thomas Wang, Jan 1997
  35. /// See: http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
  36. /// @param inValue Value to hash
  37. /// @return Hash
  38. inline uint64 Hash64(uint64 inValue)
  39. {
  40. uint64 hash = inValue;
  41. hash = (~hash) + (hash << 21); // hash = (hash << 21) - hash - 1;
  42. hash = hash ^ (hash >> 24);
  43. hash = (hash + (hash << 3)) + (hash << 8); // hash * 265
  44. hash = hash ^ (hash >> 14);
  45. hash = (hash + (hash << 2)) + (hash << 4); // hash * 21
  46. hash = hash ^ (hash >> 28);
  47. hash = hash + (hash << 31);
  48. return hash;
  49. }
  50. /// Fallback hash function that calls T::GetHash()
  51. template <class T>
  52. struct Hash
  53. {
  54. uint64 operator () (const T &inValue) const
  55. {
  56. return inValue.GetHash();
  57. }
  58. };
  59. /// A hash function for floats
  60. template <>
  61. struct Hash<float>
  62. {
  63. uint64 operator () (float inValue) const
  64. {
  65. float value = inValue == 0.0f? 0.0f : inValue; // Convert -0.0f to 0.0f
  66. return HashBytes(&value, sizeof(value));
  67. }
  68. };
  69. /// A hash function for doubles
  70. template <>
  71. struct Hash<double>
  72. {
  73. uint64 operator () (double inValue) const
  74. {
  75. double value = inValue == 0.0? 0.0 : inValue; // Convert -0.0 to 0.0
  76. return HashBytes(&value, sizeof(value));
  77. }
  78. };
  79. /// A hash function for character pointers
  80. template <>
  81. struct Hash<const char *>
  82. {
  83. uint64 operator () (const char *inValue) const
  84. {
  85. return HashString(inValue);
  86. }
  87. };
  88. /// A hash function for std::string_view
  89. template <>
  90. struct Hash<std::string_view>
  91. {
  92. uint64 operator () (const std::string_view &inValue) const
  93. {
  94. return HashBytes(inValue.data(), uint(inValue.size()));
  95. }
  96. };
  97. /// A hash function for String
  98. template <>
  99. struct Hash<String>
  100. {
  101. uint64 operator () (const String &inValue) const
  102. {
  103. return HashBytes(inValue.data(), uint(inValue.size()));
  104. }
  105. };
  106. /// A fallback function for generic pointers
  107. template <class T>
  108. struct Hash<T *>
  109. {
  110. uint64 operator () (T *inValue) const
  111. {
  112. return HashBytes(&inValue, sizeof(inValue));
  113. }
  114. };
  115. /// Helper macro to define a hash function for trivial types
  116. #define JPH_DEFINE_TRIVIAL_HASH(type) \
  117. template <> \
  118. struct Hash<type> \
  119. { \
  120. uint64 operator () (const type &inValue) const \
  121. { \
  122. return HashBytes(&inValue, sizeof(inValue)); \
  123. } \
  124. };
  125. /// Commonly used types
  126. JPH_DEFINE_TRIVIAL_HASH(char)
  127. JPH_DEFINE_TRIVIAL_HASH(int)
  128. JPH_DEFINE_TRIVIAL_HASH(uint32)
  129. JPH_DEFINE_TRIVIAL_HASH(uint64)
  130. /// Helper function that hashes a single value into ioSeed
  131. /// Based on https://github.com/jonmaiga/mx3 by Jon Maiga
  132. template <typename T>
  133. inline void HashCombine(uint64 &ioSeed, const T &inValue)
  134. {
  135. constexpr uint64 c = 0xbea225f9eb34556dUL;
  136. uint64 h = ioSeed;
  137. uint64 x = Hash<T> { } (inValue);
  138. // See: https://github.com/jonmaiga/mx3/blob/master/mx3.h
  139. // mix_stream(h, x)
  140. x *= c;
  141. x ^= x >> 39;
  142. h += x * c;
  143. h *= c;
  144. // mix(h)
  145. h ^= h >> 32;
  146. h *= c;
  147. h ^= h >> 29;
  148. h *= c;
  149. h ^= h >> 32;
  150. h *= c;
  151. h ^= h >> 29;
  152. ioSeed = h;
  153. }
  154. /// Hash combiner to use a custom struct in an unordered map or set
  155. ///
  156. /// Usage:
  157. ///
  158. /// struct SomeHashKey
  159. /// {
  160. /// std::string key1;
  161. /// std::string key2;
  162. /// bool key3;
  163. /// };
  164. ///
  165. /// JPH_MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)
  166. template <typename FirstValue, typename... Values>
  167. inline uint64 HashCombineArgs(const FirstValue &inFirstValue, Values... inValues)
  168. {
  169. // Prime the seed by hashing the first value
  170. uint64 seed = Hash<FirstValue> { } (inFirstValue);
  171. // Hash all remaining values together using a fold expression
  172. (HashCombine(seed, inValues), ...);
  173. return seed;
  174. }
  175. #define JPH_MAKE_HASH_STRUCT(type, name, ...) \
  176. struct [[nodiscard]] name \
  177. { \
  178. ::JPH::uint64 operator()(const type &t) const \
  179. { \
  180. return ::JPH::HashCombineArgs(__VA_ARGS__); \
  181. } \
  182. };
  183. #define JPH_MAKE_STD_HASH(type) \
  184. JPH_SUPPRESS_WARNING_PUSH \
  185. JPH_SUPPRESS_WARNINGS \
  186. namespace std \
  187. { \
  188. template<> \
  189. struct [[nodiscard]] hash<type> \
  190. { \
  191. size_t operator()(const type &t) const \
  192. { \
  193. return size_t(::JPH::Hash<type>{ }(t)); \
  194. } \
  195. }; \
  196. } \
  197. JPH_SUPPRESS_WARNING_POP
  198. #define JPH_MAKE_HASHABLE(type, ...) \
  199. JPH_SUPPRESS_WARNING_PUSH \
  200. JPH_SUPPRESS_WARNINGS \
  201. namespace JPH \
  202. { \
  203. template<> \
  204. JPH_MAKE_HASH_STRUCT(type, Hash<type>, __VA_ARGS__) \
  205. } \
  206. JPH_SUPPRESS_WARNING_POP \
  207. JPH_MAKE_STD_HASH(type)
  208. JPH_NAMESPACE_END