aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/util/hashing.h
diff options
context:
space:
mode:
authorGravatar Rich Gowman <rgowman@google.com>2018-06-12 10:27:17 -0400
committerGravatar Rich Gowman <rgowman@google.com>2018-06-12 10:27:17 -0400
commitcf2899a085f7ceca3fad2d1fb5336be25cecd7ff (patch)
tree38c835a29fcda279c8dd220781d2b5c726da307f /Firestore/core/src/firebase/firestore/util/hashing.h
parent1597765af8c897ab73d21d6d404f8eeede7890b1 (diff)
parent9307f4893008f7d6cf9473e906d4c896546c5c8c (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.h39
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);
}