proxygen
HashTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/hash/Hash.h>
18 
19 #include <stdint.h>
20 
21 #include <random>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <utility>
25 
26 #include <folly/MapUtil.h>
27 #include <folly/Range.h>
29 
30 using namespace folly::hash;
31 
32 TEST(Hash, Fnv32) {
33  const char* s1 = "hello, world!";
34  const uint32_t s1_res = 3605494790UL;
35  EXPECT_EQ(fnv32(s1), s1_res);
36  EXPECT_EQ(fnv32(s1), fnv32_buf(s1, strlen(s1)));
37 
38  const char* s2 = "monkeys! m0nk3yz! ev3ry \\/\\/here~~~~";
39  const uint32_t s2_res = 1270448334UL;
40  EXPECT_EQ(fnv32(s2), s2_res);
41  EXPECT_EQ(fnv32(s2), fnv32_buf(s2, strlen(s2)));
42 
43  const char* s3 = "";
44  const uint32_t s3_res = 2166136261UL;
45  EXPECT_EQ(fnv32(s3), s3_res);
46  EXPECT_EQ(fnv32(s3), fnv32_buf(s3, strlen(s3)));
47 
48  const uint8_t s4_data[] = {0xFF, 0xFF, 0xFF, 0x00};
49  const char* s4 = reinterpret_cast<const char*>(s4_data);
50  const uint32_t s4_res = 2420936562UL;
51  EXPECT_EQ(fnv32(s4), s4_res);
52  EXPECT_EQ(fnv32(s4), fnv32_buf(s4, strlen(s4)));
53 }
54 
55 TEST(Hash, Fnv64) {
56  const char* s1 = "hello, world!";
57  const uint64_t s1_res = 13991426986746681734ULL;
58  EXPECT_EQ(fnv64(s1), s1_res);
59  EXPECT_EQ(fnv64(s1), fnv64_buf(s1, strlen(s1)));
60 
61  const char* s2 = "monkeys! m0nk3yz! ev3ry \\/\\/here~~~~";
62  const uint64_t s2_res = 6091394665637302478ULL;
63  EXPECT_EQ(fnv64(s2), s2_res);
64  EXPECT_EQ(fnv64(s2), fnv64_buf(s2, strlen(s2)));
65 
66  const char* s3 = "";
67  const uint64_t s3_res = 14695981039346656037ULL;
68  EXPECT_EQ(fnv64(s3), s3_res);
69  EXPECT_EQ(fnv64(s3), fnv64_buf(s3, strlen(s3)));
70 
71  const uint8_t s4_data[] = {0xFF, 0xFF, 0xFF, 0x00};
72  const char* s4 = reinterpret_cast<const char*>(s4_data);
73  const uint64_t s4_res = 2787597222566293202ULL;
74  EXPECT_EQ(fnv64(s4), s4_res);
75  EXPECT_EQ(fnv64(s4), fnv64_buf(s4, strlen(s4)));
76 
77  // note: Use fnv64_buf to make a single hash value from multiple
78  // fields/datatypes.
79  const char* t4_a = "E Pluribus";
80  int64_t t4_b = 0xF1E2D3C4B5A69788;
81  int32_t t4_c = 0xAB12CD34;
82  const char* t4_d = "Unum";
83  uint64_t t4_res = 15571330457339273965ULL;
84  uint64_t t4_hash1 = fnv64_buf(t4_a, strlen(t4_a));
85  uint64_t t4_hash2 =
86  fnv64_buf(reinterpret_cast<void*>(&t4_b), sizeof(int64_t), t4_hash1);
87  uint64_t t4_hash3 =
88  fnv64_buf(reinterpret_cast<void*>(&t4_c), sizeof(int32_t), t4_hash2);
89  uint64_t t4_hash4 = fnv64_buf(t4_d, strlen(t4_d), t4_hash3);
90  EXPECT_EQ(t4_hash4, t4_res);
91  // note: These are probabalistic, not determinate, but c'mon.
92  // These hash values should be different, or something's not
93  // working.
94  EXPECT_NE(t4_hash1, t4_hash4);
95  EXPECT_NE(t4_hash2, t4_hash4);
96  EXPECT_NE(t4_hash3, t4_hash4);
97 }
98 
99 TEST(Hash, Hsieh32) {
100  const char* s1 = "hello, world!";
101  const uint32_t s1_res = 2918802987ul;
102  EXPECT_EQ(hsieh_hash32(s1), s1_res);
103  EXPECT_EQ(hsieh_hash32(s1), hsieh_hash32_buf(s1, strlen(s1)));
104 
105  const char* s2 = "monkeys! m0nk3yz! ev3ry \\/\\/here~~~~";
106  const uint32_t s2_res = 47373213ul;
107  EXPECT_EQ(hsieh_hash32(s2), s2_res);
108  EXPECT_EQ(hsieh_hash32(s2), hsieh_hash32_buf(s2, strlen(s2)));
109 
110  const char* s3 = "";
111  const uint32_t s3_res = 0;
112  EXPECT_EQ(hsieh_hash32(s3), s3_res);
113  EXPECT_EQ(hsieh_hash32(s3), hsieh_hash32_buf(s3, strlen(s3)));
114 }
115 
116 TEST(Hash, TWang_Mix64) {
117  uint64_t i1 = 0x78a87873e2d31dafULL;
118  uint64_t i1_res = 3389151152926383528ULL;
119  EXPECT_EQ(i1_res, twang_mix64(i1));
120  EXPECT_EQ(i1, twang_unmix64(i1_res));
121 
122  uint64_t i2 = 0x0123456789abcdefULL;
123  uint64_t i2_res = 3061460455458984563ull;
124  EXPECT_EQ(i2_res, twang_mix64(i2));
125  EXPECT_EQ(i2, twang_unmix64(i2_res));
126 }
127 
128 namespace {
129 void checkTWang(uint64_t r) {
130  uint64_t result = twang_mix64(r);
131  EXPECT_EQ(r, twang_unmix64(result));
132 }
133 } // namespace
134 
135 TEST(Hash, TWang_Unmix64) {
136  // We'll try (1 << i), (1 << i) + 1, (1 << i) - 1
137  for (int i = 1; i < 64; i++) {
138  checkTWang((uint64_t(1) << i) - 1);
139  checkTWang(uint64_t(1) << i);
140  checkTWang((uint64_t(1) << i) + 1);
141  }
142 }
143 
144 TEST(Hash, TWang_32From64) {
145  uint64_t i1 = 0x78a87873e2d31dafULL;
146  uint32_t i1_res = 1525586863ul;
147  EXPECT_EQ(twang_32from64(i1), i1_res);
148 
149  uint64_t i2 = 0x0123456789abcdefULL;
150  uint32_t i2_res = 2918899159ul;
151  EXPECT_EQ(twang_32from64(i2), i2_res);
152 }
153 
154 TEST(Hash, Jenkins_Rev_Mix32) {
155  uint32_t i1 = 3805486511ul;
156  uint32_t i1_res = 381808021ul;
157  EXPECT_EQ(i1_res, jenkins_rev_mix32(i1));
158  EXPECT_EQ(i1, jenkins_rev_unmix32(i1_res));
159 
160  uint32_t i2 = 2309737967ul;
161  uint32_t i2_res = 1834777923ul;
162  EXPECT_EQ(i2_res, jenkins_rev_mix32(i2));
163  EXPECT_EQ(i2, jenkins_rev_unmix32(i2_res));
164 }
165 
166 namespace {
167 void checkJenkins(uint32_t r) {
168  uint32_t result = jenkins_rev_mix32(r);
169  EXPECT_EQ(r, jenkins_rev_unmix32(result));
170 }
171 } // namespace
172 
173 TEST(Hash, Jenkins_Rev_Unmix32) {
174  // We'll try (1 << i), (1 << i) + 1, (1 << i) - 1
175  for (int i = 1; i < 32; i++) {
176  checkJenkins((1U << i) - 1);
177  checkJenkins(1U << i);
178  checkJenkins((1U << i) + 1);
179  }
180 }
181 
182 TEST(Hash, hasher) {
183  // Basically just confirms that things compile ok.
184  std::unordered_map<int32_t, int32_t, folly::hasher<int32_t>> m;
185  m.insert(std::make_pair(4, 5));
186  EXPECT_EQ(get_default(m, 4), 5);
187 }
188 
189 TEST(Hash, integral_types) {
190  // Basically just confirms that things compile ok.
191  std::unordered_set<size_t> hashes;
192  folly::Hash hasher;
193  hashes.insert(hasher((char)1));
194  hashes.insert(hasher((signed char)2));
195  hashes.insert(hasher((unsigned char)3));
196  hashes.insert(hasher((short)4));
197  hashes.insert(hasher((signed short)5));
198  hashes.insert(hasher((unsigned short)6));
199  hashes.insert(hasher((int)7));
200  hashes.insert(hasher((signed int)8));
201  hashes.insert(hasher((unsigned int)9));
202  hashes.insert(hasher((long)10));
203  hashes.insert(hasher((signed long)11));
204  hashes.insert(hasher((unsigned long)12));
205  hashes.insert(hasher((long long)13));
206  hashes.insert(hasher((signed long long)14));
207  hashes.insert(hasher((unsigned long long)15));
208  hashes.insert(hasher((int8_t)16));
209  hashes.insert(hasher((uint8_t)17));
210  hashes.insert(hasher((int16_t)18));
211  hashes.insert(hasher((uint16_t)19));
212  hashes.insert(hasher((int32_t)20));
213  hashes.insert(hasher((uint32_t)21));
214  hashes.insert(hasher((int64_t)22));
215  hashes.insert(hasher((uint64_t)23));
216  hashes.insert(hasher((size_t)24));
217 
218  size_t setSize = 24;
219 #if FOLLY_HAVE_INT128_T
220  hashes.insert(hasher((__int128_t)25));
221  hashes.insert(hasher((__uint128_t)26));
222  setSize += 2;
223 #endif
224  EXPECT_EQ(setSize, hashes.size());
225 }
226 
227 namespace {
228 enum class TestEnum {
229  MIN = 0,
230  ITEM = 1,
231  MAX = 2,
232 };
233 
234 enum class TestBigEnum : uint64_t {
235  ITEM = 1,
236 };
237 
238 struct TestStruct {};
239 } // namespace
240 
241 namespace std {
242 template <>
243 struct hash<TestEnum> {
244  std::size_t operator()(TestEnum const& e) const noexcept {
245  return hash<int>()(static_cast<int>(e));
246  }
247 };
248 
249 template <>
250 struct hash<TestStruct> {
251  std::size_t operator()(TestStruct const&) const noexcept {
252  return 0;
253  }
254 };
255 } // namespace std
256 
257 namespace {
258 thread_local size_t allocatedMemorySize{0};
259 
260 template <class T>
261 class TestAlloc {
262  public:
263  using Alloc = std::allocator<T>;
264  using value_type = typename Alloc::value_type;
265 
266  using pointer = typename Alloc::pointer;
267  using const_pointer = typename Alloc::const_pointer;
268  using reference = typename Alloc::reference;
269  using const_reference = typename Alloc::const_reference;
270  using size_type = typename Alloc::size_type;
271 
272  using propagate_on_container_swap = std::true_type;
273  using propagate_on_container_copy_assignment = std::true_type;
274  using propagate_on_container_move_assignment = std::true_type;
275 
276  TestAlloc() {}
277 
278  template <class T2>
279  TestAlloc(TestAlloc<T2> const& other) noexcept : a_(other.a_) {}
280 
281  template <class T2>
282  TestAlloc& operator=(TestAlloc<T2> const& other) noexcept {
283  a_ = other.a_;
284  return *this;
285  }
286 
287  template <class T2>
288  TestAlloc(TestAlloc<T2>&& other) noexcept : a_(std::move(other.a_)) {}
289 
290  template <class T2>
291  TestAlloc& operator=(TestAlloc<T2>&& other) noexcept {
292  a_ = std::move(other.a_);
293  return *this;
294  }
295 
296  static size_t getAllocatedMemorySize() {
297  return allocatedMemorySize;
298  }
299 
300  static void resetTracking() {
301  allocatedMemorySize = 0;
302  }
303 
304  T* allocate(size_t n) {
305  allocatedMemorySize += n * sizeof(T);
306  return a_.allocate(n);
307  }
308  void deallocate(T* p, size_t n) {
309  allocatedMemorySize -= n * sizeof(T);
310  a_.deallocate(p, n);
311  }
312 
313  private:
314  std::allocator<T> a_;
315 
316  template <class U>
317  friend class TestAlloc;
318 };
319 
320 template <class T1, class T2>
321 bool operator==(TestAlloc<T1> const&, TestAlloc<T2> const&) {
322  return true;
323 }
324 
325 template <class T1, class T2>
326 bool operator!=(TestAlloc<T1> const&, TestAlloc<T2> const&) {
327  return false;
328 }
329 
330 template <class M, class A>
331 std::vector<size_t> getStats(size_t iter) {
332  std::vector<size_t> ret;
333  ret.reserve(iter);
335  M m;
336  ret.push_back(A::getAllocatedMemorySize());
337  for (size_t i = 1; i < iter; ++i) {
338  m.insert(std::make_pair(
339  folly::to<typename M::key_type>(i), typename M::mapped_type{}));
340  ret.push_back(A::getAllocatedMemorySize());
341  }
342  return ret;
343 }
344 
345 template <typename K, typename V, typename H>
346 void testNoCachedHashCode() {
347  using A = TestAlloc<std::pair<const K, V>>;
348  using M = std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, A>;
349  using MActual = std::unordered_map<K, V, H, std::equal_to<K>, A>;
350  constexpr int kIter = 10;
351  auto expected = getStats<M, A>(kIter);
352  auto actual = getStats<MActual, A>(kIter);
353  ASSERT_EQ(expected.size(), actual.size());
354  for (size_t i = 0; i < expected.size(); ++i) {
355  ASSERT_EQ(expected[i], actual[i]);
356  }
357 }
358 } // namespace
359 
360 TEST(Hash, noCachedHashCode) {
361  testNoCachedHashCode<bool, char, folly::hasher<bool>>();
362  testNoCachedHashCode<int, char, folly::hasher<int>>();
363  testNoCachedHashCode<double, char, folly::hasher<double>>();
364  testNoCachedHashCode<TestEnum, char, folly::hasher<TestEnum>>();
365 
366  testNoCachedHashCode<bool, std::string, folly::Hash>();
367  testNoCachedHashCode<int, std::string, folly::Hash>();
368  testNoCachedHashCode<double, std::string, folly::Hash>();
369  testNoCachedHashCode<TestEnum, std::string, folly::Hash>();
370 }
371 
372 TEST(Hash, integer_conversion) {
374  uint64_t k = 10;
375  EXPECT_EQ(h(k), h(10));
376 }
377 
378 #if FOLLY_HAVE_INT128_T
379 TEST(Hash, int128_std_hash) {
380  std::unordered_set<__int128> hs;
381  hs.insert(__int128_t{1});
382  hs.insert(__int128_t{2});
383  EXPECT_EQ(2, hs.size());
384 
385  std::set<unsigned __int128> s;
386  s.insert(static_cast<unsigned __int128>(1));
387  s.insert(static_cast<unsigned __int128>(2));
388  EXPECT_EQ(2, s.size());
389 }
390 #endif
391 
392 TEST(Hash, float_types) {
393  folly::Hash hasher;
394 
395  EXPECT_EQ(hasher(0.0f), hasher(-0.0f));
396  EXPECT_EQ(hasher(0.0), hasher(-0.0));
397 
398  // Basically just confirms that things compile ok.
399  std::unordered_set<size_t> hashes;
400  hashes.insert(hasher(0.0f));
401  hashes.insert(hasher(0.1f));
402  hashes.insert(hasher(0.2));
403  hashes.insert(hasher(0.2f));
404  hashes.insert(hasher(-0.3));
405  hashes.insert(hasher(-0.3f));
406 
407  EXPECT_EQ(6, hashes.size());
408 }
409 
410 // Not a full hasher since only handles one type
411 class TestHasher {
412  public:
413  size_t operator()(const std::pair<int, int>& p) const {
414  return p.first + p.second;
415  }
416 };
417 
418 template <typename T, typename... Ts>
419 size_t hash_combine_test(const T& t, const Ts&... ts) {
420  return hash_combine_generic(TestHasher{}, t, ts...);
421 }
422 
423 TEST(Hash, pair) {
424  auto a = std::make_pair(1, 2);
425  auto b = std::make_pair(3, 4);
426  auto c = std::make_pair(1, 2);
427  auto d = std::make_pair(2, 1);
431 
432  // With composition
434  // Test order dependence
436 
437  // Test with custom hasher
439  // 3 + 4 != 1 + 2
441  // This time, thanks to a terrible hash function, these are equal
443  // With composition
445  // Test order dependence
447  // Again, 1 + 2 == 2 + 1
449 }
450 
453  EXPECT_NE(hash_combine(1, 2), hash_combine(2, 1));
454 }
455 
456 TEST(Hash, hash_bool) {
457  const auto hash = folly::Hash();
458  EXPECT_NE(hash(true), hash(false));
459 }
460 
461 TEST(Hash, hash_bool10) {
462  const auto hash = folly::Hash();
463  std::set<size_t> values;
464  for (bool b1 : {false, true}) {
465  for (bool b2 : {false, true}) {
466  for (bool b3 : {false, true}) {
467  for (bool b4 : {false, true}) {
468  for (bool b5 : {false, true}) {
469  for (bool b6 : {false, true}) {
470  for (bool b7 : {false, true}) {
471  for (bool b8 : {false, true}) {
472  for (bool b9 : {false, true}) {
473  for (bool b10 : {false, true}) {
474  values.insert(
475  hash(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10));
476  }
477  }
478  }
479  }
480  }
481  }
482  }
483  }
484  }
485  }
486  EXPECT_EQ(values.size(), 1 << 10);
487 }
488 
489 TEST(Hash, std_tuple) {
490  typedef std::tuple<int64_t, std::string, int32_t> tuple3;
491  tuple3 t(42, "foo", 1);
492 
493  std::unordered_map<tuple3, std::string> m;
494  m[t] = "bar";
495  EXPECT_EQ("bar", m[t]);
496 }
497 
498 TEST(Hash, enum_type) {
499  const auto hash = folly::Hash();
500 
501  enum class Enum32 : int32_t { Foo, Bar };
502  EXPECT_EQ(hash(static_cast<int32_t>(Enum32::Foo)), hash(Enum32::Foo));
503  EXPECT_EQ(hash(static_cast<int32_t>(Enum32::Bar)), hash(Enum32::Bar));
504  EXPECT_NE(hash(Enum32::Foo), hash(Enum32::Bar));
505 
506  std::unordered_map<Enum32, std::string, folly::Hash> m32;
507  m32[Enum32::Foo] = "foo";
508  EXPECT_EQ("foo", m32[Enum32::Foo]);
509 
510  enum class Enum64 : int64_t { Foo, Bar };
511  EXPECT_EQ(hash(static_cast<int64_t>(Enum64::Foo)), hash(Enum64::Foo));
512  EXPECT_EQ(hash(static_cast<int64_t>(Enum64::Bar)), hash(Enum64::Bar));
513  EXPECT_NE(hash(Enum64::Foo), hash(Enum64::Bar));
514 
515  std::unordered_map<Enum64, std::string, folly::Hash> m64;
516  m64[Enum64::Foo] = "foo";
517  EXPECT_EQ("foo", m64[Enum64::Foo]);
518 }
519 
520 TEST(Hash, pair_folly_hash) {
521  typedef std::pair<int64_t, int32_t> pair2;
522  pair2 p(42, 1);
523 
524  std::unordered_map<pair2, std::string, folly::Hash> m;
525  m[p] = "bar";
526  EXPECT_EQ("bar", m[p]);
527 }
528 
529 TEST(Hash, tuple_folly_hash) {
530  typedef std::tuple<int64_t, int32_t, int32_t> tuple3;
531  tuple3 t(42, 1, 1);
532 
533  std::unordered_map<tuple3, std::string, folly::Hash> m;
534  m[t] = "bar";
535  EXPECT_EQ("bar", m[t]);
536 }
537 
538 namespace {
539 template <class T>
540 size_t hash_vector(const std::vector<T>& v) {
541  return hash_range(v.begin(), v.end());
542 }
543 } // namespace
544 
545 TEST(Hash, hash_range) {
546  EXPECT_EQ(hash_vector<int32_t>({1, 2}), hash_vector<int16_t>({1, 2}));
547  EXPECT_NE(hash_vector<int>({2, 1}), hash_vector<int>({1, 2}));
548  EXPECT_EQ(hash_vector<int>({}), hash_vector<float>({}));
549 }
550 
552  EXPECT_EQ(
554  folly::Hash{}(12345ul), folly::Hash{}, 6789ul),
556  folly::Hash{}(6789ul), folly::Hash{}, 12345ul));
557 
558  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
559  std::random_device rd;
560  std::mt19937 g(rd());
561  auto h = commutative_hash_combine_range(v.begin(), v.end());
562  for (int i = 0; i < 100; i++) {
563  std::shuffle(v.begin(), v.end(), g);
564  EXPECT_EQ(h, commutative_hash_combine_range(v.begin(), v.end()));
565  }
566  EXPECT_NE(
567  h,
569  /* seed = */ 0xdeadbeef, folly::Hash{}, v.begin(), v.end()));
570  EXPECT_NE(
571  h, commutative_hash_combine_range(v.begin(), v.begin() + (v.size() - 1)));
572 
573  EXPECT_EQ(h, commutative_hash_combine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
574  EXPECT_EQ(h, commutative_hash_combine(10, 2, 3, 4, 5, 6, 7, 8, 9, 1));
575 
576  EXPECT_EQ(
577  commutative_hash_combine(12345, 6789),
578  commutative_hash_combine(6789, 12345));
579 }
580 
581 TEST(Hash, std_tuple_different_hash) {
582  typedef std::tuple<int64_t, std::string, int32_t> tuple3;
583  tuple3 t1(42, "foo", 1);
584  tuple3 t2(9, "bar", 3);
585  tuple3 t3(42, "foo", 3);
586 
587  EXPECT_NE(std::hash<tuple3>()(t1), std::hash<tuple3>()(t2));
588  EXPECT_NE(std::hash<tuple3>()(t1), std::hash<tuple3>()(t3));
589 }
590 
591 TEST(Hash, Strings) {
592  using namespace folly;
593 
594  StringPiece a1 = "10050517", b1 = "51107032", a2 = "10050518",
595  b2 = "51107033", a3 = "10050519", b3 = "51107034",
596  a4 = "10050525", b4 = "51107040";
597  Range<const wchar_t*> w1 = range(L"10050517"), w2 = range(L"51107032"),
598  w3 = range(L"10050518"), w4 = range(L"51107033");
599  Hash h2;
600  EXPECT_NE(h2(a1), h2(b1));
601  EXPECT_NE(h2(a1), h2(b1));
602  EXPECT_NE(h2(a2), h2(b2));
603  EXPECT_NE(h2(a3), h2(b3));
604  EXPECT_NE(h2(ByteRange(a1)), h2(ByteRange(b1)));
605  EXPECT_NE(h2(ByteRange(a2)), h2(ByteRange(b2)));
606  EXPECT_NE(h2(ByteRange(a3)), h2(ByteRange(b3)));
607  EXPECT_NE(h2(ByteRange(a4)), h2(ByteRange(b4)));
608  EXPECT_NE(h2(w1), h2(w2));
609  EXPECT_NE(h2(w1), h2(w3));
610  EXPECT_NE(h2(w2), h2(w4));
611 
612  // Check compatibility with std::string.
613  EXPECT_EQ(h2(a1), h2(a1.str()));
614  EXPECT_EQ(h2(a2), h2(a2.str()));
615  EXPECT_EQ(h2(a3), h2(a3.str()));
616  EXPECT_EQ(h2(a4), h2(a4.str()));
617 }
618 
619 struct FNVTestParam {
622 };
623 
624 class FNVTest : public ::testing::TestWithParam<FNVTestParam> {};
625 
626 TEST_P(FNVTest, Fnva64Buf) {
627  EXPECT_EQ(
628  GetParam().out, fnva64_buf(GetParam().in.data(), GetParam().in.size()));
629 }
630 
631 TEST_P(FNVTest, Fnva64) {
632  EXPECT_EQ(GetParam().out, fnva64(GetParam().in));
633 }
634 
635 TEST_P(FNVTest, Fnva64Partial) {
636  size_t partialLen = GetParam().in.size() / 2;
637  auto data = GetParam().in.data();
638  auto partial = fnva64_buf(data, partialLen);
639  EXPECT_EQ(
640  GetParam().out,
641  fnva64_buf(
642  data + partialLen, GetParam().in.size() - partialLen, partial));
643 }
644 
645 // Taken from http://www.isthe.com/chongo/src/fnv/test_fnv.c
647  FNVTesting,
648  FNVTest,
649  ::testing::Values(
650  FNVTestParam{"foobar", // 11
651  0x85944171f73967e8},
652  FNVTestParam{"chongo was here!\n", // 39
653  0x46810940eff5f915},
654  FNVTestParam{"127.0.0.3", // 106,
655  0xaabafc7104d91158},
656  FNVTestParam{"http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash", // 126
657  0xd9b957fb7fe794c5},
658  FNVTestParam{"http://norvig.com/21-days.html", // 136
659  0x07aaa640476e0b9a}));
660 
662 
663 static constexpr bool k32Bit = sizeof(std::size_t) == 4;
664 
665 static_assert(!folly::IsAvalanchingHasher<std::hash<int>, int>::value, "");
666 static_assert(
667  !folly::IsAvalanchingHasher<std::hash<char const*>, char const*>::value,
668  "");
669 static_assert(!folly::IsAvalanchingHasher<std::hash<float>, float>::value, "");
670 static_assert(
671  !folly::IsAvalanchingHasher<std::hash<double>, double>::value,
672  "");
673 static_assert(
674  !folly::IsAvalanchingHasher<std::hash<long double>, long double>::value,
675  "");
676 static_assert(
677  folly::IsAvalanchingHasher<std::hash<std::string>, std::string>::value,
678  "");
679 static_assert(
681  "");
682 static_assert(
684  "");
685 
686 static_assert(
687  !folly::IsAvalanchingHasher<folly::transparent<std::hash<int>>, int>::value,
688  "");
689 static_assert(
691  folly::transparent<std::hash<std::string>>,
692  std::string>::value,
693  "");
694 
695 // these come from folly/hash/Hash.h
696 static_assert(
698  std::hash<std::pair<int, int>>,
699  std::pair<int, int>>::value,
700  "");
701 static_assert(
702  !folly::IsAvalanchingHasher<std::hash<std::tuple<int>>, std::tuple<int>>::
703  value,
704  "");
705 static_assert(
707  std::hash<std::tuple<std::string>>,
708  std::tuple<std::string>>::value,
709  "");
710 static_assert(
712  std::hash<std::tuple<int, int>>,
713  std::tuple<int, int>>::value,
714  "");
715 static_assert(
717  std::hash<std::tuple<int, int, int>>,
718  std::tuple<int, int, int>>::value,
719  "");
720 
721 static_assert(
723  "");
724 static_assert(
726  "");
727 static_assert(
729  "");
730 static_assert(
732  "");
733 static_assert(
735  "");
736 static_assert(
738  "");
741 static_assert(
743  "");
745 static_assert(
747  "");
749 
750 static_assert(
751  k32Bit ==
753  "");
754 static_assert(
756  "");
757 static_assert(
758  k32Bit ==
760  "");
761 static_assert(
762  k32Bit ==
764  "");
765 static_assert(
766  k32Bit ==
768  "");
769 static_assert(
770  k32Bit ==
772  "");
773 static_assert(
775  "");
776 static_assert(
778  "");
779 static_assert(
781  "");
782 static_assert(
784  "");
785 static_assert(
787  "");
788 static_assert(
790  value,
791  "");
792 static_assert(
796  "");
797 static_assert(
801  "");
802 
803 static_assert(
805  "");
806 static_assert(
808  folly::hasher<std::pair<int, int>>,
809  std::pair<int, int>>::value,
810  "");
811 static_assert(
812  k32Bit ==
814  folly::hasher<std::tuple<int>>,
815  std::tuple<int>>::value,
816  "");
817 static_assert(
819  folly::hasher<std::tuple<std::string>>,
820  std::tuple<std::string>>::value,
821  "");
822 static_assert(
824  folly::hasher<std::tuple<int, int>>,
825  std::tuple<int, int>>::value,
826  "");
827 static_assert(
829  folly::hasher<std::tuple<int, int, int>>,
830  std::tuple<int, int, int>>::value,
831  "");
832 static_assert(
833  k32Bit ==
835  "");
836 static_assert(
838  "");
839 
841 
842 namespace {
843 template <typename H, typename T, typename F>
844 void verifyAvalanching(T initialValue, F const& advance) {
845  // This doesn't check probabilities, but does verify that every bit
846  // changed independently of every other bit, in both directions, when
847  // traversing a sequence of dependent changes. Note that it is NOT
848  // sufficient to just use a random sequence here, because even the
849  // identity function will pass. As constructed this will require
850  // 2^63 steps to complete for an identity hash, because none of the
851  // transitions with on == 63 will occur until then.
852  H const hasher;
853  constexpr std::size_t N = sizeof(decltype(hasher(initialValue))) * 8;
854 
855  // seen[i][j] if we have seen i flip on at the same time as j went off
856  bool seen[N][N] = {};
857  std::size_t unseenCount = N * (N - 1);
858  auto v = initialValue;
859  auto h = hasher(v);
860  std::size_t steps = 0;
861  // wait for 95% coverage
862  while (unseenCount > (N * (N - 1)) / 95) {
863  ++steps;
864  auto hPrev = h;
865  advance(v);
866  h = hasher(v);
867 
868  uint64_t delta = hPrev ^ h;
869  for (std::size_t i = 0; i < N - 1; ++i) {
870  if (((delta >> i) & 1) == 0) {
871  continue;
872  }
873  // we know i flipped
874  for (std::size_t j = i + 1; j < N; ++j) {
875  if (((delta >> j) & 1) == 0) {
876  continue;
877  }
878  // we know j flipped
879  bool iOn = ((hPrev >> i) & 1) == 0;
880  bool jOn = ((hPrev >> j) & 1) == 0;
881  if (iOn != jOn) {
882  auto on = iOn ? i : j;
883  auto off = iOn ? j : i;
884  if (!seen[on][off]) {
885  seen[on][off] = true;
886  --unseenCount;
887  }
888  }
889  }
890  }
891 
892  // we should actually only need a couple hundred
893  ASSERT_LT(steps, 1000) << unseenCount << " of " << (N * (N - 1))
894  << " pair transitions unseen";
895  }
896 }
897 } // namespace
898 
899 TEST(Traits, stdHashPairAvalances) {
900  verifyAvalanching<std::hash<std::pair<int, int>>>(
901  std::make_pair(0, 0), [](std::pair<int, int>& v) { v.first++; });
902 }
903 
904 TEST(Traits, stdHashTuple2Avalances) {
905  verifyAvalanching<std::hash<std::tuple<int, int>>>(
906  std::make_tuple(0, 0),
907  [](std::tuple<int, int>& v) { std::get<0>(v) += 1; });
908 }
909 
910 TEST(Traits, stdHashStringAvalances) {
911  verifyAvalanching<std::hash<std::string>, std::string>(
912  "00000000000000000000000000000", [](std::string& str) {
913  std::size_t i = 0;
914  while (str[i] == '1') {
915  str[i] = '0';
916  ++i;
917  }
918  str[i] = '1';
919  });
920 }
921 
922 TEST(Traits, follyHashUint64Avalances) {
923  verifyAvalanching<folly::Hash>(uint64_t{0}, [](uint64_t& v) { v++; });
924 }
925 
926 TEST(Traits, follyHasherInt64Avalances) {
927  verifyAvalanching<folly::hasher<int64_t>>(
928  int64_t{0}, [](int64_t& v) { v++; });
929 }
930 
931 TEST(Traits, follyHasherFloatAvalanches) {
932  verifyAvalanching<folly::hasher<float>>(0.0f, [](float& v) { v += 1; });
933 }
934 
935 TEST(Traits, follyHasherDoubleAvalanches) {
936  verifyAvalanching<folly::hasher<double>>(0.0, [](double& v) { v += 1; });
937 }
uint64_t fnv64_buf(const void *buf, size_t n, uint64_t hash=FNV_64_HASH_START) noexcept
Definition: Hash.h:199
*than *hazptr_holder h
Definition: Hazptr.h:116
auto f
Map::mapped_type get_default(const Map &map, const Key &key)
Definition: MapUtil.h:31
uint32_t jenkins_rev_unmix32(uint32_t key) noexcept
Definition: Hash.h:117
uint64_t commutative_hash_combine_range(Iter first, Iter last)
Definition: Hash.h:624
auto v
std::unique_ptr< int > A
std::string str() const
Definition: Range.h:591
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
size_t hash_combine_test(const T &t, const Ts &...ts)
Definition: HashTest.cpp:419
char b
uint64_t fnva64(const std::string &str, uint64_t hash=FNVA_64_HASH_START) noexcept
Definition: Hash.h:234
uint32_t hsieh_hash32_buf(const void *buf, size_t len) noexcept
Definition: Hash.h:246
#define ASSERT_LT(val1, val2)
Definition: gtest.h:1968
uint64_t commutative_hash_combine_range_generic(uint64_t seed, Hash const &hasher, Iter first, Iter last)
Definition: Hash.h:612
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
std::allocator< T >::value_type value_type
folly::std T
#define MIN(a, b)
Definition: http_parser.c:46
size_t operator()(const std::pair< int, int > &p) const
Definition: HashTest.cpp:413
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
TestEnum
Definition: HashTest.cpp:228
requires E e noexcept(noexcept(s.error(std::move(e))))
tuple make_tuple()
Definition: gtest-tuple.h:675
uint32_t twang_32from64(uint64_t key) noexcept
Definition: Hash.h:83
uint32_t jenkins_rev_mix32(uint32_t key) noexcept
Definition: Hash.h:97
uint64_t commutative_hash_combine_value_generic(uint64_t seed, Hash const &hasher, Value const &value)
Definition: Hash.h:584
bool_constant< true > true_type
Definition: gtest-port.h:2210
std::unordered_set< std::pair< const IValidator *, const dynamic * > > seen
Definition: JSONSchema.cpp:92
uint64_t hash_range(Iter begin, Iter end, uint64_t hash=0, Hash hasher=Hash())
Definition: Hash.h:604
bool operator!=(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:766
static constexpr bool k32Bit
Definition: HashTest.cpp:663
uint32_t fnv32_buf(const void *buf, size_t n, uint32_t hash=FNV_32_HASH_START) noexcept
Definition: Hash.h:163
uint32_t fnv32(const char *buf, uint32_t hash=FNV_32_HASH_START) noexcept
Definition: Hash.h:149
auto partial(F &&f, Args &&...args) -> detail::partial::Partial< typename std::decay< F >::type, std::tuple< typename std::decay< Args >::type... >>
Definition: Partial.h:119
TEST_P(FNVTest, Fnva64Buf)
Definition: HashTest.cpp:626
size_t hash_combine(const T &t, const Ts &...ts) noexcept(noexcept(hash_combine_generic(StdHasher{}, t, ts...)))
Definition: Hash.h:669
uint64_t fnv64(const char *buf, uint64_t hash=FNV_64_HASH_START) noexcept
Definition: Hash.h:185
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
void resetTracking()
Definition: F14TestUtil.h:336
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
static map< string, int > m
char a
std::size_t operator()(TestEnum const &e) const noexcept
Definition: HashTest.cpp:244
uint64_t fnva64_buf(const void *buf, size_t n, uint64_t hash=FNVA_64_HASH_START) noexcept
Definition: Hash.h:220
std::string in
Definition: HashTest.cpp:620
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
std::random_device rd
std::allocator< T >::const_pointer const_pointer
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
uint64_t twang_mix64(uint64_t key) noexcept
Definition: Hash.h:49
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
const char * string
Definition: Conv.cpp:212
g_t g(f_t)
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
size_t hash_combine_generic(const Hasher &) noexcept
Definition: Hash.h:634
::std::vector< string > Strings
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
const
Definition: upload.py:398
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
std::allocator< T >::size_type size_type
INSTANTIATE_TEST_CASE_P(FNVTesting, FNVTest,::testing::Values(FNVTestParam{"foobar", 0x85944171f73967e8}, FNVTestParam{"chongo was here!\n", 0x46810940eff5f915}, FNVTestParam{"127.0.0.3", 0xaabafc7104d91158}, FNVTestParam{"http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash", 0xd9b957fb7fe794c5}, FNVTestParam{"http://norvig.com/21-days.html", 0x07aaa640476e0b9a}))
std::size_t operator()(TestStruct const &) const noexcept
Definition: HashTest.cpp:251
char c
uint32_t hsieh_hash32(const char *s) noexcept
Definition: Hash.h:301
KeyT k
uint64_t out
Definition: HashTest.cpp:621
TEST(SequencedExecutor, CPUThreadPoolExecutor)
TestBigEnum
Definition: HashTest.cpp:234
PUSHMI_INLINE_VAR constexpr detail::on_fn on
Definition: on.h:100
uint64_t commutative_hash_combine(Value const &...value)
Definition: Hash.h:675
uint64_t twang_unmix64(uint64_t key) noexcept
Definition: Hash.h:66
std::vector< int > values(1'000)
std::allocator< T >::pointer pointer