1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_MEMORY_VALUES_EQUIVALENT_H_ 6 #define BASE_MEMORY_VALUES_EQUIVALENT_H_ 7 8 #include <functional> 9 #include <memory> 10 #include <type_traits> 11 12 #include "base/memory/scoped_refptr.h" 13 14 namespace base { 15 16 namespace internal { 17 template <typename T> 18 concept IsPointer = std::is_pointer_v<T>; 19 } // namespace internal 20 21 // Compares two pointers for equality, returns the dereferenced value comparison 22 // if both are non-null. 23 // Behaves like std::optional<T>::operator==(const std::optional<T>&) but for 24 // pointers, with an optional predicate. 25 // If `p` is specified, `p(const T& x, const T& y)` should return whether `x` 26 // and `y` are equal. It's called with `(*a, *b)` when `a != b && a && b`. 27 template <typename T, typename Predicate = std::equal_to<>> 28 bool ValuesEquivalent(const T* a, const T* b, Predicate p = {}) { 29 if (a == b) 30 return true; 31 if (!a || !b) 32 return false; 33 return p(*a, *b); 34 } 35 36 // Specialize for smart pointers like std::unique_ptr and base::scoped_refptr 37 // that provide a T* get() method. 38 // Example usage: 39 // struct Example { 40 // std::unique_ptr<Child> child; 41 // bool operator==(const Example& other) const { 42 // return base::ValuesEquivalent(child, other.child); 43 // } 44 // }; 45 template <typename T, typename Predicate = std::equal_to<>> requires(const T & t)46 requires requires(const T& t) { 47 { t.get() } -> internal::IsPointer; 48 } 49 bool ValuesEquivalent(const T& x, const T& y, Predicate p = {}) { 50 return ValuesEquivalent(x.get(), y.get(), std::move(p)); 51 } 52 53 // Specialize for smart pointers like blink::Persistent and blink::Member that 54 // provide a T* Get() method. 55 // Example usage: 56 // namespace blink { 57 // struct Example : public GarbageCollected<Example> { 58 // Member<Child> child; 59 // bool operator==(const Example& other) const { 60 // return base::ValuesEquivalent(child, other.child); 61 // } 62 // void Trace(Visitor*) const; 63 // }; 64 // } // namespace blink 65 template <typename T, typename Predicate = std::equal_to<>> requires(const T & t)66 requires requires(const T& t) { 67 { t.Get() } -> internal::IsPointer; 68 } 69 bool ValuesEquivalent(const T& x, const T& y, Predicate p = {}) { 70 return ValuesEquivalent(x.Get(), y.Get(), std::move(p)); 71 } 72 73 } // namespace base 74 75 #endif // BASE_MEMORY_VALUES_EQUIVALENT_H_ 76