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