• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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