1 /* 2 * Copyright 2022 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 #ifndef RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ 11 #define RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ 12 13 #include <memory> 14 #include <utility> 15 16 #include "rtc_base/checks.h" 17 18 namespace webrtc { 19 20 // This template allows the instantiation of a pointer to Interface in such a 21 // way that if it is passed a null pointer, an object of class Default will be 22 // created, which will be deallocated when the pointer is deleted. 23 template <typename Interface, typename Default = Interface> 24 class AlwaysValidPointer { 25 public: AlwaysValidPointer(Interface * pointer)26 explicit AlwaysValidPointer(Interface* pointer) 27 : owned_instance_(pointer ? nullptr : std::make_unique<Default>()), 28 pointer_(pointer ? pointer : owned_instance_.get()) { 29 RTC_DCHECK(pointer_); 30 } 31 32 template <typename Arg, 33 typename std::enable_if<!(std::is_invocable<Arg>::value), 34 bool>::type = true> AlwaysValidPointer(Interface * pointer,Arg arg)35 AlwaysValidPointer(Interface* pointer, Arg arg) 36 : owned_instance_(pointer ? nullptr 37 : std::make_unique<Default>(std::move(arg))), 38 pointer_(pointer ? pointer : owned_instance_.get()) { 39 RTC_DCHECK(pointer_); 40 } 41 42 // Multiple arguments 43 template <typename Arg1, typename... Args> AlwaysValidPointer(Interface * pointer,Arg1 arg1,Args...args)44 AlwaysValidPointer(Interface* pointer, Arg1 arg1, Args... args) 45 : owned_instance_(pointer 46 ? nullptr 47 : std::make_unique<Default>(std::move(arg1), 48 std::move(args...))), 49 pointer_(pointer ? pointer : owned_instance_.get()) { 50 RTC_DCHECK(pointer_); 51 } 52 53 // Create a pointer by 54 // a) using |pointer|, without taking ownership 55 // b) calling |function| and taking ownership of the result 56 template <typename Func, 57 typename std::enable_if<std::is_invocable<Func>::value, 58 bool>::type = true> AlwaysValidPointer(Interface * pointer,Func function)59 AlwaysValidPointer(Interface* pointer, Func function) 60 : owned_instance_(pointer ? nullptr : function()), 61 pointer_(owned_instance_ ? owned_instance_.get() : pointer) { 62 RTC_DCHECK(pointer_); 63 } 64 65 // Create a pointer by 66 // a) taking over ownership of |instance| 67 // b) or fallback to |pointer|, without taking ownership. 68 // c) or Default. AlwaysValidPointer(std::unique_ptr<Interface> && instance,Interface * pointer)69 AlwaysValidPointer(std::unique_ptr<Interface>&& instance, Interface* pointer) 70 : owned_instance_( 71 instance 72 ? std::move(instance) 73 : (pointer == nullptr ? std::make_unique<Default>() : nullptr)), 74 pointer_(owned_instance_ ? owned_instance_.get() : pointer) { 75 RTC_DCHECK(pointer_); 76 } 77 78 // Create a pointer by 79 // a) taking over ownership of |instance| 80 // b) or fallback to |pointer|, without taking ownership. 81 // c) or Default (with forwarded args). 82 template <typename... Args> AlwaysValidPointer(std::unique_ptr<Interface> && instance,Interface * pointer,Args...args)83 AlwaysValidPointer(std::unique_ptr<Interface>&& instance, 84 Interface* pointer, 85 Args... args) 86 : owned_instance_( 87 instance ? std::move(instance) 88 : (pointer == nullptr 89 ? std::make_unique<Default>(std::move(args...)) 90 : nullptr)), 91 pointer_(owned_instance_ ? owned_instance_.get() : pointer) { 92 RTC_DCHECK(pointer_); 93 } 94 get()95 Interface* get() { return pointer_; } 96 Interface* operator->() { return pointer_; } 97 Interface& operator*() { return *pointer_; } 98 get()99 Interface* get() const { return pointer_; } 100 Interface* operator->() const { return pointer_; } 101 Interface& operator*() const { return *pointer_; } 102 103 private: 104 const std::unique_ptr<Interface> owned_instance_; 105 Interface* const pointer_; 106 }; 107 108 // This class is similar to AlwaysValidPointer, but it does not create 109 // a default object and crashes if none of the input pointers are non-null. 110 template <typename Interface> 111 class AlwaysValidPointerNoDefault { 112 public: AlwaysValidPointerNoDefault(Interface * pointer)113 explicit AlwaysValidPointerNoDefault(Interface* pointer) : pointer_(pointer) { 114 RTC_CHECK(pointer_); 115 } 116 117 // Create a pointer by 118 // a) taking over ownership of |instance| 119 // b) or fallback to |pointer|, without taking ownership. 120 // At least one of the arguments must be non-null. 121 explicit AlwaysValidPointerNoDefault(std::unique_ptr<Interface> instance, 122 Interface* pointer = nullptr) owned_instance_(std::move (instance))123 : owned_instance_(std::move(instance)), 124 pointer_(owned_instance_ ? owned_instance_.get() : pointer) { 125 RTC_CHECK(pointer_); 126 } 127 get()128 Interface* get() { return pointer_; } 129 Interface* operator->() { return pointer_; } 130 Interface& operator*() { return *pointer_; } 131 get()132 Interface* get() const { return pointer_; } 133 Interface* operator->() const { return pointer_; } 134 Interface& operator*() const { return *pointer_; } 135 136 private: 137 const std::unique_ptr<Interface> owned_instance_; 138 Interface* const pointer_; 139 }; 140 141 template <typename T, typename U, typename V, typename W> 142 bool operator==(const AlwaysValidPointer<T, U>& a, 143 const AlwaysValidPointer<V, W>& b) { 144 return a.get() == b.get(); 145 } 146 147 template <typename T, typename U, typename V, typename W> 148 bool operator!=(const AlwaysValidPointer<T, U>& a, 149 const AlwaysValidPointer<V, W>& b) { 150 return !(a == b); 151 } 152 153 template <typename T, typename U> 154 bool operator==(const AlwaysValidPointer<T, U>& a, std::nullptr_t) { 155 return a.get() == nullptr; 156 } 157 158 template <typename T, typename U> 159 bool operator!=(const AlwaysValidPointer<T, U>& a, std::nullptr_t) { 160 return !(a == nullptr); 161 } 162 163 template <typename T, typename U> 164 bool operator==(std::nullptr_t, const AlwaysValidPointer<T, U>& a) { 165 return a.get() == nullptr; 166 } 167 168 template <typename T, typename U> 169 bool operator!=(std::nullptr_t, const AlwaysValidPointer<T, U>& a) { 170 return !(a == nullptr); 171 } 172 173 template <typename T, typename U> 174 bool operator==(const AlwaysValidPointerNoDefault<T>& a, 175 const AlwaysValidPointerNoDefault<U>& b) { 176 return a.get() == b.get(); 177 } 178 179 template <typename T, typename U> 180 bool operator!=(const AlwaysValidPointerNoDefault<T>& a, 181 const AlwaysValidPointerNoDefault<U>& b) { 182 return !(a == b); 183 } 184 185 template <typename T> 186 bool operator==(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) { 187 return a.get() == nullptr; 188 } 189 190 template <typename T> 191 bool operator!=(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) { 192 return !(a == nullptr); 193 } 194 195 template <typename T> 196 bool operator==(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) { 197 return a.get() == nullptr; 198 } 199 200 template <typename T> 201 bool operator!=(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) { 202 return !(a == nullptr); 203 } 204 205 // Comparison with raw pointer. 206 template <typename T, typename U, typename V> 207 bool operator==(const AlwaysValidPointer<T, U>& a, const V* b) { 208 return a.get() == b; 209 } 210 211 template <typename T, typename U, typename V> 212 bool operator!=(const AlwaysValidPointer<T, U>& a, const V* b) { 213 return !(a == b); 214 } 215 216 template <typename T, typename U, typename V> 217 bool operator==(const T* a, const AlwaysValidPointer<U, V>& b) { 218 return a == b.get(); 219 } 220 221 template <typename T, typename U, typename V> 222 bool operator!=(const T* a, const AlwaysValidPointer<U, V>& b) { 223 return !(a == b); 224 } 225 226 template <typename T, typename U> 227 bool operator==(const AlwaysValidPointerNoDefault<T>& a, const U* b) { 228 return a.get() == b; 229 } 230 231 template <typename T, typename U> 232 bool operator!=(const AlwaysValidPointerNoDefault<T>& a, const U* b) { 233 return !(a == b); 234 } 235 236 template <typename T, typename U> 237 bool operator==(const T* a, const AlwaysValidPointerNoDefault<U>& b) { 238 return a == b.get(); 239 } 240 241 template <typename T, typename U> 242 bool operator!=(const T* a, const AlwaysValidPointerNoDefault<U>& b) { 243 return !(a == b); 244 } 245 246 } // namespace webrtc 247 248 #endif // RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ 249