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