Comparer.h 4.8 KB

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