diff options
author | Rich Gowman <rgowman@google.com> | 2018-06-12 10:27:17 -0400 |
---|---|---|
committer | Rich Gowman <rgowman@google.com> | 2018-06-12 10:27:17 -0400 |
commit | cf2899a085f7ceca3fad2d1fb5336be25cecd7ff (patch) | |
tree | 38c835a29fcda279c8dd220781d2b5c726da307f /Firestore/core/src/firebase/firestore/util/hashing.h | |
parent | 1597765af8c897ab73d21d6d404f8eeede7890b1 (diff) | |
parent | 9307f4893008f7d6cf9473e906d4c896546c5c8c (diff) |
Merge remote-tracking branch 'origin/master' into rsgowman/protobuf_cpp
Also "fixed" BadFieldValueTagWithOtherValidTagsPresent test by changing
'false' to 'true'. Details: Depending on the version of nanopb, nanopb
would explicitly encode 'false', which shouldn't be done in proto3. When
it's explicitly encoded, the test worked properly. But when it was
(properly) dropped, the invalid tag is the only field that's actually
encoded, thus violating the assumptions of the test, leading to a test
failure. s/false/true fixes it, as now the boolean_value field is
(properly) encoded regardless of version.
Diffstat (limited to 'Firestore/core/src/firebase/firestore/util/hashing.h')
-rw-r--r-- | Firestore/core/src/firebase/firestore/util/hashing.h | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/Firestore/core/src/firebase/firestore/util/hashing.h b/Firestore/core/src/firebase/firestore/util/hashing.h index d8058c8..21c0bd6 100644 --- a/Firestore/core/src/firebase/firestore/util/hashing.h +++ b/Firestore/core/src/firebase/firestore/util/hashing.h @@ -18,6 +18,7 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HASHING_H_ #include <iterator> +#include <string> #include <type_traits> namespace firebase { @@ -49,6 +50,41 @@ namespace util { namespace impl { /** + * A type trait that identifies whether or not std::hash is available for a + * given type. + * + * This type should not be necessary since specialization failure on an + * expression like `decltype(std::hash<K>{}(value)` should be enough to disable + * overloads that require `std::hash` to be defined but unfortunately some + * standard libraries ship with std::hash defined for all types that only + * fail later (e.g. via static_assert). One such implementation is the libc++ + * that ships with Xcode 8.3.3, which is a supported platform. + */ +template <typename T> +struct has_std_hash { + // There may be other types for which std::hash is defined but they don't + // matter for our purposes. + enum { + value = std::is_arithmetic<T>{} || std::is_pointer<T>{} || + std::is_same<T, std::string>{} + }; + + constexpr operator bool() const { + return value; + } +}; + +/** + * A type that's equivalent to size_t if std::hash<T> is defined or a compile + * error otherwise. + * + * This is effectively just a safe implementation of + * `decltype(std::hash<T>{}(std::declval<T>()))`. + */ +template <typename T> +using std_hash_type = typename std::enable_if<has_std_hash<T>{}, size_t>::type; + +/** * Combines a hash_value with whatever accumulated state there is so far. */ inline size_t Combine(size_t state, size_t hash_value) { @@ -100,8 +136,7 @@ auto RankedInvokeHash(const K& value, HashChoice<0>) -> decltype(value.Hash()) { * @return The result of `std::hash<K>{}(value)` */ template <typename K> -auto RankedInvokeHash(const K& value, HashChoice<1>) - -> decltype(std::hash<K>{}(value)) { +std_hash_type<K> RankedInvokeHash(const K& value, HashChoice<1>) { return std::hash<K>{}(value); } |