Index: mojo/public/cpp/bindings/lib/clone_equals_util.h |
diff --git a/mojo/public/cpp/bindings/lib/clone_equals_util.h b/mojo/public/cpp/bindings/lib/clone_equals_util.h |
index f7bd898c3001c4e8e086d4e8408411061ad9248b..45fe94c953dc1329eccc76103e37d2fe7d9e3e7d 100644 |
--- a/mojo/public/cpp/bindings/lib/clone_equals_util.h |
+++ b/mojo/public/cpp/bindings/lib/clone_equals_util.h |
@@ -5,6 +5,7 @@ |
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_ |
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_ |
+#include <functional> |
#include <type_traits> |
#include <unordered_map> |
#include <vector> |
@@ -155,6 +156,76 @@ bool Equals(const T& a, const T& b) { |
return EqualsTraits<T>::Equals(a, b); |
} |
+template <typename T> |
+size_t HashCombine(size_t seed, const T& value) { |
yzshen1
2016/09/20 23:44:39
Does it make sense to move hash-related functions
tibell
2016/09/21 07:10:53
Done.
|
+ // Based on proposal in: |
+ // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf |
+ return seed ^ (std::hash<T>()(value) + (seed << 6) + (seed >> 2)); |
+} |
+ |
+template <typename T> |
+struct HasHashMethod { |
+ template <typename U> |
+ static char Test(decltype(&U::Hash)); |
+ template <typename U> |
+ static int Test(...); |
+ static const bool value = sizeof(Test<T>(0)) == sizeof(char); |
+ |
+ private: |
+ EnsureTypeIsComplete<T> check_t_; |
+}; |
+ |
+template <typename T, bool has_hash_method = HasHashMethod<T>::value> |
+struct HashTraits; |
+ |
+template <typename T> |
+size_t Hash(size_t seed, const T& value); |
+ |
+template <typename T> |
+struct HashTraits<T, true> { |
+ static size_t Hash(size_t seed, const T& value) { return value.Hash(seed); } |
+}; |
+ |
+template <typename T> |
+struct HashTraits<T, false> { |
+ static size_t Hash(size_t seed, const T& value) { |
+ return HashCombine(seed, value); |
+ } |
+}; |
+ |
+template <typename T> |
+struct HashTraits<base::Optional<T>, false> { |
Sam McNally
2016/09/21 04:57:58
If we're still disallowing nullable structs, array
tibell
2016/09/21 07:10:53
Done. Deleted.
|
+ static size_t Hash(size_t seed, const base::Optional<T>& value) { |
+ return !value ? HashCombine(seed, 0) : internal::Hash(seed, *value); |
yzshen1
2016/09/20 23:44:39
nit: is "internal::" necessary here?
tibell
2016/09/21 07:10:53
Done.
|
+ } |
+}; |
+ |
+template <typename T> |
+struct HashTraits<std::vector<T>, false> { |
+ static size_t Hash(size_t seed, const std::vector<T>& value) { |
+ for (const auto& element : value) { |
+ seed = Hash(seed, element); |
+ } |
+ return seed; |
+ } |
+}; |
+ |
+template <typename K, typename V> |
+struct HashTraits<std::unordered_map<K, V>, false> { |
+ static size_t Hash(size_t seed, const std::unordered_map<K, V>& value) { |
+ for (const auto& element : value) { |
+ seed = Hash(seed, element.first); |
+ seed = Hash(seed, element.second); |
+ } |
+ return seed; |
+ } |
+}; |
+ |
+template <typename T> |
+size_t Hash(size_t seed, const T& value) { |
+ return HashTraits<T>::Hash(seed, value); |
+} |
+ |
} // namespace internal |
} // namespace mojo |