MurmurHash.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*******************************************************************************
  2. 程序说明
  3. 计算Hash值的函数,参考7.8.0版本的计算哈希值函数,调用方式与7.8.0一致
  4. *******************************************************************************/
  5. #ifndef MURMURHASH_H
  6. #define MURMURHASH_H
  7. #include <TopoDS_Edge.hxx>
  8. #include <TopoDS_Face.hxx>
  9. #include <TopoDS_Shape.hxx>
  10. #include <TopLoc_Datum3D.hxx>
  11. #include <TopLoc_SListOfItemLocation.hxx>
  12. #include <TopLoc_Location.hxx>
  13. #include <TopLoc_ItemLocation.hxx>
  14. #include <string>
  15. namespace opencascade
  16. {
  17. namespace MurmurHash
  18. {
  19. inline uint64_t shift_mix(uint64_t theV)
  20. {
  21. return theV ^ (theV >> 47);
  22. }
  23. // Loads n bytes, where 1 <= n < 8.
  24. inline uint64_t load_bytes(const char* thePnt, int theNb)
  25. {
  26. uint64_t aRes = 0;
  27. --theNb;
  28. do
  29. aRes = (aRes << 8) + static_cast<unsigned char>(thePnt[theNb]);
  30. while (--theNb >= 0);
  31. return aRes;
  32. }
  33. template <typename T>
  34. inline T unaligned_load(const char* thePnt)
  35. {
  36. T aRes;
  37. memcpy(&aRes, thePnt, sizeof(aRes));
  38. return aRes;
  39. }
  40. //=======================================================================
  41. //function : MurmurHash64A
  42. //purpose :
  43. //=======================================================================
  44. inline uint64_t MurmurHash64A(const void* theKey, int theLen, uint64_t theSeed)
  45. {
  46. static constexpr uint64_t aMul = (((uint64_t)0xc6a4a793UL) << 32UL)
  47. + (uint64_t)0x5bd1e995UL;
  48. const char* const aBuf = static_cast<const char*>(theKey);
  49. // Remove the bytes not divisible by the sizeof(uint64_t). This
  50. // allows the main loop to process the data as 64-bit integers.
  51. const uint64_t aLenAligned = theLen & ~(uint64_t)0x7;
  52. const char* const anEnd = aBuf + aLenAligned;
  53. uint64_t aHash = theSeed ^ (theLen * aMul);
  54. for (const char* aPnt = aBuf; aPnt != anEnd; aPnt += 8)
  55. {
  56. const uint64_t aData = shift_mix(unaligned_load<uint64_t>(aPnt) * aMul) * aMul;
  57. aHash ^= aData;
  58. aHash *= aMul;
  59. }
  60. if ((theLen & 0x7) != 0)
  61. {
  62. const uint64_t data = load_bytes(anEnd, theLen & 0x7);
  63. aHash ^= data;
  64. aHash *= aMul;
  65. }
  66. aHash = shift_mix(aHash) * aMul;
  67. aHash = shift_mix(aHash);
  68. return aHash;
  69. }
  70. //=======================================================================
  71. //function : MurmurHash2A
  72. //purpose :
  73. //=======================================================================
  74. inline uint32_t MurmurHash2A(const void* theKey, int theLen, uint32_t theSeed)
  75. {
  76. const uint32_t aMul = 0x5bd1e995;
  77. uint32_t aHash = theSeed ^ theLen;
  78. const char* aBuf = static_cast<const char*>(theKey);
  79. // Mix 4 bytes at a time into the hash.
  80. while (theLen >= 4)
  81. {
  82. uint32_t aKey = unaligned_load<uint32_t>(aBuf);
  83. aKey *= aMul;
  84. aKey ^= aKey >> 24;
  85. aKey *= aMul;
  86. aHash *= aMul;
  87. aHash ^= aKey;
  88. aBuf += 4;
  89. theLen -= 4;
  90. }
  91. uint32_t aKey;
  92. // Handle the last few bytes of the input array.
  93. switch (theLen)
  94. {
  95. case 3:
  96. aKey = static_cast<unsigned char>(aBuf[2]);
  97. aHash ^= aKey << 16;
  98. Standard_FALLTHROUGH
  99. case 2:
  100. aKey = static_cast<unsigned char>(aBuf[1]);
  101. aHash ^= aKey << 8;
  102. Standard_FALLTHROUGH
  103. case 1:
  104. aKey = static_cast<unsigned char>(aBuf[0]);
  105. aHash ^= aKey;
  106. aHash *= aMul;
  107. };
  108. // Do a few final mixes of the hash.
  109. aHash ^= aHash >> 13;
  110. aHash *= aMul;
  111. aHash ^= aHash >> 15;
  112. return aHash;
  113. }
  114. template <typename T1, typename T = size_t>
  115. typename std::enable_if<sizeof(T) == 8, uint64_t>::type
  116. hash_combine(const T1& theValue, const int theLen = sizeof(T1), const T theSeed = 0xA329F1D3A586ULL)
  117. {
  118. return MurmurHash::MurmurHash64A(&theValue, theLen, theSeed);
  119. }
  120. template <typename T1, typename T = size_t>
  121. typename std::enable_if<sizeof(T) != 8, T>::type
  122. hash_combine(const T1& theValue, const int theLen = sizeof(T1), const T theSeed = 0xc70f6907U)
  123. {
  124. return static_cast<T>(MurmurHash::MurmurHash2A(&theValue, theLen, theSeed));
  125. }
  126. template <typename T = size_t>
  127. constexpr T optimalSeed()
  128. {
  129. return sizeof(T) == 8 ? static_cast<T>(0xA329F1D3A586ULL) : static_cast<T>(0xc70f6907U);
  130. }
  131. };
  132. template <typename T1, typename T = size_t>
  133. T hash(const T1 theValue) noexcept
  134. {
  135. return opencascade::MurmurHash::hash_combine<T1, T>(theValue);
  136. }
  137. template <typename T1, typename T = size_t>
  138. T hashBytes(const T1* theKey, int theLen)
  139. {
  140. return opencascade::MurmurHash::hash_combine<T1, T>(*theKey, theLen);
  141. }
  142. template <typename T1, typename T = size_t>
  143. T hash_combine(const T1 theValue, const int theLen, const T theSeed)
  144. {
  145. return opencascade::MurmurHash::hash_combine<T1, T>(theValue, theLen, theSeed);
  146. }
  147. };
  148. namespace std
  149. {
  150. inline size_t GetLocationHashCode(const TopLoc_Location& loc)
  151. {
  152. gp_Trsf T = loc.Transformation();
  153. TopLoc_SListOfItemLocation myItems;
  154. Handle(TopLoc_Datum3D) D = new TopLoc_Datum3D(T);
  155. myItems.Construct(TopLoc_ItemLocation(D, 1));
  156. // Hashing base on IsEqual function
  157. if (myItems.IsEmpty())
  158. {
  159. return 0;
  160. }
  161. size_t aHash = opencascade::MurmurHash::optimalSeed<size_t>();
  162. TopLoc_SListOfItemLocation items = myItems;
  163. size_t aCombined[3];
  164. while (items.More())
  165. {
  166. //aCombined[0] = std::hash<Handle(TopLoc_Datum3D)>{}(items.Value().myDatum);
  167. aCombined[0] = static_cast<size_t>(reinterpret_cast<std::uintptr_t>(D.get()));
  168. aCombined[1] = opencascade::hash(1);
  169. aCombined[2] = aHash;
  170. aHash = opencascade::hashBytes(aCombined, sizeof(aCombined));
  171. items.Next();
  172. }
  173. return aHash;
  174. }
  175. template <class TheTransientType>
  176. struct hash<Handle(TheTransientType)>
  177. {
  178. size_t operator()(const Handle(TheTransientType)& theHandle) const noexcept
  179. {
  180. return static_cast<size_t>(reinterpret_cast<std::uintptr_t>(theHandle.get()));
  181. }
  182. };
  183. template <>
  184. struct hash<TopLoc_Location>
  185. {
  186. size_t operator()(const TopLoc_Location& theLocation) const
  187. {
  188. return std::GetLocationHashCode(theLocation);
  189. }
  190. };
  191. template <>
  192. struct hash<TopoDS_Shape>
  193. {
  194. size_t operator()(const TopoDS_Shape& theShape) const noexcept
  195. {
  196. const size_t aHL = std::hash<TopLoc_Location>{}(theShape.Location());
  197. return aHL == 0 ? opencascade::hash(theShape.TShape().get())
  198. : opencascade::MurmurHash::hash_combine(theShape.TShape().get(), sizeof(void*), aHL);
  199. }
  200. };
  201. template <>
  202. struct hash<TopoDS_Face>
  203. {
  204. size_t operator()(const TopoDS_Face& theShape) const
  205. {
  206. return std::hash<TopoDS_Shape>{}(theShape);
  207. }
  208. };
  209. template <>
  210. struct hash<TopoDS_Edge>
  211. {
  212. size_t operator()(const TopoDS_Edge& theShape) const
  213. {
  214. return std::hash<TopoDS_Shape>{}(theShape);
  215. }
  216. };
  217. };
  218. #endif // MURMURHASH_H