1 /*
2 * Copyright 2015 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
11 #ifndef API_OPTIONAL_H_
12 #define API_OPTIONAL_H_
13
14 #include <algorithm>
15 #include <memory>
16 #include <utility>
17
18 #ifdef UNIT_TEST
19 #include <iomanip>
20 #include <ostream>
21 #endif // UNIT_TEST
22
23 #include "api/array_view.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/sanitizer.h"
26
27 namespace rtc {
28
29 namespace optional_internal {
30
31 #if RTC_HAS_ASAN
32
33 // This is a non-inlined function. The optimizer can't see inside it. It
34 // prevents the compiler from generating optimized code that reads value_ even
35 // if it is unset. Although safe, this causes memory sanitizers to complain.
36 const void* FunctionThatDoesNothingImpl(const void*);
37
38 template <typename T>
FunctionThatDoesNothing(const T * x)39 inline const T* FunctionThatDoesNothing(const T* x) {
40 return reinterpret_cast<const T*>(
41 FunctionThatDoesNothingImpl(reinterpret_cast<const void*>(x)));
42 }
43
44
45 #else
46
47 template <typename T>
48 inline T* FunctionThatDoesNothing(T* x) {
49 return x;
50 }
51
52 #endif
53
54 struct NulloptArg;
55
56 } // namespace optional_internal
57
58 // nullopt_t must be a non-aggregate literal type with a constexpr constructor
59 // that takes some implementation-defined literal type. It mustn't have a
60 // default constructor nor an initializer-list constructor.
61 // See:
62 // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
63 // That page uses int, though this seems to confuse older versions of GCC.
64 struct nullopt_t {
nullopt_tnullopt_t65 constexpr explicit nullopt_t(rtc::optional_internal::NulloptArg&) {}
66 };
67
68 // Specification:
69 // http://en.cppreference.com/w/cpp/utility/optional/nullopt
70 extern const nullopt_t nullopt;
71
72 // Simple std::optional-wannabe. It either contains a T or not.
73 //
74 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows
75 // being assigned to after having been moved from. Specifically, you may not
76 // assume that it just doesn't contain a value anymore.
77 //
78 // Examples of good places to use Optional:
79 //
80 // - As a class or struct member, when the member doesn't always have a value:
81 // struct Prisoner {
82 // std::string name;
83 // Optional<int> cell_number; // Empty if not currently incarcerated.
84 // };
85 //
86 // - As a return value for functions that may fail to return a value on all
87 // allowed inputs. For example, a function that searches an array might
88 // return an Optional<size_t> (the index where it found the element, or
89 // nothing if it didn't find it); and a function that parses numbers might
90 // return Optional<double> (the parsed number, or nothing if parsing failed).
91 //
92 // Examples of bad places to use Optional:
93 //
94 // - As a return value for functions that may fail because of disallowed
95 // inputs. For example, a string length function should not return
96 // Optional<size_t> so that it can return nothing in case the caller passed
97 // it a null pointer; the function should probably use RTC_[D]CHECK instead,
98 // and return plain size_t.
99 //
100 // - As a return value for functions that may fail to return a value on all
101 // allowed inputs, but need to tell the caller what went wrong. Returning
102 // Optional<double> when parsing a single number as in the example above
103 // might make sense, but any larger parse job is probably going to need to
104 // tell the caller what the problem was, not just that there was one.
105 //
106 // - As a non-mutable function argument. When you want to pass a value of a
107 // type T that can fail to be there, const T* is almost always both fastest
108 // and cleanest. (If you're *sure* that the the caller will always already
109 // have an Optional<T>, const Optional<T>& is slightly faster than const T*,
110 // but this is a micro-optimization. In general, stick to const T*.)
111 //
112 // TODO(kwiberg): Get rid of this class when the standard library has
113 // std::optional (and we're allowed to use it).
114 template <typename T>
115 class Optional final {
116 public:
117 // Construct an empty Optional.
Optional()118 Optional() : has_value_(false), empty_('\0') { PoisonValue(); }
119
Optional(rtc::nullopt_t)120 Optional(rtc::nullopt_t) // NOLINT(runtime/explicit)
121 : Optional() {}
122
123 // Construct an Optional that contains a value.
Optional(const T & value)124 Optional(const T& value) // NOLINT(runtime/explicit)
125 : has_value_(true) {
126 new (&value_) T(value);
127 }
Optional(T && value)128 Optional(T&& value) // NOLINT(runtime/explicit)
129 : has_value_(true) {
130 new (&value_) T(std::move(value));
131 }
132
133 // Copy constructor: copies the value from m if it has one.
Optional(const Optional & m)134 Optional(const Optional& m) : has_value_(m.has_value_) {
135 if (has_value_)
136 new (&value_) T(m.value_);
137 else
138 PoisonValue();
139 }
140
141 // Move constructor: if m has a value, moves the value from m, leaving m
142 // still in a state where it has a value, but a moved-from one (the
143 // properties of which depends on T; the only general guarantee is that we
144 // can destroy m).
Optional(Optional && m)145 Optional(Optional&& m) : has_value_(m.has_value_) {
146 if (has_value_)
147 new (&value_) T(std::move(m.value_));
148 else
149 PoisonValue();
150 }
151
~Optional()152 ~Optional() {
153 if (has_value_)
154 value_.~T();
155 else
156 UnpoisonValue();
157 }
158
159 Optional& operator=(rtc::nullopt_t) {
160 reset();
161 return *this;
162 }
163
164 // Copy assignment. Uses T's copy assignment if both sides have a value, T's
165 // copy constructor if only the right-hand side has a value.
166 Optional& operator=(const Optional& m) {
167 if (m.has_value_) {
168 if (has_value_) {
169 value_ = m.value_; // T's copy assignment.
170 } else {
171 UnpoisonValue();
172 new (&value_) T(m.value_); // T's copy constructor.
173 has_value_ = true;
174 }
175 } else {
176 reset();
177 }
178 return *this;
179 }
180
181 // Move assignment. Uses T's move assignment if both sides have a value, T's
182 // move constructor if only the right-hand side has a value. The state of m
183 // after it's been moved from is as for the move constructor.
184 Optional& operator=(Optional&& m) {
185 if (m.has_value_) {
186 if (has_value_) {
187 value_ = std::move(m.value_); // T's move assignment.
188 } else {
189 UnpoisonValue();
190 new (&value_) T(std::move(m.value_)); // T's move constructor.
191 has_value_ = true;
192 }
193 } else {
194 reset();
195 }
196 return *this;
197 }
198
199 // Swap the values if both m1 and m2 have values; move the value if only one
200 // of them has one.
swap(Optional & m1,Optional & m2)201 friend void swap(Optional& m1, Optional& m2) {
202 if (m1.has_value_) {
203 if (m2.has_value_) {
204 // Both have values: swap.
205 using std::swap;
206 swap(m1.value_, m2.value_);
207 } else {
208 // Only m1 has a value: move it to m2.
209 m2.UnpoisonValue();
210 new (&m2.value_) T(std::move(m1.value_));
211 m1.value_.~T(); // Destroy the moved-from value.
212 m1.has_value_ = false;
213 m2.has_value_ = true;
214 m1.PoisonValue();
215 }
216 } else if (m2.has_value_) {
217 // Only m2 has a value: move it to m1.
218 m1.UnpoisonValue();
219 new (&m1.value_) T(std::move(m2.value_));
220 m2.value_.~T(); // Destroy the moved-from value.
221 m1.has_value_ = true;
222 m2.has_value_ = false;
223 m2.PoisonValue();
224 }
225 }
226
227 // Destroy any contained value. Has no effect if we have no value.
reset()228 void reset() {
229 if (!has_value_)
230 return;
231 value_.~T();
232 has_value_ = false;
233 PoisonValue();
234 }
235
236 template <class... Args>
emplace(Args &&...args)237 void emplace(Args&&... args) {
238 if (has_value_)
239 value_.~T();
240 else
241 UnpoisonValue();
242 new (&value_) T(std::forward<Args>(args)...);
243 has_value_ = true;
244 }
245
246 // Conversion to bool to test if we have a value.
247 explicit operator bool() const { return has_value_; }
has_value()248 bool has_value() const { return has_value_; }
249
250 // Dereferencing. Only allowed if we have a value.
251 const T* operator->() const {
252 RTC_DCHECK(has_value_);
253 return &value_;
254 }
255 T* operator->() {
256 RTC_DCHECK(has_value_);
257 return &value_;
258 }
259 const T& operator*() const {
260 RTC_DCHECK(has_value_);
261 return value_;
262 }
263 T& operator*() {
264 RTC_DCHECK(has_value_);
265 return value_;
266 }
value()267 const T& value() const {
268 RTC_DCHECK(has_value_);
269 return value_;
270 }
value()271 T& value() {
272 RTC_DCHECK(has_value_);
273 return value_;
274 }
275
276 // Dereference with a default value in case we don't have a value.
value_or(const T & default_val)277 const T& value_or(const T& default_val) const {
278 // The no-op call prevents the compiler from generating optimized code that
279 // reads value_ even if !has_value_, but only if FunctionThatDoesNothing is
280 // not completely inlined; see its declaration.).
281 return has_value_ ? *optional_internal::FunctionThatDoesNothing(&value_)
282 : default_val;
283 }
284
285 // Dereference and move value.
MoveValue()286 T MoveValue() {
287 RTC_DCHECK(has_value_);
288 return std::move(value_);
289 }
290
291 // Equality tests. Two Optionals are equal if they contain equivalent values,
292 // or if they're both empty.
293 friend bool operator==(const Optional& m1, const Optional& m2) {
294 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_
295 : m1.has_value_ == m2.has_value_;
296 }
297 friend bool operator==(const Optional& opt, const T& value) {
298 return opt.has_value_ && opt.value_ == value;
299 }
300 friend bool operator==(const T& value, const Optional& opt) {
301 return opt.has_value_ && value == opt.value_;
302 }
303
304 friend bool operator==(const Optional& opt, rtc::nullopt_t) {
305 return !opt.has_value_;
306 }
307
308 friend bool operator==(rtc::nullopt_t, const Optional& opt) {
309 return !opt.has_value_;
310 }
311
312 friend bool operator!=(const Optional& m1, const Optional& m2) {
313 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_
314 : m1.has_value_ != m2.has_value_;
315 }
316 friend bool operator!=(const Optional& opt, const T& value) {
317 return !opt.has_value_ || opt.value_ != value;
318 }
319 friend bool operator!=(const T& value, const Optional& opt) {
320 return !opt.has_value_ || value != opt.value_;
321 }
322
323 friend bool operator!=(const Optional& opt, rtc::nullopt_t) {
324 return opt.has_value_;
325 }
326
327 friend bool operator!=(rtc::nullopt_t, const Optional& opt) {
328 return opt.has_value_;
329 }
330
331 private:
332 // Tell sanitizers that value_ shouldn't be touched.
PoisonValue()333 void PoisonValue() {
334 rtc::AsanPoison(rtc::MakeArrayView(&value_, 1));
335 rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1));
336 }
337
338 // Tell sanitizers that value_ is OK to touch again.
UnpoisonValue()339 void UnpoisonValue() { rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1)); }
340
341 bool has_value_; // True iff value_ contains a live value.
342 union {
343 // empty_ exists only to make it possible to initialize the union, even when
344 // it doesn't contain any data. If the union goes uninitialized, it may
345 // trigger compiler warnings.
346 char empty_;
347 // By placing value_ in a union, we get to manage its construction and
348 // destruction manually: the Optional constructors won't automatically
349 // construct it, and the Optional destructor won't automatically destroy
350 // it. Basically, this just allocates a properly sized and aligned block of
351 // memory in which we can manually put a T with placement new.
352 T value_;
353 };
354 };
355
356 #ifdef UNIT_TEST
357 namespace optional_internal {
358
359 // Checks if there's a valid PrintTo(const T&, std::ostream*) call for T.
360 template <typename T>
361 struct HasPrintTo {
362 private:
363 struct No {};
364
365 template <typename T2>
366 static auto Test(const T2& obj)
367 -> decltype(PrintTo(obj, std::declval<std::ostream*>()));
368
369 template <typename>
370 static No Test(...);
371
372 public:
373 static constexpr bool value =
374 !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value;
375 };
376
377 // Checks if there's a valid operator<<(std::ostream&, const T&) call for T.
378 template <typename T>
379 struct HasOstreamOperator {
380 private:
381 struct No {};
382
383 template <typename T2>
384 static auto Test(const T2& obj)
385 -> decltype(std::declval<std::ostream&>() << obj);
386
387 template <typename>
388 static No Test(...);
389
390 public:
391 static constexpr bool value =
392 !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value;
393 };
394
395 // Prefer using PrintTo to print the object.
396 template <typename T>
OptionalPrintToHelper(const T & value,std::ostream * os)397 typename std::enable_if<HasPrintTo<T>::value, void>::type OptionalPrintToHelper(
398 const T& value,
399 std::ostream* os) {
400 PrintTo(value, os);
401 }
402
403 // Fall back to operator<<(std::ostream&, ...) if it exists.
404 template <typename T>
405 typename std::enable_if<HasOstreamOperator<T>::value && !HasPrintTo<T>::value,
406 void>::type
OptionalPrintToHelper(const T & value,std::ostream * os)407 OptionalPrintToHelper(const T& value, std::ostream* os) {
408 *os << value;
409 }
410
OptionalPrintObjectBytes(const unsigned char * bytes,size_t size,std::ostream * os)411 inline void OptionalPrintObjectBytes(const unsigned char* bytes,
412 size_t size,
413 std::ostream* os) {
414 *os << "<optional with " << size << "-byte object [";
415 for (size_t i = 0; i != size; ++i) {
416 *os << (i == 0 ? "" : ((i & 1) ? "-" : " "));
417 *os << std::hex << std::setw(2) << std::setfill('0')
418 << static_cast<int>(bytes[i]);
419 }
420 *os << "]>";
421 }
422
423 // As a final back-up, just print the contents of the objcets byte-wise.
424 template <typename T>
425 typename std::enable_if<!HasOstreamOperator<T>::value && !HasPrintTo<T>::value,
426 void>::type
OptionalPrintToHelper(const T & value,std::ostream * os)427 OptionalPrintToHelper(const T& value, std::ostream* os) {
428 OptionalPrintObjectBytes(reinterpret_cast<const unsigned char*>(&value),
429 sizeof(value), os);
430 }
431
432 } // namespace optional_internal
433
434 // PrintTo is used by gtest to print out the results of tests. We want to ensure
435 // the object contained in an Optional can be printed out if it's set, while
436 // avoiding touching the object's storage if it is undefined.
437 template <typename T>
PrintTo(const rtc::Optional<T> & opt,std::ostream * os)438 void PrintTo(const rtc::Optional<T>& opt, std::ostream* os) {
439 if (opt) {
440 optional_internal::OptionalPrintToHelper(*opt, os);
441 } else {
442 *os << "<empty optional>";
443 }
444 }
445
446 #endif // UNIT_TEST
447
448 } // namespace rtc
449
450 #endif // API_OPTIONAL_H_
451