@@ -85,20 +85,67 @@ template <typename HasherT> class HashBuilderBase {
8585 HasherT &Hasher;
8686};
8787
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.
89138template <typename HasherT, support::endianness Endianness>
90- class HashBuilderImpl : public HashBuilderBase <HasherT> {
139+ class HashBuilder : public HashBuilderBase <HasherT> {
91140public:
92- explicit HashBuilderImpl (HasherT &Hasher)
93- : HashBuilderBase<HasherT>(Hasher) {}
141+ explicit HashBuilder (HasherT &Hasher) : HashBuilderBase<HasherT>(Hasher) {}
94142 template <typename ... ArgTypes>
95- explicit HashBuilderImpl (ArgTypes &&...Args)
143+ explicit HashBuilder (ArgTypes &&...Args)
96144 : HashBuilderBase<HasherT>(Args...) {}
97145
98146 // / Implement hashing for hashable data types, e.g. integral or enum values.
99147 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 &>
102149 add (T Value) {
103150 return adjustForEndiannessAndAdd (Value);
104151 }
@@ -116,7 +163,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
116163 // / builder.add({3});
117164 // / ```
118165 // / do not collide.
119- template <typename T> HashBuilderImpl &add (ArrayRef<T> Value) {
166+ template <typename T> HashBuilder &add (ArrayRef<T> Value) {
120167 // As of implementation time, simply calling `addRange(Value)` would also go
121168 // through the `update` fast path. But that would rely on the implementation
122169 // details of `ArrayRef::begin()` and `ArrayRef::end()`. Explicitly call
@@ -146,7 +193,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
146193 // / builder.add("c");
147194 // / ```
148195 // / do not collide.
149- HashBuilderImpl &add (StringRef Value) {
196+ HashBuilder &add (StringRef Value) {
150197 // As of implementation time, simply calling `addRange(Value)` would also go
151198 // through `update`. But that would rely on the implementation of
152199 // `StringRef::begin()` and `StringRef::end()`. Explicitly call `update` to
@@ -159,7 +206,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
159206
160207 template <typename T>
161208 using HasAddHashT =
162- decltype (addHash(std::declval<HashBuilderImpl &>(), std::declval<T &>()));
209+ decltype (addHash(std::declval<HashBuilder &>(), std::declval<T &>()));
163210 // / Implement hashing for user-defined `struct`s.
164211 // /
165212 // / Any user-define `struct` can participate in hashing via `HashBuilder` by
@@ -179,7 +226,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
179226 // / };
180227 // /
181228 // / template <typename HasherT, support::endianness Endianness>
182- // / void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
229+ // / void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
183230 // / const SimpleStruct &Value) {
184231 // / HBuilder.add(Value.c);
185232 // / HBuilder.add(Value.i);
@@ -199,7 +246,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
199246 // / // If possible, we want to hash both `I` and `C` in a single
200247 // / // `update` call for performance concerns.
201248 // / template <typename HasherT, support::endianness Endianness>
202- // / friend void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
249+ // / friend void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
203250 // / const StructWithFastHash &Value) {
204251 // / if (Endianness == support::endian::system_endianness()) {
205252 // / HBuilder.update(ArrayRef(
@@ -229,7 +276,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
229276 // / Elements[I] = I;
230277 // / }
231278 // / template <typename HasherT, support::endianness Endianness>
232- // / friend void addHash(HashBuilderImpl <HasherT, Endianness> &HBuilder,
279+ // / friend void addHash(HashBuilder <HasherT, Endianness> &HBuilder,
233280 // / const CustomContainer &Value) {
234281 // / if (Endianness == support::endian::system_endianness()) {
235282 // / HBuilder.update(ArrayRef(
@@ -246,18 +293,18 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
246293 template <typename T>
247294 std::enable_if_t <is_detected<HasAddHashT, T>::value &&
248295 !hashbuilder_detail::IsHashableData<T>::value,
249- HashBuilderImpl &>
296+ HashBuilder &>
250297 add (const T &Value) {
251298 addHash (*this , Value);
252299 return *this ;
253300 }
254301
255302 template <typename T1, typename T2>
256- HashBuilderImpl &add (const std::pair<T1, T2> &Value) {
303+ HashBuilder &add (const std::pair<T1, T2> &Value) {
257304 return add (Value.first , Value.second );
258305 }
259306
260- template <typename ... Ts> HashBuilderImpl &add (const std::tuple<Ts...> &Arg) {
307+ template <typename ... Ts> HashBuilder &add (const std::tuple<Ts...> &Arg) {
261308 std::apply ([this ](const auto &...Args ) { this ->add (Args...); }, Arg);
262309 return *this ;
263310 }
@@ -273,31 +320,29 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
273320 // / add(Arg2)
274321 // / ```
275322 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) {
278324 return (add (Args), ...);
279325 }
280326
281327 template <typename ForwardIteratorT>
282- HashBuilderImpl &addRange (ForwardIteratorT First, ForwardIteratorT Last) {
328+ HashBuilder &addRange (ForwardIteratorT First, ForwardIteratorT Last) {
283329 add (std::distance (First, Last));
284330 return addRangeElements (First, Last);
285331 }
286332
287- template <typename RangeT> HashBuilderImpl &addRange (const RangeT &Range) {
333+ template <typename RangeT> HashBuilder &addRange (const RangeT &Range) {
288334 return addRange (adl_begin (Range), adl_end (Range));
289335 }
290336
291337 template <typename ForwardIteratorT>
292- HashBuilderImpl &addRangeElements (ForwardIteratorT First,
293- ForwardIteratorT Last) {
338+ HashBuilder &addRangeElements (ForwardIteratorT First, ForwardIteratorT Last) {
294339 return addRangeElementsImpl (
295340 First, Last,
296341 typename std::iterator_traits<ForwardIteratorT>::iterator_category ());
297342 }
298343
299344 template <typename RangeT>
300- HashBuilderImpl &addRangeElements (const RangeT &Range) {
345+ HashBuilder &addRangeElements (const RangeT &Range) {
301346 return addRangeElements (adl_begin (Range), adl_end (Range));
302347 }
303348
@@ -306,7 +351,7 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
306351 std::declval<T &>(), support::endianness::little));
307352 // / Adjust `Value` for the target endianness and add it to the hash.
308353 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 &>
310355 adjustForEndiannessAndAdd (const T &Value) {
311356 T SwappedValue = support::endian::byte_swap (Value, Endianness);
312357 this ->update (ArrayRef (reinterpret_cast <const uint8_t *>(&SwappedValue),
@@ -318,9 +363,9 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
318363 // FIXME: Once available, specialize this function for `contiguous_iterator`s,
319364 // and use it for `ArrayRef` and `StringRef`.
320365 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) {
324369 for (auto It = First; It != Last; ++It)
325370 add (*It);
326371 return *this ;
@@ -329,67 +374,14 @@ class HashBuilderImpl : public HashBuilderBase<HasherT> {
329374 template <typename T>
330375 std::enable_if_t <hashbuilder_detail::IsHashableData<T>::value &&
331376 Endianness == support::endian::system_endianness(),
332- HashBuilderImpl &>
377+ HashBuilder &>
333378 addRangeElementsImpl (T *First, T *Last, std::forward_iterator_tag) {
334379 this ->update (ArrayRef (reinterpret_cast <const uint8_t *>(First),
335380 (Last - First) * sizeof (T)));
336381 return *this ;
337382 }
338383};
339384
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-
393385namespace hashbuilder_detail {
394386class HashCodeHasher {
395387public:
0 commit comments