Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: webrtc/rtc_base/optional.h

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

Powered by Google App Engine
This is Rietveld 408576698