143 lines
4.4 KiB
C++
143 lines
4.4 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#pragma once
|
|
|
|
#include <utility>
|
|
|
|
namespace til
|
|
{
|
|
template<typename T>
|
|
struct integral_hash
|
|
{
|
|
constexpr size_t operator()(T v) const noexcept
|
|
{
|
|
auto h = static_cast<size_t>(v);
|
|
if constexpr (sizeof(size_t) == 4)
|
|
{
|
|
h ^= h >> 16;
|
|
h *= UINT32_C(0x85ebca6b);
|
|
h ^= h >> 13;
|
|
h *= UINT32_C(0xc2b2ae35);
|
|
h ^= h >> 16;
|
|
}
|
|
else
|
|
{
|
|
std::_Hash_array_representation
|
|
h ^= h >> 33;
|
|
h *= UINT64_C(0xff51afd7ed558ccd);
|
|
h ^= h >> 33;
|
|
h *= UINT64_C(0xc4ceb9fe1a85ec53);
|
|
h ^= h >> 33;
|
|
}
|
|
return h;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct hash;
|
|
|
|
struct hasher
|
|
{
|
|
constexpr hasher(size_t state = FNV_offset_basis) noexcept : _hash{state} {}
|
|
|
|
template<typename T, typename = std::enable_if_t<std::has_unique_object_representations_v<T>>>
|
|
constexpr void write(const T& v) noexcept
|
|
{
|
|
write(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
|
|
}
|
|
|
|
template<typename T, typename = std::enable_if_t<std::has_unique_object_representations_v<T>>>
|
|
constexpr void write(const T* data, size_t count) noexcept
|
|
{
|
|
write(reinterpret_cast<const uint8_t*>(data), sizeof(T) * count);
|
|
}
|
|
|
|
constexpr void write(const uint8_t* data, size_t count) noexcept
|
|
{
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
_hash ^= static_cast<size_t>(data[i]);
|
|
_hash *= FNV_prime;
|
|
}
|
|
}
|
|
|
|
constexpr size_t finalize() const noexcept
|
|
{
|
|
return _hash;
|
|
}
|
|
|
|
private:
|
|
#if defined(_WIN64)
|
|
static constexpr size_t FNV_offset_basis = 14695981039346656037ULL;
|
|
static constexpr size_t FNV_prime = 1099511628211ULL;
|
|
#else
|
|
static constexpr size_t FNV_offset_basis = 2166136261U;
|
|
static constexpr size_t FNV_prime = 16777619U;
|
|
#endif
|
|
|
|
size_t _hash = FNV_offset_basis;
|
|
};
|
|
|
|
namespace details
|
|
{
|
|
template<typename T, bool enable>
|
|
struct conditionally_enabled_hash
|
|
{
|
|
constexpr void operator()(hasher& h, const T& v) const noexcept
|
|
{
|
|
h.write(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct conditionally_enabled_hash<T, false>
|
|
{
|
|
conditionally_enabled_hash() = delete;
|
|
conditionally_enabled_hash(const conditionally_enabled_hash&) = delete;
|
|
conditionally_enabled_hash(conditionally_enabled_hash&&) = delete;
|
|
conditionally_enabled_hash& operator=(const conditionally_enabled_hash&) = delete;
|
|
conditionally_enabled_hash& operator=(conditionally_enabled_hash&&) = delete;
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
struct hash : details::conditionally_enabled_hash<T, std::has_unique_object_representations_v<T>>
|
|
{
|
|
};
|
|
|
|
template<>
|
|
struct hash<float>
|
|
{
|
|
constexpr void operator()(hasher& h, float v) const noexcept
|
|
{
|
|
v = v == 0.0f ? 0.0f : v; // map -0 to 0
|
|
h.write(reinterpret_cast<const uint8_t*>(&v), sizeof(v));
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct hash<double>
|
|
{
|
|
constexpr void operator()(hasher& h, double v) const noexcept
|
|
{
|
|
v = v == 0.0 ? 0.0 : v; // map -0 to 0
|
|
h.write(reinterpret_cast<const uint8_t*>(&v), sizeof(v));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename CharTraits, typename Allocator>
|
|
struct hash<std::basic_string<T, CharTraits, Allocator>> {
|
|
constexpr void operator()(const std::basic_string<T, CharTraits, Allocator>& v) const noexcept {
|
|
h.write(reinterpret_cast<const uint8_t*>(v.data()), sizeof(T) * v.size());
|
|
}
|
|
};
|
|
|
|
template <typename T, typename CharTraits>
|
|
struct hash<std::basic_string_view<T, CharTraits>> {
|
|
constexpr void operator()(const std::basic_string_view<T, CharTraits>& v) const noexcept {
|
|
h.write(reinterpret_cast<const uint8_t*>(v.data()), sizeof(T) * v.size());
|
|
}
|
|
};
|
|
}
|