hash: Add support for arrays
There is now builtin support for stdplus::hash<> and
stdplus::hashMulti(...) hashing std::array<> and C array containers.
Change-Id: I111511fcd2c1627011b47cf3593cc9d63d752c1a
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/meson.build b/include/meson.build
index fc304f3..5785caf 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -7,6 +7,7 @@
'stdplus/handle/copyable.hpp',
'stdplus/handle/managed.hpp',
'stdplus/hash.hpp',
+ 'stdplus/hash/array.hpp',
'stdplus/hash/tuple.hpp',
'stdplus/pinned.hpp',
'stdplus/raw.hpp',
diff --git a/include/stdplus/hash.hpp b/include/stdplus/hash.hpp
index f3aa8e6..5c521fa 100644
--- a/include/stdplus/hash.hpp
+++ b/include/stdplus/hash.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include <array>
#include <cstddef>
#include <tuple>
#include <utility>
@@ -62,10 +63,63 @@
return detail::hashMultiS(hashMulti(t), ts...);
}
+namespace detail
+{
+
+template <typename T>
+constexpr std::size_t
+ hashArr(std::size_t seed, const T* ts,
+ std::size_t n) noexcept(noexcept(hashMulti(std::declval<T>())))
+{
+ if (n == 1)
+ {
+ return updateSeed(seed, hashMulti(*ts));
+ }
+ return hashArr(updateSeed(seed, hashMulti(*ts)), ts + 1, n - 1);
+}
+
+template <typename T>
+constexpr std::size_t
+ hashArr(const T* ts,
+ std::size_t n) noexcept(noexcept(hashMulti(std::declval<T>())))
+{
+ if (n == 0)
+ {
+ return 0;
+ }
+ if (n == 1)
+ {
+ return hashMulti(*ts);
+ }
+ return hashArr(hashMulti(*ts), ts + 1, n - 1);
+}
+
+} // namespace detail
+
template <class Key>
struct hash : std::hash<Key>
{};
+template <typename T, std::size_t N>
+struct hash<std::array<T, N>>
+{
+ constexpr std::size_t operator()(const std::array<T, N>& a) noexcept(
+ noexcept(hashMulti(std::declval<T>())))
+ {
+ return detail::hashArr(a.data(), N);
+ }
+};
+
+template <typename T, std::size_t N>
+struct hash<T[N]>
+{
+ constexpr std::size_t operator()(const T (&a)[N]) noexcept(
+ noexcept(hashMulti(std::declval<T>())))
+ {
+ return detail::hashArr(a, N);
+ }
+};
+
template <typename... Ts>
struct hash<std::tuple<Ts...>>
{
diff --git a/include/stdplus/hash/array.hpp b/include/stdplus/hash/array.hpp
new file mode 100644
index 0000000..358c1a3
--- /dev/null
+++ b/include/stdplus/hash/array.hpp
@@ -0,0 +1,24 @@
+#pragma once
+#include <stdplus/hash.hpp>
+
+#include <array>
+
+template <typename T, std::size_t N>
+struct std::hash<std::array<T, N>>
+{
+ constexpr auto operator()(const std::array<T, N>& ts) const
+ noexcept(noexcept(stdplus::hashMulti(std::declval<std::array<T, N>>())))
+ {
+ return stdplus::hashMulti(ts);
+ }
+};
+
+template <typename T, std::size_t N>
+struct std::hash<T[N]>
+{
+ constexpr auto operator()(const T (&ts)[N]) const
+ noexcept(noexcept(stdplus::hashMulti(std::declval<T[N]>())))
+ {
+ return stdplus::hashMulti(ts);
+ }
+};
diff --git a/src/hash/array.cpp b/src/hash/array.cpp
new file mode 100644
index 0000000..d736797
--- /dev/null
+++ b/src/hash/array.cpp
@@ -0,0 +1 @@
+#include <stdplus/hash/array.hpp>
diff --git a/src/meson.build b/src/meson.build
index ed994ea..b367dc4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -48,6 +48,7 @@
'handle/copyable.cpp',
'handle/managed.cpp',
'hash.cpp',
+ 'hash/array.cpp',
'hash/tuple.cpp',
'pinned.cpp',
'raw.cpp',
diff --git a/test/hash.cpp b/test/hash.cpp
index d9bcd48..a49f1b4 100644
--- a/test/hash.cpp
+++ b/test/hash.cpp
@@ -1,5 +1,6 @@
#include <stdplus/hash.hpp>
+#include <array>
#include <string>
#include <tuple>
@@ -12,8 +13,10 @@
{
EXPECT_EQ(0, hashMulti());
EXPECT_EQ(2654435834, hashMulti(1, 2));
+ int s[4] = {1, 2, 3, 4};
+ std::array<uint16_t, 2> a = {3, 4};
std::tuple<std::string, int> t = {"s", 8};
- hashMulti(1, std::string("bacon"), nullptr, t);
+ hashMulti(1, std::string("bacon"), nullptr, s, a, t);
}
} // namespace stdplus
diff --git a/test/hash/array.cpp b/test/hash/array.cpp
new file mode 100644
index 0000000..73d2892
--- /dev/null
+++ b/test/hash/array.cpp
@@ -0,0 +1,14 @@
+#include <stdplus/hash/array.hpp>
+
+#include <gtest/gtest.h>
+
+namespace stdplus
+{
+
+TEST(HashTuple, Basic)
+{
+ std::array<std::string, 2> a{"bacon", "sound"};
+ std::hash<decltype(a)>{}(a);
+}
+
+} // namespace stdplus
diff --git a/test/meson.build b/test/meson.build
index ab788ff..1e15a0e 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -4,6 +4,7 @@
'handle/copyable': [stdplus_dep, gtest_main_dep],
'handle/managed': [stdplus_dep, gtest_main_dep],
'hash': [stdplus_dep, gtest_main_dep],
+ 'hash/array': [stdplus_dep, gtest_main_dep],
'hash/tuple': [stdplus_dep, gtest_main_dep],
'pinned': [stdplus_dep, gtest_main_dep],
'raw': [stdplus_dep, gmock_dep, gtest_main_dep],