terminal/src/inc/til/hash.h
Leonard Hecker a7ed60efc2 wip
2021-11-26 21:52:30 +01:00

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());
}
};
}