| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // -*- mode: C++ -*- |
| // |
| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License v2.0 with LLVM Exceptions (the |
| // "License"); you may not use this file except in compliance with the |
| // License. You may obtain a copy of the License at |
| // |
| // https://llvm.org/LICENSE.txt |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Author: Giuliano Procida |
| // Author: Siddharth Nayyar |
| |
| #ifndef STG_HASHING_H_ |
| #define STG_HASHING_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <functional> |
| #include <string> |
| #include <string_view> |
| |
| namespace stg { |
| |
| struct HashValue { |
| constexpr explicit HashValue(uint32_t value) : value(value) {} |
| auto operator<=>(const HashValue&) const = default; |
| uint32_t value; |
| }; |
| |
| } // namespace stg |
| |
| namespace std { |
| |
| template <> |
| struct hash<stg::HashValue> { |
| size_t operator()(const stg::HashValue& hv) const { |
| // do not overhash |
| return hv.value; |
| } |
| }; |
| |
| } // namespace std |
| |
| namespace stg { |
| |
| struct Hash { |
| constexpr HashValue operator()(HashValue hash_value) const { |
| return hash_value; |
| } |
| |
| // Hash boolean by converting to int. |
| constexpr HashValue operator()(bool x) const { |
| return x ? (*this)(1) : (*this)(0); |
| } |
| |
| // Hash unsigned 64 bits by splitting, hashing and combining. |
| constexpr HashValue operator()(uint64_t x) const { |
| const uint32_t lo = x; |
| const uint32_t hi = x >> 32; |
| return (*this)(lo, hi); |
| } |
| |
| // Hash signed 64 bits by casting to unsigned 64 bits. |
| constexpr HashValue operator()(int64_t x) const { |
| return (*this)(static_cast<uint64_t>(x)); |
| } |
| |
| // See https://github.com/skeeto/hash-prospector. |
| constexpr HashValue operator()(uint32_t x) const { |
| x ^= x >> 16; |
| x *= 0x21f0aaad; |
| x ^= x >> 15; |
| x *= 0xd35a2d97; |
| x ^= x >> 15; |
| return HashValue(x); |
| } |
| |
| // Hash signed 32 bits by casting to unsigned 32 bits. |
| constexpr HashValue operator()(int32_t x) const { |
| return (*this)(static_cast<uint32_t>(x)); |
| } |
| |
| // Hash 8 bits by zero extending to 32 bits. |
| constexpr HashValue operator()(char x) const { |
| return (*this)(static_cast<uint32_t>(static_cast<unsigned char>(x))); |
| } |
| |
| // 32-bit FNV-1a. See https://wikipedia.org/wiki/Fowler-Noll-Vo_hash_function. |
| constexpr HashValue operator()(const std::string_view x) const { |
| uint32_t h = 0x811c9dc5; |
| for (auto ch : x) { |
| h ^= static_cast<unsigned char>(ch); |
| h *= 0x01000193; |
| } |
| return HashValue(h); |
| } |
| |
| // Hash std::string by constructing a std::string_view. |
| HashValue operator()(const std::string& x) const { |
| return (*this)(std::string_view(x)); |
| } |
| |
| // Hash C string by constructing a std::string_view. |
| constexpr HashValue operator()(const char* x) const { |
| return (*this)(std::string_view(x)); |
| } |
| |
| // Reverse order Boost hash_combine (must be used with good hashes). |
| template <typename Arg, typename... Args> |
| constexpr HashValue operator()(Arg arg, Args... args) const { |
| const uint32_t seed = (*this)(args...).value; |
| const uint32_t hash = (*this)(arg).value; |
| return HashValue(seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2))); |
| } |
| }; |
| |
| } // namespace stg |
| |
| #endif // STG_HASHING_H_ |