• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 WEBRTC_BASE_OPTIONAL_H_
12 #define WEBRTC_BASE_OPTIONAL_H_
13 
14 #include <algorithm>
15 #include <utility>
16 
17 #include "webrtc/base/checks.h"
18 
19 namespace rtc {
20 
21 // Simple std::experimental::optional-wannabe. It either contains a T or not.
22 // In order to keep the implementation simple and portable, this implementation
23 // actually contains a (default-constructed) T even when it supposedly doesn't
24 // contain a value; use e.g. rtc::scoped_ptr<T> instead if that's too
25 // expensive.
26 //
27 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows
28 // being assigned to after having been moved from. Specifically, you may not
29 // assume that it just doesn't contain a value anymore.
30 //
31 // Examples of good places to use Optional:
32 //
33 // - As a class or struct member, when the member doesn't always have a value:
34 //     struct Prisoner {
35 //       std::string name;
36 //       Optional<int> cell_number;  // Empty if not currently incarcerated.
37 //     };
38 //
39 // - As a return value for functions that may fail to return a value on all
40 //   allowed inputs. For example, a function that searches an array might
41 //   return an Optional<size_t> (the index where it found the element, or
42 //   nothing if it didn't find it); and a function that parses numbers might
43 //   return Optional<double> (the parsed number, or nothing if parsing failed).
44 //
45 // Examples of bad places to use Optional:
46 //
47 // - As a return value for functions that may fail because of disallowed
48 //   inputs. For example, a string length function should not return
49 //   Optional<size_t> so that it can return nothing in case the caller passed
50 //   it a null pointer; the function should probably use RTC_[D]CHECK instead,
51 //   and return plain size_t.
52 //
53 // - As a return value for functions that may fail to return a value on all
54 //   allowed inputs, but need to tell the caller what went wrong. Returning
55 //   Optional<double> when parsing a single number as in the example above
56 //   might make sense, but any larger parse job is probably going to need to
57 //   tell the caller what the problem was, not just that there was one.
58 //
59 // TODO(kwiberg): Get rid of this class when the standard library has
60 // std::optional (and we're allowed to use it).
61 template <typename T>
62 class Optional final {
63  public:
64   // Construct an empty Optional.
Optional()65   Optional() : has_value_(false) {}
66 
67   // Construct an Optional that contains a value.
Optional(const T & val)68   explicit Optional(const T& val) : value_(val), has_value_(true) {}
Optional(T && val)69   explicit Optional(T&& val) : value_(std::move(val)), has_value_(true) {}
70 
71   // Copy and move constructors.
72   // TODO(kwiberg): =default the move constructor when MSVC supports it.
73   Optional(const Optional&) = default;
Optional(Optional && m)74   Optional(Optional&& m)
75       : value_(std::move(m.value_)), has_value_(m.has_value_) {}
76 
77   // Assignment.
78   // TODO(kwiberg): =default the move assignment op when MSVC supports it.
79   Optional& operator=(const Optional&) = default;
80   Optional& operator=(Optional&& m) {
81     value_ = std::move(m.value_);
82     has_value_ = m.has_value_;
83     return *this;
84   }
85 
swap(Optional & m1,Optional & m2)86   friend void swap(Optional& m1, Optional& m2) {
87     using std::swap;
88     swap(m1.value_, m2.value_);
89     swap(m1.has_value_, m2.has_value_);
90   }
91 
92   // Conversion to bool to test if we have a value.
93   explicit operator bool() const { return has_value_; }
94 
95   // Dereferencing. Only allowed if we have a value.
96   const T* operator->() const {
97     RTC_DCHECK(has_value_);
98     return &value_;
99   }
100   T* operator->() {
101     RTC_DCHECK(has_value_);
102     return &value_;
103   }
104   const T& operator*() const {
105     RTC_DCHECK(has_value_);
106     return value_;
107   }
108   T& operator*() {
109     RTC_DCHECK(has_value_);
110     return value_;
111   }
112 
113   // Dereference with a default value in case we don't have a value.
value_or(const T & default_val)114   const T& value_or(const T& default_val) const {
115     return has_value_ ? value_ : default_val;
116   }
117 
118   // Equality tests. Two Optionals are equal if they contain equivalent values,
119   // or
120   // if they're both empty.
121   friend bool operator==(const Optional& m1, const Optional& m2) {
122     return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_
123                                           : m1.has_value_ == m2.has_value_;
124   }
125   friend bool operator!=(const Optional& m1, const Optional& m2) {
126     return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_
127                                           : m1.has_value_ != m2.has_value_;
128   }
129 
130  private:
131   // Invariant: Unless *this has been moved from, value_ is default-initialized
132   // (or copied or moved from a default-initialized T) if !has_value_.
133   T value_;
134   bool has_value_;
135 };
136 
137 }  // namespace rtc
138 
139 #endif  // WEBRTC_BASE_OPTIONAL_H_
140