Comparer.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #pragma once
  7. typedef uint hash_t;
  8. #define TAGHASH(hash) ((static_cast<hash_t>(hash) << 1) | 1)
  9. #define UNTAGHASH(hash) (static_cast<hash_t>(hash) >> 1)
  10. // This comparer can create good hash codes and comparisons for all value,
  11. // pointer and string types using template specialization.
  12. template <typename T>
  13. struct DefaultComparer
  14. {
  15. inline static bool Equals(const T &x, const T &y)
  16. {
  17. return x == y;
  18. }
  19. inline static hash_t GetHashCode(const T &i)
  20. {
  21. return (hash_t)i;
  22. }
  23. };
  24. template <>
  25. struct DefaultComparer<double>
  26. {
  27. inline static bool Equals(double x, double y)
  28. {
  29. return x == y;
  30. }
  31. inline static hash_t GetHashCode(double d)
  32. {
  33. __int64 i64 = *(__int64*)&d;
  34. return (hash_t)((i64>>32) ^ (uint)i64);
  35. }
  36. };
  37. template <typename T>
  38. struct DefaultComparer<T *>
  39. {
  40. inline static bool Equals(T * x, T * y)
  41. {
  42. return x == y;
  43. }
  44. inline static hash_t GetHashCode(T * i)
  45. {
  46. // Shifting helps us eliminate any sameness due to our alignment strategy.
  47. // TODO: This works for Arena memory only. Recycler memory is 16 byte aligned.
  48. // Find a good universal hash for pointers.
  49. return (hash_t)(((size_t)i) >> ArenaAllocator::ObjectAlignmentBitShift);
  50. }
  51. };
  52. template <>
  53. struct DefaultComparer<size_t>
  54. {
  55. inline static bool Equals(size_t x, size_t y)
  56. {
  57. return x == y;
  58. }
  59. inline static hash_t GetHashCode(size_t i)
  60. {
  61. #ifdef TARGET_64
  62. // For 64 bits we want all 64 bits of the pointer to be represented in the hash code.
  63. uint32 hi = ((UINT_PTR) i >> 32);
  64. uint32 lo = (uint32)i;
  65. hash_t hash = hi ^ lo;
  66. #else
  67. hash_t hash = i;
  68. #endif
  69. return hash;
  70. }
  71. static int Compare(size_t i1, size_t i2)
  72. {
  73. if (i1 < i2)
  74. {
  75. return -1;
  76. }
  77. else if (i1 > i2)
  78. {
  79. return 1;
  80. }
  81. else
  82. {
  83. return 0;
  84. }
  85. }
  86. };
  87. // This specialization does a better job of creating hash codes
  88. // for recycler pointers.
  89. template <typename T>
  90. struct RecyclerPointerComparer
  91. {
  92. inline static bool Equals(T x, T y)
  93. {
  94. return x == y;
  95. }
  96. inline static hash_t GetHashCode(T i)
  97. {
  98. // Shifting helps us eliminate any sameness due to our alignment strategy.
  99. // TODO: This works for Recycler memory only. Arena memory is 8 byte aligned.
  100. // Find a good universal hash for pointers.
  101. return (hash_t)(((size_t)i) >> HeapConstants::ObjectAllocationShift);
  102. }
  103. };
  104. // TODO: FNV is a proven hash especially for short strings, which is common case here.
  105. // Still. it may be worth to consider a more recent block-based hash.
  106. // They tend to be faster, but it need to be examined against typical workloads.
  107. //
  108. // FNV-1a hash -> https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
  109. #define CC_HASH_OFFSET_VALUE 2166136261
  110. #define CC_HASH_LOGIC(hash, byte) \
  111. hash ^= byte; \
  112. hash *= 16777619
  113. template <>
  114. struct DefaultComparer<GUID>
  115. {
  116. inline static bool Equals(GUID const& x, GUID const& y)
  117. {
  118. return x == y;
  119. }
  120. inline static hash_t GetHashCode(GUID const& guid)
  121. {
  122. char* p = (char*)&guid;
  123. hash_t hash = CC_HASH_OFFSET_VALUE;
  124. for (int i = 0; i < sizeof(GUID); i++)
  125. {
  126. CC_HASH_LOGIC(hash, (uint32)(p[i]));
  127. }
  128. return hash;
  129. }
  130. };
  131. template<typename T>
  132. struct StringComparer
  133. {
  134. inline static bool Equals(T str1, T str2)
  135. {
  136. return ::wcscmp(str1, str2) == 0;
  137. }
  138. inline static hash_t GetHashCode(T str)
  139. {
  140. hash_t hash = CC_HASH_OFFSET_VALUE;
  141. while (*str)
  142. {
  143. CC_HASH_LOGIC(hash, *str);
  144. str++;
  145. }
  146. return hash;
  147. }
  148. inline static int Compare(T str1, T str2)
  149. {
  150. return ::wcscmp(str1, str2);
  151. }
  152. };
  153. template<>
  154. struct DefaultComparer<WCHAR*> : public StringComparer<WCHAR*> {};
  155. template<>
  156. struct DefaultComparer<const WCHAR*> : public StringComparer<const WCHAR*> {};
  157. template <typename T, typename TComparer>
  158. struct SpecializedComparer
  159. {
  160. template <typename U> class TComparerType : public TComparer {};
  161. };
  162. namespace regex
  163. {
  164. template <class T> struct Comparer
  165. {
  166. public:
  167. virtual bool Equals(T item1, T item2) = 0;
  168. virtual int GetHashCode(T item) = 0;
  169. virtual int Compare(T item1, T item2) = 0;
  170. };
  171. }