//===- llvm/Support/HashBuilder.h - Convenient hashing interface-*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements an interface allowing to conveniently build hashes of // various data types, without relying on the underlying hasher type to know // about hashed data types. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_HASHBUILDER_H #define LLVM_SUPPORT_HASHBUILDER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/type_traits.h" #include <iterator> #include <optional> #include <utility> namespace llvm { namespace hashbuilder_detail { /// Trait to indicate whether a type's bits can be hashed directly (after /// endianness correction). template <typename U> struct IsHashableData : std::integral_constant<bool, is_integral_or_enum<U>::value> { … }; } // namespace hashbuilder_detail /// Declares the hasher member, and functions forwarding directly to the hasher. template <typename HasherT> class HashBuilderBase { … }; /// Interface to help hash various types through a hasher type. /// /// Via provided specializations of `add`, `addRange`, and `addRangeElements` /// functions, various types (e.g. `ArrayRef`, `StringRef`, etc.) can be hashed /// without requiring any knowledge of hashed types from the hasher type. /// /// The only method expected from the templated hasher type `HasherT` is: /// * void update(ArrayRef<uint8_t> Data) /// /// Additionally, the following methods will be forwarded to the hasher type: /// * decltype(std::declval<HasherT &>().final()) final() /// * decltype(std::declval<HasherT &>().result()) result() /// /// From a user point of view, the interface provides the following: /// * `template<typename T> add(const T &Value)` /// The `add` function implements hashing of various types. /// * `template <typename ItT> void addRange(ItT First, ItT Last)` /// The `addRange` function is designed to aid hashing a range of values. /// It explicitly adds the size of the range in the hash. /// * `template <typename ItT> void addRangeElements(ItT First, ItT Last)` /// The `addRangeElements` function is also designed to aid hashing a range of /// values. In contrast to `addRange`, it **ignores** the size of the range, /// behaving as if elements were added one at a time with `add`. /// /// User-defined `struct` types can participate in this interface by providing /// an `addHash` templated function. See the associated template specialization /// for details. /// /// This interface does not impose requirements on the hasher /// `update(ArrayRef<uint8_t> Data)` method. We want to avoid collisions for /// variable-size types; for example for /// ``` /// builder.add({1}); /// builder.add({2, 3}); /// ``` /// and /// ``` /// builder.add({1, 2}); /// builder.add({3}); /// ``` /// . Thus, specializations of `add` and `addHash` for variable-size types must /// not assume that the hasher type considers the size as part of the hash; they /// must explicitly add the size to the hash. See for example specializations /// for `ArrayRef` and `StringRef`. /// /// Additionally, since types are eventually forwarded to the hasher's /// `void update(ArrayRef<uint8_t>)` method, endianness plays a role in the hash /// computation (for example when computing `add((int)123)`). /// Specifiying a non-`native` `Endianness` template parameter allows to compute /// stable hash across platforms with different endianness. template <typename HasherT, llvm::endianness Endianness> class HashBuilder : public HashBuilderBase<HasherT> { … }; namespace hashbuilder_detail { class HashCodeHasher { … }; HashCodeHashBuilder; } // namespace hashbuilder_detail /// Provide a default implementation of `hash_value` when `addHash(const T &)` /// is supported. template <typename T> std::enable_if_t< is_detected<hashbuilder_detail::HashCodeHashBuilder::HasAddHashT, T>::value, hash_code> hash_value(const T &Value) { … } } // end namespace llvm #endif // LLVM_SUPPORT_HASHBUILDER_H