@@ -85,20 +85,67 @@ template <typename HasherT> class HashBuilderBase {
85
85
HasherT &Hasher;
86
86
};
87
87
88
- // / Implementation of the `HashBuilder` interface.
88
+ // / Interface to help hash various types through a hasher type.
89
+ // /
90
+ // / Via provided specializations of `add`, `addRange`, and `addRangeElements`
91
+ // / functions, various types (e.g. `ArrayRef`, `StringRef`, etc.) can be hashed
92
+ // / without requiring any knowledge of hashed types from the hasher type.
93
+ // /
94
+ // / The only method expected from the templated hasher type `HasherT` is:
95
+ // / * void update(ArrayRef<uint8_t> Data)
96
+ // /
97
+ // / Additionally, the following methods will be forwarded to the hasher type:
98
+ // / * decltype(std::declval<HasherT &>().final()) final()
99
+ // / * decltype(std::declval<HasherT &>().result()) result()
100
+ // /
101
+ // / From a user point of view, the interface provides the following:
102
+ // / * `template<typename T> add(const T &Value)`
103
+ // / The `add` function implements hashing of various types.
104
+ // / * `template <typename ItT> void addRange(ItT First, ItT Last)`
105
+ // / The `addRange` function is designed to aid hashing a range of values.
106
+ // / It explicitly adds the size of the range in the hash.
107
+ // / * `template <typename ItT> void addRangeElements(ItT First, ItT Last)`
108
+ // / The `addRangeElements` function is also designed to aid hashing a range of
109
+ // / values. In contrast to `addRange`, it **ignores** the size of the range,
110
+ // / behaving as if elements were added one at a time with `add`.
111
+ // /
112
+ // / User-defined `struct` types can participate in this interface by providing
113
+ // / an `addHash` templated function. See the associated template specialization
114
+ // / for details.
115
+ // /
116
+ // / This interface does not impose requirements on the hasher
117
+ // / `update(ArrayRef<uint8_t> Data)` method. We want to avoid collisions for
118
+ // / variable-size types; for example for
119
+ // / ```
120
+ // / builder.add({1});
121
+ // / builder.add({2, 3});
122
+ // / ```
123
+ // / and
124
+ // / ```
125
+ // / builder.add({1, 2});
126
+ // / builder.add({3});
127
+ // / ```
128
+ // / . Thus, specializations of `add` and `addHash` for variable-size types must
129
+ // / not assume that the hasher type considers the size as part of the hash; they
130
+ // / must explicitly add the size to the hash. See for example specializations
131
+ // / for `ArrayRef` and `StringRef`.
132
+ // /
133
+ // / Additionally, since types are eventually forwarded to the hasher's
134
+ // / `void update(ArrayRef<uint8_t>)` method, endianness plays a role in the hash
135
+ // / computation (for example when computing `add((int)123)`).
136
+ // / Specifiying a non-`native` `Endianness` template parameter allows to compute
137
+ // / stable hash across platforms with different endianness.
89
138
template <typename HasherT, support::endianness Endianness>
90
- class HashBuilderImpl : public HashBuilderBase <HasherT> {
139
+ class HashBuilder : public HashBuilderBase <HasherT> {
91
140
public:
92
- explicit HashBuilderImpl (HasherT &Hasher)
93
- : HashBuilderBase<HasherT>(Hasher) {}
141
+ explicit HashBuilder (HasherT &Hasher) : HashBuilderBase<HasherT>(Hasher) {}
94
142
template <typename ... ArgTypes>
95
- explicit HashBuilderImpl (ArgTypes &&...Args)
143
+ explicit HashBuilder (ArgTypes &&...Args)
96
144
: HashBuilderBase<HasherT>(Args...) {}
97
145
98
146
// / Implement hashing for hashable data types, e.g. integral or enum values.
99
147
template <typename T>
100
- std::enable_if_t <hashbuilder_detail::IsHashableData<T>::value,
101
- HashBuilderImpl &>
148
+ std::enable_if_t <hashbuilder_detail::IsHashableData<T>::value, HashBuilder &>
102
149
add (T Value) {
103
150
return adjustForEndiannessAndAdd (Value);
104
151
}
@@ -116,7 +163,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
116
163
// / builder.add({3});
117
164
// / ```
118
165
// / do not collide.
119
- template <typename T> HashBuilderImpl &add (ArrayRef<T> Value) {
166
+ template <typename T> HashBuilder &add (ArrayRef<T> Value) {
120
167
// As of implementation time, simply calling `addRange(Value)` would also go
121
168
// through the `update` fast path. But that would rely on the implementation
122
169
// details of `ArrayRef::begin()` and `ArrayRef::end()`. Explicitly call
@@ -146,7 +193,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
146
193
// / builder.add("c");
147
194
// / ```
148
195
// / do not collide.
149
- HashBuilderImpl &add (StringRef Value) {
196
+ HashBuilder &add (StringRef Value) {
150
197
// As of implementation time, simply calling `addRange(Value)` would also go
151
198
// through `update`. But that would rely on the implementation of
152
199
// `StringRef::begin()` and `StringRef::end()`. Explicitly call `update` to
@@ -159,7 +206,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
159
206
160
207
template <typename T>
161
208
using HasAddHashT =
162
- decltype (addHash(std::declval<HashBuilderImpl &>(), std::declval<T &>()));
209
+ decltype (addHash(std::declval<HashBuilder &>(), std::declval<T &>()));
163
210
// / Implement hashing for user-defined `struct`s.
164
211
// /
165
212
// / Any user-define `struct` can participate in hashing via `HashBuilder` by
@@ -179,7 +226,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
179
226
// / };
180
227
// /
181
228
// / template <typename HasherT, support::endianness Endianness>
182
- // / void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
229
+ // / void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
183
230
// / const SimpleStruct &Value) {
184
231
// / HBuilder.add(Value.c);
185
232
// / HBuilder.add(Value.i);
@@ -199,7 +246,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
199
246
// / // If possible, we want to hash both `I` and `C` in a single
200
247
// / // `update` call for performance concerns.
201
248
// / template <typename HasherT, support::endianness Endianness>
202
- // / friend void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
249
+ // / friend void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
203
250
// / const StructWithFastHash &Value) {
204
251
// / if (Endianness == support::endian::system_endianness()) {
205
252
// / HBuilder.update(ArrayRef(
@@ -229,7 +276,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
229
276
// / Elements[I] = I;
230
277
// / }
231
278
// / template <typename HasherT, support::endianness Endianness>
232
- // / friend void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
279
+ // / friend void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
233
280
// / const CustomContainer &Value) {
234
281
// / if (Endianness == support::endian::system_endianness()) {
235
282
// / HBuilder.update(ArrayRef(
@@ -246,18 +293,18 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
246
293
template <typename T>
247
294
std::enable_if_t <is_detected<HasAddHashT, T>::value &&
248
295
!hashbuilder_detail::IsHashableData<T>::value,
249
- HashBuilderImpl &>
296
+ HashBuilder &>
250
297
add (const T &Value) {
251
298
addHash (*this , Value);
252
299
return *this ;
253
300
}
254
301
255
302
template <typename T1, typename T2>
256
- HashBuilderImpl &add (const std::pair<T1, T2> &Value) {
303
+ HashBuilder &add (const std::pair<T1, T2> &Value) {
257
304
return add (Value.first , Value.second );
258
305
}
259
306
260
- template <typename ... Ts> HashBuilderImpl &add (const std::tuple<Ts...> &Arg) {
307
+ template <typename ... Ts> HashBuilder &add (const std::tuple<Ts...> &Arg) {
261
308
std::apply ([this ](const auto &...Args ) { this ->add (Args...); }, Arg);
262
309
return *this ;
263
310
}
@@ -273,31 +320,29 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
273
320
// / add(Arg2)
274
321
// / ```
275
322
template <typename ... Ts>
276
- std::enable_if_t <(sizeof ...(Ts) > 1 ), HashBuilderImpl &>
277
- add (const Ts &...Args) {
323
+ std::enable_if_t <(sizeof ...(Ts) > 1 ), HashBuilder &> add (const Ts &...Args) {
278
324
return (add (Args), ...);
279
325
}
280
326
281
327
template <typename ForwardIteratorT>
282
- HashBuilderImpl &addRange (ForwardIteratorT First, ForwardIteratorT Last) {
328
+ HashBuilder &addRange (ForwardIteratorT First, ForwardIteratorT Last) {
283
329
add (std::distance (First, Last));
284
330
return addRangeElements (First, Last);
285
331
}
286
332
287
- template <typename RangeT> HashBuilderImpl &addRange (const RangeT &Range) {
333
+ template <typename RangeT> HashBuilder &addRange (const RangeT &Range) {
288
334
return addRange (adl_begin (Range), adl_end (Range));
289
335
}
290
336
291
337
template <typename ForwardIteratorT>
292
- HashBuilderImpl &addRangeElements (ForwardIteratorT First,
293
- ForwardIteratorT Last) {
338
+ HashBuilder &addRangeElements (ForwardIteratorT First, ForwardIteratorT Last) {
294
339
return addRangeElementsImpl (
295
340
First, Last,
296
341
typename std::iterator_traits<ForwardIteratorT>::iterator_category ());
297
342
}
298
343
299
344
template <typename RangeT>
300
- HashBuilderImpl &addRangeElements (const RangeT &Range) {
345
+ HashBuilder &addRangeElements (const RangeT &Range) {
301
346
return addRangeElements (adl_begin (Range), adl_end (Range));
302
347
}
303
348
@@ -306,7 +351,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
306
351
std::declval<T &>(), support::endianness::little));
307
352
// / Adjust `Value` for the target endianness and add it to the hash.
308
353
template <typename T>
309
- std::enable_if_t <is_detected<HasByteSwapT, T>::value, HashBuilderImpl &>
354
+ std::enable_if_t <is_detected<HasByteSwapT, T>::value, HashBuilder &>
310
355
adjustForEndiannessAndAdd (const T &Value) {
311
356
T SwappedValue = support::endian::byte_swap (Value, Endianness);
312
357
this ->update (ArrayRef (reinterpret_cast <const uint8_t *>(&SwappedValue),
@@ -318,9 +363,9 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
318
363
// FIXME: Once available, specialize this function for `contiguous_iterator`s,
319
364
// and use it for `ArrayRef` and `StringRef`.
320
365
template <typename ForwardIteratorT>
321
- HashBuilderImpl &addRangeElementsImpl (ForwardIteratorT First,
322
- ForwardIteratorT Last,
323
- std::forward_iterator_tag) {
366
+ HashBuilder &addRangeElementsImpl (ForwardIteratorT First,
367
+ ForwardIteratorT Last,
368
+ std::forward_iterator_tag) {
324
369
for (auto It = First; It != Last; ++It)
325
370
add (*It);
326
371
return *this ;
@@ -329,67 +374,14 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
329
374
template <typename T>
330
375
std::enable_if_t <hashbuilder_detail::IsHashableData<T>::value &&
331
376
Endianness == support::endian::system_endianness(),
332
- HashBuilderImpl &>
377
+ HashBuilder &>
333
378
addRangeElementsImpl (T *First, T *Last, std::forward_iterator_tag) {
334
379
this ->update (ArrayRef (reinterpret_cast <const uint8_t *>(First),
335
380
(Last - First) * sizeof (T)));
336
381
return *this ;
337
382
}
338
383
};
339
384
340
- // / Interface to help hash various types through a hasher type.
341
- // /
342
- // / Via provided specializations of `add`, `addRange`, and `addRangeElements`
343
- // / functions, various types (e.g. `ArrayRef`, `StringRef`, etc.) can be hashed
344
- // / without requiring any knowledge of hashed types from the hasher type.
345
- // /
346
- // / The only method expected from the templated hasher type `HasherT` is:
347
- // / * void update(ArrayRef<uint8_t> Data)
348
- // /
349
- // / Additionally, the following methods will be forwarded to the hasher type:
350
- // / * decltype(std::declval<HasherT &>().final()) final()
351
- // / * decltype(std::declval<HasherT &>().result()) result()
352
- // /
353
- // / From a user point of view, the interface provides the following:
354
- // / * `template<typename T> add(const T &Value)`
355
- // / The `add` function implements hashing of various types.
356
- // / * `template <typename ItT> void addRange(ItT First, ItT Last)`
357
- // / The `addRange` function is designed to aid hashing a range of values.
358
- // / It explicitly adds the size of the range in the hash.
359
- // / * `template <typename ItT> void addRangeElements(ItT First, ItT Last)`
360
- // / The `addRangeElements` function is also designed to aid hashing a range of
361
- // / values. In contrast to `addRange`, it **ignores** the size of the range,
362
- // / behaving as if elements were added one at a time with `add`.
363
- // /
364
- // / User-defined `struct` types can participate in this interface by providing
365
- // / an `addHash` templated function. See the associated template specialization
366
- // / for details.
367
- // /
368
- // / This interface does not impose requirements on the hasher
369
- // / `update(ArrayRef<uint8_t> Data)` method. We want to avoid collisions for
370
- // / variable-size types; for example for
371
- // / ```
372
- // / builder.add({1});
373
- // / builder.add({2, 3});
374
- // / ```
375
- // / and
376
- // / ```
377
- // / builder.add({1, 2});
378
- // / builder.add({3});
379
- // / ```
380
- // / . Thus, specializations of `add` and `addHash` for variable-size types must
381
- // / not assume that the hasher type considers the size as part of the hash; they
382
- // / must explicitly add the size to the hash. See for example specializations
383
- // / for `ArrayRef` and `StringRef`.
384
- // /
385
- // / Additionally, since types are eventually forwarded to the hasher's
386
- // / `void update(ArrayRef<uint8_t>)` method, endianness plays a role in the hash
387
- // / computation (for example when computing `add((int)123)`).
388
- // / Specifiying a non-`native` `Endianness` template parameter allows to compute
389
- // / stable hash across platforms with different endianness.
390
- template <class HasherT , support::endianness Endianness>
391
- using HashBuilder = HashBuilderImpl<HasherT, Endianness>;
392
-
393
385
namespace hashbuilder_detail {
394
386
class HashCodeHasher {
395
387
public:
0 commit comments