Gabriel B. has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/67663?usp=email )

Change subject: base: Provide several hash implementation for common types
......................................................................

base: Provide several hash implementation for common types

These types include std::pair, std::tuple, all iterable types and any
composition of these. Convenience hash factory and computation
functions are also provided.

These functions are in the stl_helpers namespace and must not move to
::std which would cause undefined behaviour. This is because
specialization of std templates for std or native types (or
composition of these) is undefined behaviour. This inconvenience can't
be circumvented for generic code. Users are free to bring these hash
implementations to namespace std after specialization for their own
non-std and non-native types.

Change-Id: Ifd0f0b64e5421d5d44890eb25428cc9c53484eb3
---
M src/base/stl_helpers.hh
1 file changed, 126 insertions(+), 0 deletions(-)



diff --git a/src/base/stl_helpers.hh b/src/base/stl_helpers.hh
index d12f266..07aceb1 100644
--- a/src/base/stl_helpers.hh
+++ b/src/base/stl_helpers.hh
@@ -31,6 +31,7 @@

 #include <algorithm>
 #include <iostream>
+#include <numeric>
 #include <type_traits>
 #include <vector>

@@ -76,6 +77,110 @@
     return out;
 }

+namespace hash_impl {
+// iterable type trait
+template <typename, typename = void>
+constexpr bool is_iterable = false;
+
+template <typename T>
+constexpr bool is_iterable<T,
+    std::void_t<decltype(begin(std::declval<T>())),
+                decltype(end(std::declval<T>()))>> = true;
+
+// std::hash-enabled type trait
+template <typename, typename = void>
+constexpr bool is_std_hash_enabled = false;
+template <typename T>
+constexpr bool is_std_hash_enabled<T,
+    std::void_t<decltype(std::hash<T>())>> = true;
+
+// Hash combination function stollen from boost::hash_combine
+// Has the reputation to be a decent all-rounder.
+template<typename T, typename... U>
+size_t hash_combine(const T& h, const U&... tail) {
+    if constexpr (sizeof...(U) == 0) {
+        return h;
+    } else {
+        auto h1 = hash_combine(tail...);
+        return h ^ (h1 + 0x9e3779b9ull + (h << 6) + (h >> 2));
+    }
+}
+
+// SFINAE-enabled hash functor
+template<typename T, typename = void>
+struct hash;
+
+// Reuse std::hash whenever possible
+template<typename T>
+struct hash<T, std::enable_if_t<is_std_hash_enabled<T>>>: std::hash<T>
+{};
+
+// Enable type deduction for hash object construction
+template<typename T>
+constexpr auto make_hash_for(const T&) {
+    return hash<T>();
+}
+
+// Compute a hash without the hassle of constructing a hash functor
+template<typename T>
+constexpr auto hash_value(const T& v) {
+    return make_hash_for(v)(v);
+}
+
+// Hash for tuple
+template<typename... T>
+struct hash<std::tuple<T...>>
+{
+    constexpr size_t operator()(const std::tuple<T...>& t) const {
+        if constexpr (sizeof...(T) == 0) {
+            return 0;
+        } else {
+            return std::apply([&](const auto&... e){
+               return hash_combine(hash_value(e)...);
+            }, t);
+        }
+    }
+};
+
+// Hash for pairs (based on hash for 2-uple)
+template<typename T, typename U>
+struct hash<std::pair<T, U>>
+{
+    constexpr size_t operator()(const std::pair<T, U>& p) const {
+        return hash_value(std::tie(p.first, p.second));
+    }
+};
+
+// Hash for any iterable of stl_helpers::hash-enabled types.
+template<typename T>
+struct hash<T, std::enable_if_t<is_iterable<T>>>
+{
+    constexpr size_t operator()(const T& t) const {
+        if (begin(t) == end(t)) return 0;
+        auto b = begin(t);
+        auto e = end(t);
+        return std::accumulate(next(b), e, hash_value(*b),
+            [](const auto& acc, const auto& val) {
+                return hash_combine(acc, hash_value(val));
+            });
+    }
+};
+
+template<typename, typename = void>
+constexpr bool is_hash_enabled = false;
+
+template <typename T>
+constexpr bool is_hash_enabled<T,
+    std::void_t<decltype(hash<T>()(std::declval<T>()))>> = true;
+
+} // namespace hash_impl
+
+// Export useful hash_impl functions
+using hash_impl::hash;
+using hash_impl::make_hash_for;
+using hash_impl::hash_value;
+using hash_impl::is_hash_enabled;
+
 } // namespace stl_helpers
 } // namespace gem5


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/67663?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Ifd0f0b64e5421d5d44890eb25428cc9c53484eb3
Gerrit-Change-Number: 67663
Gerrit-PatchSet: 1
Gerrit-Owner: Gabriel B. <gabriel.bus...@arteris.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org

Reply via email to