llvm.org GIT mirror llvm / c7384cf
Add support for hashing pairs by delegating to each sub-object. There is an open question of whether we can do better than this by treating pairs as boring data containers and directly hashing the two subobjects. This at least makes the API reasonable. In order to make this change, I reorganized the header a bit. I lifted the declarations of the hash_value functions up to the top of the header with their doxygen comments as these are intended for users to interact with. They shouldn't have to wade through implementation details. I then defined them at the very end so that they could be defined in terms of hash_combine or any other hashing infrastructure. Added various pair-hashing unittests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151882 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 8 years ago
2 changed file(s) with 90 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
101101 /// \brief Allow a hash_code to be directly run through hash_value.
102102 friend size_t hash_value(const hash_code &code) { return code.value; }
103103 };
104
105 /// \brief Compute a hash_code for any integer value.
106 ///
107 /// Note that this function is intended to compute the same hash_code for
108 /// a particular value without regard to the pre-promotion type. This is in
109 /// contrast to hash_combine which may produce different hash_codes for
110 /// differing argument types even if they would implicit promote to a common
111 /// type without changing the value.
112 template
113 typename enable_if, hash_code>::type hash_value(T value);
114
115 /// \brief Compute a hash_code for a pointer's address.
116 ///
117 /// N.B.: This hashes the *address*. Not the value and not the type.
118 template hash_code hash_value(const T *ptr);
119
120 /// \brief Compute a hash_code for a pair of objects.
121 template
122 hash_code hash_value(const std::pair &arg);
123
124
125 /// \brief Override the execution seed with a fixed value.
126 ///
127 /// This hashing library uses a per-execution seed designed to change on each
128 /// run with high probability in order to ensure that the hash codes are not
129 /// attackable and to ensure that output which is intended to be stable does
130 /// not rely on the particulars of the hash codes produced.
131 ///
132 /// That said, there are use cases where it is important to be able to
133 /// reproduce *exactly* a specific behavior. To that end, we provide a function
134 /// which will forcibly set the seed to a fixed value. This must be done at the
135 /// start of the program, before any hashes are computed. Also, it cannot be
136 /// undone. This makes it thread-hostile and very hard to use outside of
137 /// immediately on start of a simple program designed for reproducible
138 /// behavior.
139 void set_fixed_execution_hash_seed(size_t fixed_value);
104140
105141
106142 // All of the implementation details of actually computing the various hash
297333 }
298334
299335
300 /// \brief Helper to hash the value of a single integer.
301 ///
302 /// Overloads for smaller integer types are not provided to ensure consistent
303 /// behavior in the presence of integral promotions. Essentially,
304 /// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
305 inline hash_code hash_integer_value(uint64_t value) {
306 // Similar to hash_4to8_bytes but using a seed instead of length.
307 const uint64_t seed = get_execution_seed();
308 const char *s = reinterpret_cast(&value);
309 const uint64_t a = fetch32(s);
310 return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
311 }
312
313 } // namespace detail
314 } // namespace hashing
315
316
317 /// \brief Override the execution seed with a fixed value.
318 ///
319 /// This hashing library uses a per-execution seed designed to change on each
320 /// run with high probability in order to ensure that the hash codes are not
321 /// attackable and to ensure that output which is intended to be stable does
322 /// not rely on the particulars of the hash codes produced.
323 ///
324 /// That said, there are use cases where it is important to be able to
325 /// reproduce *exactly* a specific behavior. To that end, we provide a function
326 /// which will forcibly set the seed to a fixed value. This must be done at the
327 /// start of the program, before any hashes are computed. Also, it cannot be
328 /// undone. This makes it thread-hostile and very hard to use outside of
329 /// immediately on start of a simple program designed for reproducible
330 /// behavior.
331 void set_fixed_execution_hash_seed(size_t fixed_value);
332
333
334 /// \brief Compute a hash_code for any integer value.
335 ///
336 /// Note that this function is intended to compute the same hash_code for
337 /// a particular value without regard to the pre-promotion type. This is in
338 /// contrast to hash_combine which may produce different hash_codes for
339 /// differing argument types even if they would implicit promote to a common
340 /// type without changing the value.
341 template
342 typename enable_if, hash_code>::type hash_value(T value) {
343 return ::llvm::hashing::detail::hash_integer_value(value);
344 }
345
346 /// \brief Compute a hash_code for a pointer's address.
347 ///
348 /// N.B.: This hashes the *address*. Not the value and not the type.
349 template hash_code hash_value(const T *ptr) {
350 return ::llvm::hashing::detail::hash_integer_value(
351 reinterpret_cast(ptr));
352 }
353
354
355 // Implementation details for implementing hash combining functions.
356 namespace hashing {
357 namespace detail {
358
359336 /// \brief Trait to indicate whether a type's bits can be hashed directly.
360337 ///
361338 /// A type trait which is true if we want to combine values for hashing by
712689
713690 #endif
714691
692
693 // Implementation details for implementatinos of hash_value overloads provided
694 // here.
695 namespace hashing {
696 namespace detail {
697
698 /// \brief Helper to hash the value of a single integer.
699 ///
700 /// Overloads for smaller integer types are not provided to ensure consistent
701 /// behavior in the presence of integral promotions. Essentially,
702 /// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
703 inline hash_code hash_integer_value(uint64_t value) {
704 // Similar to hash_4to8_bytes but using a seed instead of length.
705 const uint64_t seed = get_execution_seed();
706 const char *s = reinterpret_cast(&value);
707 const uint64_t a = fetch32(s);
708 return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
709 }
710
711 } // namespace detail
712 } // namespace hashing
713
714 // Declared and documented above, but defined here so that any of the hashing
715 // infrastructure is available.
716 template
717 typename enable_if, hash_code>::type hash_value(T value) {
718 return ::llvm::hashing::detail::hash_integer_value(value);
719 }
720
721 // Declared and documented above, but defined here so that any of the hashing
722 // infrastructure is available.
723 template hash_code hash_value(const T *ptr) {
724 return ::llvm::hashing::detail::hash_integer_value(
725 reinterpret_cast(ptr));
726 }
727
728 // Declared and documented above, but defined here so that any of the hashing
729 // infrastructure is available.
730 template
731 hash_code hash_value(const std::pair &arg) {
732 return hash_combine(arg.first, arg.second);
733 }
734
715735 } // namespace llvm
716736
717737 #endif
5959 EXPECT_EQ(hash_value(c), hash_value('x'));
6060 EXPECT_EQ(hash_value('4'), hash_value('0' + 4));
6161 EXPECT_EQ(hash_value(addr), hash_value(&y));
62
63 EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43)));
64 EXPECT_NE(hash_combine(43, 42), hash_value(std::make_pair(42, 43)));
65 EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43ull)));
66 EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42, 43ull)));
67 EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43)));
68 EXPECT_EQ(hash_combine(42, hash_combine(43, hash_combine(44, 45))),
69 hash_value(
70 std::make_pair(42, std::make_pair(43, std::make_pair(44, 45)))));
71 EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43)));
72 EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43)));
6273 }
6374
6475 template T *begin(T (&arr)[N]) { return arr; }