hash_bytes.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Definition of _Hash_bytes. -*- C++ -*-
  2. // Copyright (C) 2010-2022 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. // This file defines Hash_bytes, a primitive used for defining hash
  21. // functions. Based on public domain MurmurHashUnaligned2, by Austin
  22. // Appleby. http://murmurhash.googlepages.com/
  23. // This file also defines _Fnv_hash_bytes, another primitive with
  24. // exactly the same interface but using a different hash algorithm,
  25. // Fowler / Noll / Vo (FNV) Hash (type FNV-1a). The Murmur hash
  26. // function apears to be better in both speed and hash quality, and
  27. // FNV is provided primarily for backward compatibility.
  28. #include <bits/hash_bytes.h>
  29. namespace
  30. {
  31. inline std::size_t
  32. unaligned_load(const char* p)
  33. {
  34. std::size_t result;
  35. __builtin_memcpy(&result, p, sizeof(result));
  36. return result;
  37. }
  38. #if __SIZEOF_SIZE_T__ == 8
  39. // Loads n bytes, where 1 <= n < 8.
  40. inline std::size_t
  41. load_bytes(const char* p, int n)
  42. {
  43. std::size_t result = 0;
  44. --n;
  45. do
  46. result = (result << 8) + static_cast<unsigned char>(p[n]);
  47. while (--n >= 0);
  48. return result;
  49. }
  50. inline std::size_t
  51. shift_mix(std::size_t v)
  52. { return v ^ (v >> 47);}
  53. #endif
  54. }
  55. namespace std
  56. {
  57. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  58. #if __SIZEOF_SIZE_T__ == 4
  59. // Implementation of Murmur hash for 32-bit size_t.
  60. size_t
  61. _Hash_bytes(const void* ptr, size_t len, size_t seed)
  62. {
  63. const size_t m = 0x5bd1e995;
  64. size_t hash = seed ^ len;
  65. const char* buf = static_cast<const char*>(ptr);
  66. // Mix 4 bytes at a time into the hash.
  67. while(len >= 4)
  68. {
  69. size_t k = unaligned_load(buf);
  70. k *= m;
  71. k ^= k >> 24;
  72. k *= m;
  73. hash *= m;
  74. hash ^= k;
  75. buf += 4;
  76. len -= 4;
  77. }
  78. // Handle the last few bytes of the input array.
  79. switch(len)
  80. {
  81. case 3:
  82. hash ^= static_cast<unsigned char>(buf[2]) << 16;
  83. [[gnu::fallthrough]];
  84. case 2:
  85. hash ^= static_cast<unsigned char>(buf[1]) << 8;
  86. [[gnu::fallthrough]];
  87. case 1:
  88. hash ^= static_cast<unsigned char>(buf[0]);
  89. hash *= m;
  90. };
  91. // Do a few final mixes of the hash.
  92. hash ^= hash >> 13;
  93. hash *= m;
  94. hash ^= hash >> 15;
  95. return hash;
  96. }
  97. // Implementation of FNV hash for 32-bit size_t.
  98. // N.B. This function should work on unsigned char, otherwise it does not
  99. // correctly implement the FNV-1a algorithm (see PR59406).
  100. // The existing behaviour is retained for backwards compatibility.
  101. size_t
  102. _Fnv_hash_bytes(const void* ptr, size_t len, size_t hash)
  103. {
  104. const char* cptr = static_cast<const char*>(ptr);
  105. for (; len; --len)
  106. {
  107. hash ^= static_cast<size_t>(*cptr++);
  108. hash *= static_cast<size_t>(16777619UL);
  109. }
  110. return hash;
  111. }
  112. #elif __SIZEOF_SIZE_T__ == 8
  113. // Implementation of Murmur hash for 64-bit size_t.
  114. size_t
  115. _Hash_bytes(const void* ptr, size_t len, size_t seed)
  116. {
  117. static const size_t mul = (((size_t) 0xc6a4a793UL) << 32UL)
  118. + (size_t) 0x5bd1e995UL;
  119. const char* const buf = static_cast<const char*>(ptr);
  120. // Remove the bytes not divisible by the sizeof(size_t). This
  121. // allows the main loop to process the data as 64-bit integers.
  122. const size_t len_aligned = len & ~(size_t)0x7;
  123. const char* const end = buf + len_aligned;
  124. size_t hash = seed ^ (len * mul);
  125. for (const char* p = buf; p != end; p += 8)
  126. {
  127. const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
  128. hash ^= data;
  129. hash *= mul;
  130. }
  131. if ((len & 0x7) != 0)
  132. {
  133. const size_t data = load_bytes(end, len & 0x7);
  134. hash ^= data;
  135. hash *= mul;
  136. }
  137. hash = shift_mix(hash) * mul;
  138. hash = shift_mix(hash);
  139. return hash;
  140. }
  141. // Implementation of FNV hash for 64-bit size_t.
  142. // N.B. This function should work on unsigned char, otherwise it does not
  143. // correctly implement the FNV-1a algorithm (see PR59406).
  144. // The existing behaviour is retained for backwards compatibility.
  145. size_t
  146. _Fnv_hash_bytes(const void* ptr, size_t len, size_t hash)
  147. {
  148. const char* cptr = static_cast<const char*>(ptr);
  149. for (; len; --len)
  150. {
  151. hash ^= static_cast<size_t>(*cptr++);
  152. hash *= static_cast<size_t>(1099511628211ULL);
  153. }
  154. return hash;
  155. }
  156. #else
  157. // Dummy hash implementation for unusual sizeof(size_t).
  158. size_t
  159. _Hash_bytes(const void* ptr, size_t len, size_t seed)
  160. {
  161. size_t hash = seed;
  162. const char* cptr = reinterpret_cast<const char*>(ptr);
  163. for (; len; --len)
  164. hash = (hash * 131) + *cptr++;
  165. return hash;
  166. }
  167. size_t
  168. _Fnv_hash_bytes(const void* ptr, size_t len, size_t seed)
  169. { return _Hash_bytes(ptr, len, seed); }
  170. #endif /* __SIZEOF_SIZE_T__ */
  171. _GLIBCXX_END_NAMESPACE_VERSION
  172. } // namespace