//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- 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 // //===----------------------------------------------------------------------===// /// /// \file /// This file defines DenseMapInfo traits for DenseMap. /// //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_DENSEMAPINFO_H #define LLVM_ADT_DENSEMAPINFO_H #include #include #include #include #include #include #include #include namespace llvm { namespace densemap::detail { // A bit mixer with very low latency using one multiplications and one // xor-shift. The constant is from splitmix64. inline uint64_t mix(uint64_t x) { x *= 0xbf58476d1ce4e5b9u; x ^= x >> 31; return x; } } // namespace densemap::detail namespace detail { /// Simplistic combination of 32-bit hash values into 32-bit hash values. inline unsigned combineHashValue(unsigned a, unsigned b) { uint64_t x = (uint64_t)a << 32 | (uint64_t)b; return (unsigned)densemap::detail::mix(x); } } // end namespace detail /// An information struct used to provide DenseMap with the various necessary /// components for a given value type `T`. `Enable` is an optional additional /// parameter that is used to support SFINAE (generally using std::enable_if_t) /// in derived DenseMapInfo specializations; in non-SFINAE use cases this should /// just be `void`. template struct DenseMapInfo { // static unsigned getHashValue(const T &Val); // static bool isEqual(const T &LHS, const T &RHS); }; // Provide DenseMapInfo for all pointers. Avoid requiring T to be complete so // clients can instantiate DenseMap with forward declared key types. template struct DenseMapInfo { static unsigned getHashValue(const T *PtrVal) { return densemap::detail::mix(reinterpret_cast(PtrVal)); } static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; } }; // Provide DenseMapInfo for all integral types. template struct DenseMapInfo>> { static unsigned getHashValue(const T &Val) { if constexpr (std::is_unsigned_v && sizeof(T) > sizeof(unsigned)) return densemap::detail::mix(Val); else return static_cast(Val * static_cast>(37U)); } static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; } }; // Provide DenseMapInfo for all pairs whose members have info. template struct DenseMapInfo> { using Pair = std::pair; using FirstInfo = DenseMapInfo; using SecondInfo = DenseMapInfo; static unsigned getHashValue(const Pair& PairVal) { return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first), SecondInfo::getHashValue(PairVal.second)); } // Expose an additional function intended to be used by other // specializations of DenseMapInfo without needing to know how // to combine hash values manually static unsigned getHashValuePiecewise(const T &First, const U &Second) { return detail::combineHashValue(FirstInfo::getHashValue(First), SecondInfo::getHashValue(Second)); } static bool isEqual(const Pair &LHS, const Pair &RHS) { return FirstInfo::isEqual(LHS.first, RHS.first) && SecondInfo::isEqual(LHS.second, RHS.second); } }; // Provide DenseMapInfo for all tuples whose members have info. template struct DenseMapInfo> { using Tuple = std::tuple; template static unsigned getHashValueImpl(const Tuple &values) { if constexpr (I == sizeof...(Ts)) { return 0; } else { using EltType = std::tuple_element_t; return detail::combineHashValue( DenseMapInfo::getHashValue(std::get(values)), getHashValueImpl(values)); } } static unsigned getHashValue(const std::tuple &values) { return getHashValueImpl<0>(values); } template static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::index_sequence) { return (DenseMapInfo>::isEqual( std::get(lhs), std::get(rhs)) && ...); } static bool isEqual(const Tuple &lhs, const Tuple &rhs) { return isEqualImpl(lhs, rhs, std::index_sequence_for{}); } }; // Provide DenseMapInfo for enum classes. template struct DenseMapInfo>> { using UnderlyingType = std::underlying_type_t; using Info = DenseMapInfo; static unsigned getHashValue(const Enum &Val) { return Info::getHashValue(static_cast(Val)); } static bool isEqual(const Enum &LHS, const Enum &RHS) { return LHS == RHS; } }; template struct DenseMapInfo> { using Optional = std::optional; using Info = DenseMapInfo; static unsigned getHashValue(const Optional &OptionalVal) { if (OptionalVal) return detail::combineHashValue(1, Info::getHashValue(*OptionalVal)); return 0; } static bool isEqual(const Optional &LHS, const Optional &RHS) { if (LHS && RHS) { return Info::isEqual(LHS.value(), RHS.value()); } return !LHS && !RHS; } }; } // end namespace llvm #endif // LLVM_ADT_DENSEMAPINFO_H