Comparer.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 & 0xFFFFFFFF);
  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. // FNV-1a hash -> https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
  104. // #define CC_HASH_OFFSET_VALUE 2166136261
  105. // #define CC_HASH_LOGIC(hash, byte) \
  106. // hash ^= byte; \
  107. // hash *= 16777619
  108. // previous hash function.
  109. // TODO: hash function below is bad for key distribution.
  110. // FNV-1a above results better but expensive for lookups in small data sets.
  111. #define CC_HASH_OFFSET_VALUE 0
  112. #define CC_HASH_LOGIC(hash, byte) \
  113. hash = _rotl(hash, 7); \
  114. hash ^= byte;
  115. template <>
  116. struct DefaultComparer<GUID>
  117. {
  118. inline static bool Equals(GUID const& x, GUID const& y)
  119. {
  120. return x == y;
  121. }
  122. inline static hash_t GetHashCode(GUID const& guid)
  123. {
  124. char* p = (char*)&guid;
  125. hash_t hash = CC_HASH_OFFSET_VALUE;
  126. for (int i = 0; i < sizeof(GUID); i++)
  127. {
  128. CC_HASH_LOGIC(hash, (uint32)(p[i]));
  129. }
  130. return hash;
  131. }
  132. };
  133. template<typename T>
  134. struct StringComparer
  135. {
  136. inline static bool Equals(T str1, T str2)
  137. {
  138. return ::wcscmp(str1, str2) == 0;
  139. }
  140. inline static hash_t GetHashCode(T str)
  141. {
  142. hash_t hash = CC_HASH_OFFSET_VALUE;
  143. while (*str)
  144. {
  145. CC_HASH_LOGIC(hash, *str);
  146. str++;
  147. }
  148. return hash;
  149. }
  150. inline static int Compare(T str1, T str2)
  151. {
  152. return ::wcscmp(str1, str2);
  153. }
  154. };
  155. template<>
  156. struct DefaultComparer<WCHAR*> : public StringComparer<WCHAR*> {};
  157. template<>
  158. struct DefaultComparer<const WCHAR*> : public StringComparer<const WCHAR*> {};
  159. template <typename T, typename TComparer>
  160. struct SpecializedComparer
  161. {
  162. template <typename T> class TComparerType : public TComparer {};
  163. };
  164. namespace regex
  165. {
  166. template <class T> struct Comparer
  167. {
  168. public:
  169. virtual bool Equals(T item1, T item2) = 0;
  170. virtual int GetHashCode(T item) = 0;
  171. virtual int Compare(T item1, T item2) = 0;
  172. };
  173. }