#ifndef hash_hh_INCLUDED #define hash_hh_INCLUDED #include #include #include #include namespace Kakoune { inline size_t fnv1a(const char* data, size_t len) { constexpr uint32_t FNV_prime_32 = 16777619; constexpr uint32_t offset_basis_32 = 2166136261; uint32_t hash_value = offset_basis_32; for (size_t i = 0; i < len; ++i) hash_value = (hash_value ^ data[i]) * FNV_prime_32; return hash_value; } size_t murmur3(const char* input, size_t len); template requires std::is_integral_v constexpr size_t hash_value(const Type& val) { return (size_t)val; } template requires std::is_enum_v constexpr size_t hash_value(const Type& val) { return hash_value((std::underlying_type_t)val); } template constexpr size_t hash_values(Type&& t) { return hash_value(std::forward(t)); } constexpr size_t combine_hash(size_t lhs, size_t rhs) { return lhs ^ (rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2)); } template constexpr size_t hash_values(Type&& t, RemainingTypes&&... rt) { size_t seed = hash_values(std::forward(rt)...); return combine_hash(seed, hash_value(std::forward(t))); } template constexpr size_t hash_value(const std::pair& val) { return hash_values(val.first, val.second); } template struct Hash { constexpr size_t operator()(const Type& val) const { return hash_value(val); } }; // Traits specifying if two types have compatible hashing, that is, // if lhs == rhs => hash_value(lhs) == hash_value(rhs) template struct HashCompatible : std::false_type {}; template struct HashCompatible : std::true_type {}; template constexpr bool IsHashCompatible = HashCompatible::value; } #endif // hash_hh_INCLUDED