// // ASEqualityHashHelpers.h // AsyncDisplayKit // // Copyright (c) 2014-present, Facebook, Inc. All rights reserved. // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // #import #import // From folly: // This is the Hash128to64 function from Google's cityhash (available // under the MIT License). We use it to reduce multiple 64 bit hashes // into a single hash. inline uint64_t ASHashCombine(const uint64_t upper, const uint64_t lower) { // Murmur-inspired hashing. const uint64_t kMul = 0x9ddfea08eb382d69ULL; uint64_t a = (lower ^ upper) * kMul; a ^= (a >> 47); uint64_t b = (upper ^ a) * kMul; b ^= (b >> 47); b *= kMul; return b; } #if __LP64__ inline size_t ASHash64ToNative(uint64_t key) { return key; } #else // Thomas Wang downscaling hash function inline size_t ASHash64ToNative(uint64_t key) { key = (~key) + (key << 18); key = key ^ (key >> 31); key = key * 21; key = key ^ (key >> 11); key = key + (key << 6); key = key ^ (key >> 22); return (uint32_t) key; } #endif NSUInteger ASIntegerArrayHash(const NSUInteger *subhashes, NSUInteger count); namespace AS { // Default is not an ObjC class template struct is_objc_class : std::false_type { }; // Conditionally enable this template specialization on whether T is convertible to id, makes the is_objc_class a true_type template struct is_objc_class::value, bool>::type> : std::true_type { }; // ASUtils::hash()(value) -> either std::hash if c++ or [o hash] if ObjC object. template struct hash; // For non-objc types, defer to std::hash template struct hash::value>::type> { size_t operator ()(const T& a) { return std::hash()(a); } }; // For objc types, call [o hash] template struct hash::value>::type> { size_t operator ()(id o) { return [o hash]; } }; template struct is_equal; // For non-objc types use == operator template struct is_equal::value>::type> { bool operator ()(const T& a, const T& b) { return a == b; } }; // For objc types, check pointer equality, then use -isEqual: template struct is_equal::value>::type> { bool operator ()(id a, id b) { return a == b || [a isEqual:b]; } }; }; namespace ASTupleOperations { // Recursive case (hash up to Index) template ::value - 1> struct _hash_helper { static size_t hash(Tuple const& tuple) { size_t prev = _hash_helper::hash(tuple); using TypeForIndex = typename std::tuple_element::type; size_t thisHash = AS::hash()(std::get(tuple)); return ASHashCombine(prev, thisHash); } }; // Base case (hash 0th element) template struct _hash_helper { static size_t hash(Tuple const& tuple) { using TypeForIndex = typename std::tuple_element<0,Tuple>::type; return AS::hash()(std::get<0>(tuple)); } }; // Recursive case (elements equal up to Index) template ::value - 1> struct _eq_helper { static bool equal(Tuple const& a, Tuple const& b) { bool prev = _eq_helper::equal(a, b); using TypeForIndex = typename std::tuple_element::type; auto aValue = std::get(a); auto bValue = std::get(b); return prev && AS::is_equal()(aValue, bValue); } }; // Base case (0th elements equal) template struct _eq_helper { static bool equal(Tuple const& a, Tuple const& b) { using TypeForIndex = typename std::tuple_element<0,Tuple>::type; auto& aValue = std::get<0>(a); auto& bValue = std::get<0>(b); return AS::is_equal()(aValue, bValue); } }; template struct hash; template struct hash> { size_t operator()(std::tuple const& tt) const { return _hash_helper>::hash(tt); } }; template struct equal_to; template struct equal_to> { bool operator()(std::tuple const& a, std::tuple const& b) const { return _eq_helper>::equal(a, b); } }; }