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