llvm.org GIT mirror llvm / d4d8b2a
Add support to the hashing infrastructure for automatically hashing both integral and enumeration types. This is accomplished with a bit of template type trait magic. Thanks to Richard Smith for the core idea here to detect viable types by detecting the set of types which can be default constructed in a template parameter. This is used (in conjunction with a system for detecting nullptr_t should it exist) to provide an is_integral_or_enum type trait that doesn't need a whitelist or direct compiler support. With this, the hashing is extended to the more general facility. This will be used in a subsequent commit to hashing more things, but I wanted to make sure the type trait magic went through the build bots separately in case other compilers don't like this formulation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152217 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 8 years ago
3 changed file(s) with 48 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
112112 /// differing argument types even if they would implicit promote to a common
113113 /// type without changing the value.
114114 template
115 typename enable_if, hash_code>::type hash_value(T value);
115 typename enable_if_or_enum, hash_code>::type hash_value(T value);
116116
117117 /// \brief Compute a hash_code for a pointer's address.
118118 ///
348348 /// reading the underlying data. It is false if values of this type must
349349 /// first be passed to hash_value, and the resulting hash_codes combined.
350350 //
351 // FIXME: We want to replace is_integral and is_pointer here with a predicate
352 // which asserts that comparing the underlying storage of two values of the
353 // type for equality is equivalent to comparing the two values for equality.
354 // For all the platforms we care about, this holds for integers and pointers,
355 // but there are platforms where it doesn't and we would like to support
356 // user-defined types which happen to satisfy this property.
351 // FIXME: We want to replace is_integral_or_enum and is_pointer here with
352 // a predicate which asserts that comparing the underlying storage of two
353 // values of the type for equality is equivalent to comparing the two values
354 // for equality. For all the platforms we care about, this holds for integers
355 // and pointers, but there are platforms where it doesn't and we would like to
356 // support user-defined types which happen to satisfy this property.
357357 template struct is_hashable_data
358 : integral_constant::value || is_pointer::value) &&
358 : integral_constant_or_enum::value ||
359 is_pointer::value) &&
359360 64 % sizeof(T) == 0)> {};
360361
361362 // Special case std::pair to detect when both types are viable and when there
731732 // Declared and documented above, but defined here so that any of the hashing
732733 // infrastructure is available.
733734 template
734 typename enable_if, hash_code>::type hash_value(T value) {
735 typename enable_if_or_enum, hash_code>::type
736 hash_value(T value) {
735737 return ::llvm::hashing::detail::hash_integer_value(value);
736738 }
737739
120120 template
121121 struct is_integral : is_integral_impl {};
122122
123 /// \brief Metafunction that determines whether the given type is either an
124 /// integral type or an enumeration type.
125 ///
126 /// Note that this accepts potentially more integral types than we whitelist
127 /// above for is_integral, it should accept essentially anything the compiler
128 /// believes is an integral type.
129 template class is_integral_or_enum {
130
131 // Form a return type that can only be instantiated with an integral or enum
132 // types (or with nullptr_t in C++11).
133 template struct check1_return_type { char c[2]; };
134 template static check1_return_type checker1(U*);
135 static char checker1(...);
136
137 // Form a return type that can only be instantiated with nullptr_t in C++11
138 // mode. It's harmless in C++98 mode, but this allows us to filter nullptr_t
139 // when building in C++11 mode without having to detect that mode for each
140 // different compiler.
141 struct nonce {};
142 template
143 struct check2_return_type { char c[2]; };
144 template static check2_return_type checker2(U*);
145 static char checker2(...);
146
147 public:
148 enum {
149 value = (sizeof(char) != sizeof(checker1((T*)0)) &&
150 sizeof(char) == sizeof(checker2((T*)0)))
151 };
152 };
153
123154 /// \brief Metafunction that determines whether the given type is a pointer
124155 /// type.
125156 template struct is_pointer : false_type {};
126157 template struct is_pointer : true_type {};
127158
128
129159 // enable_if_c - Enable/disable a template based on a metafunction
130160 template
131161 struct enable_if_c {
5050
5151 namespace {
5252
53 enum TestEnumeration {
54 TE_Foo = 42,
55 TE_Bar = 43
56 };
5357
5458 TEST(HashingTest, HashValueBasicTest) {
5559 int x = 42, y = 43, c = 'x';
6064 const volatile int cvi = 71;
6165 uintptr_t addr = reinterpret_cast(&y);
6266 EXPECT_EQ(hash_value(42), hash_value(x));
67 EXPECT_EQ(hash_value(42), hash_value(TE_Foo));
6368 EXPECT_NE(hash_value(42), hash_value(y));
69 EXPECT_NE(hash_value(42), hash_value(TE_Bar));
6470 EXPECT_NE(hash_value(42), hash_value(p));
6571 EXPECT_EQ(hash_value(71), hash_value(i));
6672 EXPECT_EQ(hash_value(71), hash_value(ci));