44#include <unordered_map>
45#include <unordered_set>
49# include <string_view>
55template <
typename Integral,
typename CharT>
57 CharT (&dest)[
sizeof(Integral)])
noexcept ->
void {
58 static_assert(std::is_integral<CharT>::value and
sizeof(CharT) == 1
59 and not std::is_same<CharT, bool>::value,
60 "CharT must be a char-like type.");
61 for (
int byte = 0;
byte !=
sizeof(Integral); ++byte) {
67template <
typename Integral,
typename CharT>
69 CharT (&dest)[
sizeof(Integral)])
noexcept ->
void {
70 static_assert(std::is_integral<CharT>::value and
sizeof(CharT) == 1
71 and not std::is_same<CharT, bool>::value,
72 "CharT must be a char-like type.");
73 for (
auto byte :
range(
sizeof(Integral))) {
74 dest[(
sizeof(Integral) - 1) - byte]
75 =
static_cast<CharT
>(ival >> (CHAR_BIT * byte));
79template <
typename Integral,
typename CharT>
80constexpr auto to_bytes(Integral val, CharT (&dest)[
sizeof(Integral)])
noexcept
82 static_assert(std::is_integral<CharT>::value and
sizeof(CharT) == 1
83 and not std::is_same<CharT, bool>::value,
84 "CharT must be a char-like type.");
97 template <
typename UInt>
102 : std::integral_constant<std::uint32_t, 16777619ul> {};
105 : std::integral_constant<std::uint64_t, 1099511628211ull> {};
107 template <
typename UInt>
117 template <
typename UInt>
122 : std::integral_constant<std::uint32_t, 2166136261ul> {};
125 : std::integral_constant<std::uint64_t, 14695981039346656037ull> {};
127 template <
typename UInt>
146template <
typename HashInt,
typename Span>
151 static_assert(
sizeof(*std::begin(s)) == 1,
152 "Can only hash char-like objects.");
155 hval ^=
static_cast<HashInt
>(
static_cast<unsigned char>(c));
172template <
typename HashInt,
typename CharT, std::
size_t N>
176 static_assert(
sizeof(s[0]) == 1,
"Can only hash char-like objects.");
179 hval ^=
static_cast<HashInt
>(
static_cast<unsigned char>(c));
200 hval ^=
static_cast<std::uint32_t
>(
static_cast<unsigned char>(c));
207template <
typename HashInt>
209 const char* begin, std::size_t
length,
216 for (
const char* pos :
range(begin, begin +
length)) {
217 hval ^=
static_cast<HashInt
>(
static_cast<unsigned char>(*pos));
232template <std::
size_t N>
239 hval ^=
static_cast<std::uint32_t
>(
static_cast<unsigned char>(c));
246 const char* begin, std::size_t
length,
250 for (
const char* pos = begin; pos != begin +
length; ++pos) {
251 hval ^=
static_cast<std::uint32_t
>(
static_cast<unsigned char>(*pos));
257inline namespace literals {
262 std::size_t
length)
noexcept
264 return FNVa_s<std::uint32_t>(str,
length);
271 std::size_t
length)
noexcept
273 return FNVa_s<std::uint64_t>(str,
length);
279 unsigned char bytes[
sizeof(
unsigned long long)]{};
281 return FNVa_a<std::uint32_t>(bytes);
286 unsigned char bytes[
sizeof(
unsigned long long)]{};
288 return FNVa_a<std::uint64_t>(bytes);
301 = CHAR_BIT *
sizeof(T) - std::numeric_limits<T>::digits
302 - std::numeric_limits<T>::is_signed;
308struct padding_bits : std::integral_constant<int, padding_bits_v<T>> {};
317 : std::integral_constant<int, CHAR_BIT * sizeof(T)
318 - std::numeric_limits<T>::digits
319 - std::numeric_limits<T>::is_signed> {};
321struct padding_bits<void> : std::integral_constant<int, 0> {};
333template <
typename Key =
void,
typename HashInt = std::
size_t,
typename =
void>
342template <
typename Key,
typename =
void>
345template <
typename Key>
349template <
typename Key>
352template <
typename Key>
359template <
typename HashInt>
362 bool key, HashInt offset
365 return FNVa_a(tmp, offset);
373template <
typename HashInt>
376 char key, HashInt offset
379 return FNVa_a(tmp, offset);
387template <
typename HashInt>
393 signed char tmp[1] = {key};
394 return FNVa_a(tmp, offset);
402template <
typename HashInt>
408 unsigned char tmp[1] = {key};
409 return FNVa_a(tmp, offset);
416template <
typename T,
typename HashInt>
419 const T&, HashInt offset
421 return FNVa_a(
"", offset);
425#if __cpp_lib_has_unique_object_representations
428 = (std::is_trivially_copyable_v<
429 T> and std::has_unique_object_representations_v<T>);
434 or std::is_pointer<T>::value or std::is_member_object_pointer<T>::value
435 or std::is_member_function_pointer<T>::value;
445template <
typename T,
typename HashInt>
452 unsigned char tmp[
sizeof(T)]{};
454 return FNVa_a(tmp, offset);
465template <
typename T,
typename HashInt>
468 T key_in, HashInt offset
471 reinterpret_cast<std::uintptr_t
>(key_in), offset);
481template <
typename T,
typename HashInt>
484 typename std::iterator_traits<
485 T>::iterator_category>::value and
486 not std::is_pointer<T>::value and
488 std::is_pointer<typename fakestd::invoke_result<
489 decltype(&T::operator->), T>::type>::value)>> {
491 T key_in, HashInt offset
498 reinterpret_cast<std::uintptr_t
>(
to_pointer(key_in)), offset);
508 template <
typename Container>
511 and is_trivially_hashable_v<typename Container::value_type>);
512 static_assert(is_trivial_container<std::string>,
513 "kblib bug: std::string should be trivially hashable");
521template <
typename Container,
typename HashInt>
529 HashInt offset)
const noexcept -> HashInt {
530 return FNVa_s<HashInt>(
reinterpret_cast<const char*
>(key.data()),
531 key.size() *
sizeof(*key.begin()), offset);
535 const Container& key,
539 if (std::is_constant_evaluated()) {
540 using T =
typename Container::value_type;
541 for (
const auto&
e : key) {
545 return hash_fast(key, offset);
548 return hash_fast(key, offset);
561template <
typename T,
typename HashInt>
565 and not std::is_pointer<T>::value
568 T key, HashInt offset = fnv::fnv_offset<HashInt>::value) const noexcept
571 auto tmp = std::bit_cast<std::array<char,
sizeof(T)>>(key);
572 return FNVa_s(tmp.data(), tmp.size(), offset);
575 std::memcpy(tmp, &key,
sizeof(T));
576 return FNVa_a(tmp, offset);
585template <
typename Container,
typename HashInt>
591 value_detected_t<Container>> and not
hash_detected<Container>::value
593 and not (is_contiguous<Container>::value
594 and is_trivially_hashable_v<typename Container::value_type>)
597 const Container& key,
600 using Elem =
typename Container::value_type;
602 [](HashInt offset_,
const Elem& elem) {
622 template <
typename Tuple,
typename HashInt, std::
size_t I>
624 std::index_sequence<I>)
noexcept -> HashInt {
626 std::get<I>(tuple), offset);
637 template <
typename Tuple,
typename HashInt, std::size_t I, std::size_t I2,
640 std::index_sequence<I, I2, Is...>)
noexcept
644 std::get<I>(tuple), offset);
646 std::index_sequence<I2, Is...>{});
650 template <
typename Tuple, std::size_t... Is>
653 and
is_hashable_v<
typename std::tuple_element<Is, Tuple>::type>);
657 template <
typename Tuple,
typename IS>
658 struct all_hashable_impl_t;
660 template <
typename Tuple, std::size_t I, std::size_t... Is>
661 struct all_hashable_impl_t<Tuple,
std::index_sequence<I, Is...>>
664 typename std::tuple_element<I, Tuple>::
665 type> and all_hashable_impl_t<Tuple, std::index_sequence<Is...>>::value)> {
668 template <
typename Tuple, std::
size_t I>
669 struct all_hashable_impl_t<Tuple,
std::index_sequence<I>>
671 is_hashable_v<typename std::tuple_element<I, Tuple>::type>> {};
673 template <
typename Tuple, std::size_t... Is>
675 return all_hashable_impl_t<Tuple, std::index_sequence<Is...>>::value;
681 typename std::enable_if<(std::tuple_size<Tuple>::value > 0u),
int>::type
684 return all_hashable_impl<Tuple>(
685 std::make_index_sequence<std::tuple_size<Tuple>::value>{});
694template <
typename Tuple,
typename HashInt>
698 Tuple> and (
std::tuple_size<Tuple>::value > 0u)
699 and not is_linear_container_v<Tuple>>> {
706 std::make_index_sequence<std::tuple_size<Tuple>::value>{});
712template <
typename T,
typename HashInt>
715 const std::optional<T>& key,
726template <
typename... Ts,
typename HashInt>
728 void_if_t<detail_hash::all_hashable<std::tuple<Ts...>>()>> {
730 const std::variant<Ts...>& key,
737 offset =
FNV_hash<
typename std::remove_reference<
decltype(V)>::type,
738 HashInt>{}(V, offset);
750template <
typename HashInt>
754 template <
typename T>
763template <
typename Key,
typename Value>
764using hash_map = std::unordered_map<Key, Value, FNV_hash<>, std::equal_to<>>;
765template <
typename Key,
typename Value>
767 = std::unordered_multimap<Key, Value, FNV_hash<>, std::equal_to<>>;
768template <
typename T,
typename HashInt>
769using hash_set = std::unordered_set<T, FNV_hash<>, std::equal_to<>>;
770template <
typename T,
typename HashInt>
This file provides some iterators, ranges, iterator/range adapters, and operations that can be perfor...
KBLIB_CONSTANT_V is_trivial_container
constexpr auto all_hashable_impl(std::index_sequence< Is... >) -> bool
constexpr auto all_hashable() -> bool
constexpr auto hash_tuple_impl(const Tuple &tuple, HashInt offset, std::index_sequence< I, I2, Is... >) noexcept -> HashInt
Hash each element of a tuple. This overload is for tuples of at least 2 elements.
KBLIB_CONSTANT_V is_hashable_v
KBLIB_CONSTANT_V is_trivially_hashable_v
constexpr auto to_pointer(P &&p) noexcept -> auto *
Gets a raw pointer out of any smart pointer or iterator you might pass in, without dereferencing it o...
std::unordered_multimap< Key, Value, FNV_hash<>, std::equal_to<> > hash_multimap
typename std::enable_if< B, T >::type enable_if_t
constexpr auto to_bytes(Integral val, CharT(&dest)[sizeof(Integral)]) noexcept -> void
constexpr auto FNV32a_s(const char *begin, std::size_t length, uint32_t hval=fnv::fnv_offset< std::uint32_t >::value) noexcept -> std::uint32_t
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
constexpr auto FNVa(Span &&s, HashInt hval=fnv::fnv_offset< HashInt >::value) noexcept -> HashInt
A templatized generic FNVa hash function.
constexpr auto visit2_nop(V &&v, F &&f, Fs &&... fs) -> void
KBLIB_CONSTANT_V is_iterator_v
constexpr auto length(const CharT *str) noexcept -> std::size_t
constexpr auto FNV32a_a(const char(&s)[N], std::uint32_t hval=fnv::fnv_offset< std::uint32_t >::value) noexcept -> std::uint32_t
A standard FNV32a hash function, for raw character arrays, such as string literals.
constexpr int padding_bits_v< void >
constexpr int padding_bits_v
Get the number of padding bits in an integral type.
constexpr auto FNV32a(std::string_view s, std::uint32_t hval=fnv::fnv_offset< std::uint32_t >::value) noexcept -> std::uint32_t
A standard FNV32a hash function, for string_views.
std::unordered_set< T, FNV_hash<>, std::equal_to<> > hash_multiset
std::integral_constant< bool, v > bool_constant
typename void_if< b >::type void_if_t
constexpr auto FNVa_s(const char *begin, std::size_t length, HashInt hval=fnv::fnv_offset< HashInt >::value) noexcept -> HashInt
std::unordered_set< T, FNV_hash<>, std::equal_to<> > hash_set
constexpr auto to_bytes_be(Integral ival, CharT(&dest)[sizeof(Integral)]) noexcept -> void
constexpr auto accumulate(InputIt first, InputIt last, T init) -> T
A constexpr version of std::accumulate.
constexpr auto to_bytes_le(Integral ival, CharT(&dest)[sizeof(Integral)]) noexcept -> void
constexpr auto FNVa_a(const CharT(&s)[N], HashInt hval=fnv::fnv_offset< HashInt >::value) noexcept -> HashInt
A templatized FNVa hash function, for raw character arrays, such as string literals.
KBLIB_CONSTANT_V is_contiguous_v
Type trait to determine if a container is contiguous.
constexpr endian hash_order
std::unordered_map< Key, Value, FNV_hash<>, std::equal_to<> > hash_map
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
constexpr auto operator()(const Container &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(const Container &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
auto hash_fast(const Container &key, HashInt offset) const noexcept -> HashInt
constexpr auto operator()(const T &, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(T key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
auto operator()(T key_in, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
auto operator()(T key_in, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(const Tuple &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(bool key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(char key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(signed char key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(const std::optional< T > &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(const std::variant< Ts... > &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(unsigned char key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> HashInt
constexpr auto operator()(const T &key, HashInt offset=fnv::fnv_offset< HashInt >::value) const noexcept -> enable_if_t< is_hashable_v< T >, HashInt >
The primary template has to exist, but not be constructible, in order to be compatible with std::hash...
FNV_hash(FNV_hash &&)=delete
FNV_hash(const FNV_hash &)=delete
FNV_hash & operator=(const FNV_hash &)=delete
FNV_hash & operator=(FNV_hash &&)=delete
The starting value for the FNVa hash algorithm, as a type trait.
The prime to use for the FNVa hash algorithm, as a type trait.
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
#define KBLIB_CXX20(args)
This internal macro is used to selectively use C++20 features.
#define KBLIB_CONSTANT_MV
Contains some type traits not in the standard library that are useful in the implementation of kblib.
Provides utilities for working with std::variant more expressively and more efficiently.