blob: 728ed9e7378c07ce4b2c0c89edecfc497c14c4f7 [file] [log] [blame]
Karl Wibergbe579832015-11-10 22:34:18 +01001/*
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>
kwibergbfefb032016-05-01 14:53:46 -070015#include <memory>
Karl Wibergbe579832015-11-10 22:34:18 +010016#include <utility>
17
kwiberg2b11fd22016-09-09 03:35:24 -070018#include "webrtc/base/array_view.h"
Karl Wibergbe579832015-11-10 22:34:18 +010019#include "webrtc/base/checks.h"
kwiberg2b11fd22016-09-09 03:35:24 -070020#include "webrtc/base/sanitizer.h"
Karl Wibergbe579832015-11-10 22:34:18 +010021
22namespace rtc {
23
kwiberg2b11fd22016-09-09 03:35:24 -070024namespace optional_internal {
25
26#if RTC_HAS_ASAN
27
28// This is a non-inlined function. The optimizer can't see inside it.
29void* FunctionThatDoesNothingImpl(void*);
30
31template <typename T>
32inline T* FunctionThatDoesNothing(T* x) {
33 return reinterpret_cast<T*>(
34 FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x)));
35}
36
37#else
38
39template <typename T>
40inline T* FunctionThatDoesNothing(T* x) { return x; }
41
42#endif
43
44} // namespace optional_internal
45
kwibergd0404802016-05-09 06:06:05 -070046// Simple std::optional-wannabe. It either contains a T or not.
Karl Wibergbe579832015-11-10 22:34:18 +010047//
48// A moved-from Optional<T> may only be destroyed, and assigned to if T allows
49// being assigned to after having been moved from. Specifically, you may not
50// assume that it just doesn't contain a value anymore.
51//
52// Examples of good places to use Optional:
53//
54// - As a class or struct member, when the member doesn't always have a value:
55// struct Prisoner {
56// std::string name;
57// Optional<int> cell_number; // Empty if not currently incarcerated.
58// };
59//
60// - As a return value for functions that may fail to return a value on all
61// allowed inputs. For example, a function that searches an array might
62// return an Optional<size_t> (the index where it found the element, or
63// nothing if it didn't find it); and a function that parses numbers might
64// return Optional<double> (the parsed number, or nothing if parsing failed).
65//
66// Examples of bad places to use Optional:
67//
68// - As a return value for functions that may fail because of disallowed
69// inputs. For example, a string length function should not return
70// Optional<size_t> so that it can return nothing in case the caller passed
71// it a null pointer; the function should probably use RTC_[D]CHECK instead,
72// and return plain size_t.
73//
74// - As a return value for functions that may fail to return a value on all
75// allowed inputs, but need to tell the caller what went wrong. Returning
76// Optional<double> when parsing a single number as in the example above
77// might make sense, but any larger parse job is probably going to need to
78// tell the caller what the problem was, not just that there was one.
79//
80// TODO(kwiberg): Get rid of this class when the standard library has
81// std::optional (and we're allowed to use it).
82template <typename T>
83class Optional final {
84 public:
85 // Construct an empty Optional.
kwiberg2b11fd22016-09-09 03:35:24 -070086 Optional() : has_value_(false), empty_('\0') {
87 PoisonValue();
88 }
Karl Wibergbe579832015-11-10 22:34:18 +010089
90 // Construct an Optional that contains a value.
kwibergd0404802016-05-09 06:06:05 -070091 explicit Optional(const T& value) : has_value_(true) {
92 new (&value_) T(value);
93 }
94 explicit Optional(T&& value) : has_value_(true) {
95 new (&value_) T(std::move(value));
96 }
Karl Wibergbe579832015-11-10 22:34:18 +010097
kwibergd0404802016-05-09 06:06:05 -070098 // Copy constructor: copies the value from m if it has one.
99 Optional(const Optional& m) : has_value_(m.has_value_) {
100 if (has_value_)
101 new (&value_) T(m.value_);
kwiberg2b11fd22016-09-09 03:35:24 -0700102 else
103 PoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700104 }
Karl Wibergbe579832015-11-10 22:34:18 +0100105
kwibergd0404802016-05-09 06:06:05 -0700106 // Move constructor: if m has a value, moves the value from m, leaving m
107 // still in a state where it has a value, but a moved-from one (the
108 // properties of which depends on T; the only general guarantee is that we
109 // can destroy m).
110 Optional(Optional&& m) : has_value_(m.has_value_) {
111 if (has_value_)
112 new (&value_) T(std::move(m.value_));
kwiberg2b11fd22016-09-09 03:35:24 -0700113 else
114 PoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700115 }
Karl Wibergbe579832015-11-10 22:34:18 +0100116
kwibergd0404802016-05-09 06:06:05 -0700117 ~Optional() {
118 if (has_value_)
119 value_.~T();
kwiberg2b11fd22016-09-09 03:35:24 -0700120 else
121 UnpoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700122 }
123
124 // Copy assignment. Uses T's copy assignment if both sides have a value, T's
125 // copy constructor if only the right-hand side has a value.
126 Optional& operator=(const Optional& m) {
127 if (m.has_value_) {
128 if (has_value_) {
129 value_ = m.value_; // T's copy assignment.
130 } else {
kwiberg2b11fd22016-09-09 03:35:24 -0700131 UnpoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700132 new (&value_) T(m.value_); // T's copy constructor.
133 has_value_ = true;
134 }
danilchapc4fd23c2016-10-17 07:16:54 -0700135 } else {
136 reset();
kwibergd0404802016-05-09 06:06:05 -0700137 }
138 return *this;
139 }
140
141 // Move assignment. Uses T's move assignment if both sides have a value, T's
142 // move constructor if only the right-hand side has a value. The state of m
143 // after it's been moved from is as for the move constructor.
144 Optional& operator=(Optional&& m) {
145 if (m.has_value_) {
146 if (has_value_) {
147 value_ = std::move(m.value_); // T's move assignment.
148 } else {
kwiberg2b11fd22016-09-09 03:35:24 -0700149 UnpoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700150 new (&value_) T(std::move(m.value_)); // T's move constructor.
151 has_value_ = true;
152 }
danilchapc4fd23c2016-10-17 07:16:54 -0700153 } else {
154 reset();
kwibergd0404802016-05-09 06:06:05 -0700155 }
156 return *this;
157 }
158
159 // Swap the values if both m1 and m2 have values; move the value if only one
160 // of them has one.
Karl Wibergbe579832015-11-10 22:34:18 +0100161 friend void swap(Optional& m1, Optional& m2) {
kwibergd0404802016-05-09 06:06:05 -0700162 if (m1.has_value_) {
163 if (m2.has_value_) {
164 // Both have values: swap.
165 using std::swap;
166 swap(m1.value_, m2.value_);
167 } else {
168 // Only m1 has a value: move it to m2.
kwiberg2b11fd22016-09-09 03:35:24 -0700169 m2.UnpoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700170 new (&m2.value_) T(std::move(m1.value_));
171 m1.value_.~T(); // Destroy the moved-from value.
172 m1.has_value_ = false;
173 m2.has_value_ = true;
kwiberg2b11fd22016-09-09 03:35:24 -0700174 m1.PoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700175 }
176 } else if (m2.has_value_) {
177 // Only m2 has a value: move it to m1.
kwiberg2b11fd22016-09-09 03:35:24 -0700178 m1.UnpoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700179 new (&m1.value_) T(std::move(m2.value_));
180 m2.value_.~T(); // Destroy the moved-from value.
181 m1.has_value_ = true;
182 m2.has_value_ = false;
kwiberg2b11fd22016-09-09 03:35:24 -0700183 m2.PoisonValue();
kwibergd0404802016-05-09 06:06:05 -0700184 }
Karl Wibergbe579832015-11-10 22:34:18 +0100185 }
186
danilchapc4fd23c2016-10-17 07:16:54 -0700187 // Destroy any contained value. Has no effect if we have no value.
188 void reset() {
189 if (!has_value_)
190 return;
191 value_.~T();
192 has_value_ = false;
193 PoisonValue();
194 }
195
danilchap9e83c972016-10-18 04:07:18 -0700196 template <class... Args>
197 void emplace(Args&&... args) {
198 if (has_value_)
199 value_.~T();
200 else
201 UnpoisonValue();
202 new (&value_) T(std::forward<Args>(args)...);
203 has_value_ = true;
204 }
205
Karl Wibergbe579832015-11-10 22:34:18 +0100206 // Conversion to bool to test if we have a value.
207 explicit operator bool() const { return has_value_; }
208
209 // Dereferencing. Only allowed if we have a value.
210 const T* operator->() const {
211 RTC_DCHECK(has_value_);
212 return &value_;
213 }
214 T* operator->() {
215 RTC_DCHECK(has_value_);
216 return &value_;
217 }
218 const T& operator*() const {
219 RTC_DCHECK(has_value_);
220 return value_;
221 }
222 T& operator*() {
223 RTC_DCHECK(has_value_);
224 return value_;
225 }
226
227 // Dereference with a default value in case we don't have a value.
228 const T& value_or(const T& default_val) const {
kwiberg2b11fd22016-09-09 03:35:24 -0700229 // The no-op call prevents the compiler from generating optimized code that
230 // reads value_ even if !has_value_, but only if FunctionThatDoesNothing is
231 // not completely inlined; see its declaration.).
232 return has_value_ ? *optional_internal::FunctionThatDoesNothing(&value_)
233 : default_val;
Karl Wibergbe579832015-11-10 22:34:18 +0100234 }
235
236 // Equality tests. Two Optionals are equal if they contain equivalent values,
237 // or
238 // if they're both empty.
239 friend bool operator==(const Optional& m1, const Optional& m2) {
240 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_
241 : m1.has_value_ == m2.has_value_;
242 }
243 friend bool operator!=(const Optional& m1, const Optional& m2) {
244 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_
245 : m1.has_value_ != m2.has_value_;
246 }
247
248 private:
kwiberg2b11fd22016-09-09 03:35:24 -0700249 // Tell sanitizers that value_ shouldn't be touched.
250 void PoisonValue() {
251 rtc::AsanPoison(rtc::MakeArrayView(&value_, 1));
252 rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1));
253 }
254
255 // Tell sanitizers that value_ is OK to touch again.
256 void UnpoisonValue() {
257 rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1));
258 }
259
kwibergd0404802016-05-09 06:06:05 -0700260 bool has_value_; // True iff value_ contains a live value.
261 union {
ossuea416942016-06-30 02:14:54 -0700262 // empty_ exists only to make it possible to initialize the union, even when
263 // it doesn't contain any data. If the union goes uninitialized, it may
264 // trigger compiler warnings.
265 char empty_;
kwibergd0404802016-05-09 06:06:05 -0700266 // By placing value_ in a union, we get to manage its construction and
267 // destruction manually: the Optional constructors won't automatically
268 // construct it, and the Optional destructor won't automatically destroy
269 // it. Basically, this just allocates a properly sized and aligned block of
270 // memory in which we can manually put a T with placement new.
271 T value_;
272 };
Karl Wibergbe579832015-11-10 22:34:18 +0100273};
274
275} // namespace rtc
276
277#endif // WEBRTC_BASE_OPTIONAL_H_