Last active
January 8, 2025 01:38
-
-
Save chengscott/40e5b500ba483c607c9f99f4546dcc51 to your computer and use it in GitHub Desktop.
flat_array_t and flat_tuple_t are automatically hashable type wrapper for std::array<T, N> and std::tuple<Ts...> that can be used as keys in map/unordered_map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <functional> | |
#include <iostream> | |
#include <tuple> | |
#include <unordered_map> | |
template <class T, size_t N> union flat_array_t { | |
using hash_t = std::tuple_element_t< | |
sizeof(T) - 1, | |
std::tuple<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>>; | |
hash_t hash; | |
std::array<T, N> data; | |
flat_array_t() = default; | |
flat_array_t(std::array<T, N> &&rhs) | |
: data(std::forward<std::array<T, N>>(rhs)) {} | |
template <typename... Ts, typename = std::enable_if_t<sizeof...(Ts) == N>> | |
flat_array_t(Ts &&... rhs) : data{std::forward<Ts>(rhs)...} {} | |
bool operator==(const flat_array_t &rhs) const { return hash == rhs.hash; } | |
}; | |
template <class T, size_t N> struct std::hash<flat_array_t<T, N>> { | |
std::size_t operator()(const flat_array_t<T, N> &rhs) const { | |
return std::hash<typename flat_array_t<T, N>::hash_t>{}(rhs.hash); | |
} | |
}; | |
int main() { | |
std::unordered_map<flat_array_t<uint32_t, 2>, size_t> m2; | |
m2[{1, 2}]++; | |
m2[{3, 4}]++; | |
m2[{1, 3}] = m2[{1, 2}] + m2[{3, 4}]; | |
std::cout << m2[{1, 3}] << std::endl; | |
std::cout << m2[{{3, 4}}] << std::endl; | |
std::unordered_map<flat_array_t<uint16_t, 4>, size_t> m4; | |
m4[{1, 2, 3, 4}]++; | |
m4[{5, 6, 7, 8}]++; | |
m4[{1, 2, 5, 6}] = m4[{1, 2, 3, 4}] + m4[{5, 6, 7, 8}]; | |
std::cout << m4[{1, 2, 5, 6}] << std::endl; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <functional> | |
#include <iostream> | |
#include <tuple> | |
#include <unordered_map> | |
template <typename... Ts> union flat_tuple_t { | |
using hash_t = std::tuple_element_t< | |
(0 + ... + sizeof(Ts)) - 1, | |
std::tuple<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>>; | |
hash_t hash; | |
std::tuple<Ts...> data; | |
flat_tuple_t() = default; | |
flat_tuple_t(std::tuple<Ts...> &&rhs) | |
: data{std::forward<std::tuple<Ts...>>(rhs)} {} | |
flat_tuple_t(Ts &&... rhs) : data{std::forward<Ts>(rhs)...} {} | |
bool operator==(const flat_tuple_t &rhs) const { return hash == rhs.hash; } | |
}; | |
template <typename... Ts> struct std::hash<flat_tuple_t<Ts...>> { | |
std::size_t operator()(const flat_tuple_t<Ts...> &rhs) const { | |
return std::hash<typename flat_tuple_t<Ts...>::hash_t>{}(rhs.hash); | |
} | |
}; | |
int main() { | |
std::cout << sizeof(flat_tuple_t<uint16_t, uint8_t>::hash_t) << std::endl; | |
std::unordered_map<flat_tuple_t<uint8_t, uint16_t>, size_t> m2; | |
m2[{1, 2}]++; | |
m2[{1, 2}]++; | |
m2[{3, 4}]++; | |
m2[{1, 3}] = m2[{1, 2}] + m2[{3, 4}]; | |
std::cout << m2[{1, 3}] << std::endl; | |
std::unordered_map<flat_tuple_t<uint8_t, uint8_t, uint8_t, uint8_t>, size_t> | |
m4; | |
m4[{1, 2, 3, 4}]++; | |
m4[{5, 6, 7, 8}]++; | |
m4[{1, 2, 5, 6}] = m4[{1, 2, 3, 4}] + m4[{5, 6, 7, 8}]; | |
std::cout << m4[{1, 2, 5, 6}] << std::endl; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <array> | |
#include <unordered_map> | |
union uint32x2_t { | |
using hash_t = uint64_t; | |
hash_t hash; | |
std::array<uint32_t, 2> data; | |
uint32x2_t() = default; | |
uint32x2_t(const std::array<uint32_t, 2> &rhs) : data{rhs} {} | |
bool operator==(const uint32x2_t &rhs) const { return hash == rhs.hash; } | |
}; | |
template <> struct std::hash<uint32x2_t> { | |
std::size_t operator()(const uint32x2_t &rhs) const { | |
return std::hash<uint32x2_t::hash_t>{}(rhs.hash); | |
} | |
}; | |
int main() { | |
std::unordered_map<uint32x2_t, size_t> m; | |
m[{{1, 2}}]++; | |
m[{{3, 4}}]++; | |
m[{{1, 3}}] = m[{{1, 2}}] + m[{{3, 4}}]; | |
std::cout << m[{{1, 3}}] << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment