1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file is a clone of "base/optional.h" in chromium.
6 // Keep in sync, especially when fixing bugs.
7 // Copyright 2017 the V8 project authors. All rights reserved.
8
9 #ifndef V8_BASE_OPTIONAL_H_
10 #define V8_BASE_OPTIONAL_H_
11
12 #include <type_traits>
13 #include <utility>
14
15 #include "src/base/logging.h"
16
17 namespace v8 {
18 namespace base {
19
20 // Specification:
21 // http://en.cppreference.com/w/cpp/utility/optional/in_place_t
22 struct in_place_t {};
23
24 // Specification:
25 // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
26 struct nullopt_t {
nullopt_tv8::base::nullopt_t27 constexpr explicit nullopt_t(int) {}
28 };
29
30 // Specification:
31 // http://en.cppreference.com/w/cpp/utility/optional/in_place
32 constexpr in_place_t in_place = {};
33
34 // Specification:
35 // http://en.cppreference.com/w/cpp/utility/optional/nullopt
36 constexpr nullopt_t nullopt(0);
37
38 // Forward declaration, which is referred by following helpers.
39 template <typename T>
40 class Optional;
41
42 namespace internal {
43
44 template <typename T, bool = std::is_trivially_destructible<T>::value>
45 struct OptionalStorageBase {
46 // Initializing |empty_| here instead of using default member initializing
47 // to avoid errors in g++ 4.8.
OptionalStorageBasev8::base::internal::OptionalStorageBase48 constexpr OptionalStorageBase() : empty_('\0') {}
49
50 template <class... Args>
OptionalStorageBasev8::base::internal::OptionalStorageBase51 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
52 : is_populated_(true), value_(std::forward<Args>(args)...) {}
53
54 // When T is not trivially destructible we must call its
55 // destructor before deallocating its memory.
56 // Note that this hides the (implicitly declared) move constructor, which
57 // would be used for constexpr move constructor in OptionalStorage<T>.
58 // It is needed iff T is trivially move constructible. However, the current
59 // is_trivially_{copy,move}_constructible implementation requires
60 // is_trivially_destructible (which looks a bug, cf:
61 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
62 // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
63 // necessary for this case at the moment. Please see also the destructor
64 // comment in "is_trivially_destructible = true" specialization below.
~OptionalStorageBasev8::base::internal::OptionalStorageBase65 ~OptionalStorageBase() {
66 if (is_populated_) value_.~T();
67 }
68
69 template <class... Args>
Initv8::base::internal::OptionalStorageBase70 void Init(Args&&... args) {
71 DCHECK(!is_populated_);
72 ::new (&value_) T(std::forward<Args>(args)...);
73 is_populated_ = true;
74 }
75
76 bool is_populated_ = false;
77 union {
78 // |empty_| exists so that the union will always be initialized, even when
79 // it doesn't contain a value. Union members must be initialized for the
80 // constructor to be 'constexpr'.
81 char empty_;
82 T value_;
83 };
84 };
85
86 template <typename T>
87 struct OptionalStorageBase<T, true /* trivially destructible */> {
88 // Initializing |empty_| here instead of using default member initializing
89 // to avoid errors in g++ 4.8.
OptionalStorageBasev8::base::internal::OptionalStorageBase90 constexpr OptionalStorageBase() : empty_('\0') {}
91
92 template <class... Args>
OptionalStorageBasev8::base::internal::OptionalStorageBase93 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
94 : is_populated_(true), value_(std::forward<Args>(args)...) {}
95
96 // When T is trivially destructible (i.e. its destructor does nothing) there
97 // is no need to call it. Implicitly defined destructor is trivial, because
98 // both members (bool and union containing only variants which are trivially
99 // destructible) are trivially destructible.
100 // Explicitly-defaulted destructor is also trivial, but do not use it here,
101 // because it hides the implicit move constructor. It is needed to implement
102 // constexpr move constructor in OptionalStorage iff T is trivially move
103 // constructible. Note that, if T is trivially move constructible, the move
104 // constructor of OptionalStorageBase<T> is also implicitly defined and it is
105 // trivially move constructor. If T is not trivially move constructible,
106 // "not declaring move constructor without destructor declaration" here means
107 // "delete move constructor", which works because any move constructor of
108 // OptionalStorage will not refer to it in that case.
109
110 template <class... Args>
Initv8::base::internal::OptionalStorageBase111 void Init(Args&&... args) {
112 DCHECK(!is_populated_);
113 ::new (&value_) T(std::forward<Args>(args)...);
114 is_populated_ = true;
115 }
116
117 bool is_populated_ = false;
118 union {
119 // |empty_| exists so that the union will always be initialized, even when
120 // it doesn't contain a value. Union members must be initialized for the
121 // constructor to be 'constexpr'.
122 char empty_;
123 T value_;
124 };
125 };
126
127 // Implement conditional constexpr copy and move constructors. These are
128 // constexpr if is_trivially_{copy,move}_constructible<T>::value is true
129 // respectively. If each is true, the corresponding constructor is defined as
130 // "= default;", which generates a constexpr constructor (In this case,
131 // the condition of constexpr-ness is satisfied because the base class also has
132 // compiler generated constexpr {copy,move} constructors). Note that
133 // placement-new is prohibited in constexpr.
134 template <typename T, bool = std::is_trivially_copy_constructible<T>::value,
135 bool = std::is_trivially_move_constructible<T>::value>
136 struct OptionalStorage : OptionalStorageBase<T> {
137 // This is no trivially {copy,move} constructible case. Other cases are
138 // defined below as specializations.
139
140 // Accessing the members of template base class requires explicit
141 // declaration.
142 using OptionalStorageBase<T>::is_populated_;
143 using OptionalStorageBase<T>::value_;
144 using OptionalStorageBase<T>::Init;
145
146 // Inherit constructors (specifically, the in_place constructor).
147 using OptionalStorageBase<T>::OptionalStorageBase;
148
149 // User defined constructor deletes the default constructor.
150 // Define it explicitly.
151 OptionalStorage() = default;
152
153 OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
154 if (other.is_populated_) Init(other.value_);
155 }
156
157 OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
158 if (other.is_populated_) Init(std::move(other.value_));
159 }
160 };
161
162 template <typename T>
163 struct OptionalStorage<T, true /* trivially copy constructible */,
164 false /* trivially move constructible */>
165 : OptionalStorageBase<T> {
166 using OptionalStorageBase<T>::is_populated_;
167 using OptionalStorageBase<T>::value_;
168 using OptionalStorageBase<T>::Init;
169 using OptionalStorageBase<T>::OptionalStorageBase;
170
171 OptionalStorage() = default;
172 OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT = default;
173
174 OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
175 if (other.is_populated_) Init(std::move(other.value_));
176 }
177 };
178
179 template <typename T>
180 struct OptionalStorage<T, false /* trivially copy constructible */,
181 true /* trivially move constructible */>
182 : OptionalStorageBase<T> {
183 using OptionalStorageBase<T>::is_populated_;
184 using OptionalStorageBase<T>::value_;
185 using OptionalStorageBase<T>::Init;
186 using OptionalStorageBase<T>::OptionalStorageBase;
187
188 OptionalStorage() = default;
189 OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT = default;
190
191 OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
192 if (other.is_populated_) Init(other.value_);
193 }
194 };
195
196 template <typename T>
197 struct OptionalStorage<T, true /* trivially copy constructible */,
198 true /* trivially move constructible */>
199 : OptionalStorageBase<T> {
200 // If both trivially {copy,move} constructible are true, it is not necessary
201 // to use user-defined constructors. So, just inheriting constructors
202 // from the base class works.
203 using OptionalStorageBase<T>::OptionalStorageBase;
204 };
205
206 // Base class to support conditionally usable copy-/move- constructors
207 // and assign operators.
208 template <typename T>
209 class OptionalBase {
210 // This class provides implementation rather than public API, so everything
211 // should be hidden. Often we use composition, but we cannot in this case
212 // because of C++ language restriction.
213 protected:
214 constexpr OptionalBase() = default;
215 constexpr OptionalBase(const OptionalBase& other) V8_NOEXCEPT = default;
216 constexpr OptionalBase(OptionalBase&& other) V8_NOEXCEPT = default;
217
218 template <class... Args>
OptionalBase(in_place_t, Args&&... args)219 constexpr explicit OptionalBase(in_place_t, Args&&... args)
220 : storage_(in_place, std::forward<Args>(args)...) {}
221
222 // Implementation of converting constructors.
223 template <typename U>
224 explicit OptionalBase(const OptionalBase<U>& other) V8_NOEXCEPT {
225 if (other.storage_.is_populated_) storage_.Init(other.storage_.value_);
226 }
227
228 template <typename U>
229 explicit OptionalBase(OptionalBase<U>&& other) V8_NOEXCEPT {
230 if (other.storage_.is_populated_)
231 storage_.Init(std::move(other.storage_.value_));
232 }
233
234 ~OptionalBase() = default;
235
236 OptionalBase& operator=(const OptionalBase& other) V8_NOEXCEPT {
237 CopyAssign(other);
238 return *this;
239 }
240
241 OptionalBase& operator=(OptionalBase&& other) V8_NOEXCEPT {
242 MoveAssign(std::move(other));
243 return *this;
244 }
245
246 template <typename U>
CopyAssign(const OptionalBase<U>& other)247 void CopyAssign(const OptionalBase<U>& other) {
248 if (other.storage_.is_populated_)
249 InitOrAssign(other.storage_.value_);
250 else
251 FreeIfNeeded();
252 }
253
254 template <typename U>
MoveAssign(OptionalBase<U>&& other)255 void MoveAssign(OptionalBase<U>&& other) {
256 if (other.storage_.is_populated_)
257 InitOrAssign(std::move(other.storage_.value_));
258 else
259 FreeIfNeeded();
260 }
261
262 template <typename U>
InitOrAssign(U&& value)263 void InitOrAssign(U&& value) {
264 if (storage_.is_populated_)
265 storage_.value_ = std::forward<U>(value);
266 else
267 storage_.Init(std::forward<U>(value));
268 }
269
FreeIfNeeded()270 void FreeIfNeeded() {
271 if (!storage_.is_populated_) return;
272 storage_.value_.~T();
273 storage_.is_populated_ = false;
274 }
275
276 // For implementing conversion, allow access to other typed OptionalBase
277 // class.
278 template <typename U>
279 friend class OptionalBase;
280
281 OptionalStorage<T> storage_;
282 };
283
284 // The following {Copy,Move}{Constructible,Assignable} structs are helpers to
285 // implement constructor/assign-operator overloading. Specifically, if T is
286 // is not movable but copyable, Optional<T>'s move constructor should not
287 // participate in overload resolution. This inheritance trick implements that.
288 template <bool is_copy_constructible>
289 struct CopyConstructible {};
290
291 template <>
292 struct CopyConstructible<false> {
293 constexpr CopyConstructible() = default;
294 constexpr CopyConstructible(const CopyConstructible&) V8_NOEXCEPT = delete;
295 constexpr CopyConstructible(CopyConstructible&&) V8_NOEXCEPT = default;
296 CopyConstructible& operator=(const CopyConstructible&) V8_NOEXCEPT = default;
297 CopyConstructible& operator=(CopyConstructible&&) V8_NOEXCEPT = default;
298 };
299
300 template <bool is_move_constructible>
301 struct MoveConstructible {};
302
303 template <>
304 struct MoveConstructible<false> {
305 constexpr MoveConstructible() = default;
306 constexpr MoveConstructible(const MoveConstructible&) V8_NOEXCEPT = default;
307 constexpr MoveConstructible(MoveConstructible&&) V8_NOEXCEPT = delete;
308 MoveConstructible& operator=(const MoveConstructible&) V8_NOEXCEPT = default;
309 MoveConstructible& operator=(MoveConstructible&&) V8_NOEXCEPT = default;
310 };
311
312 template <bool is_copy_assignable>
313 struct CopyAssignable {};
314
315 template <>
316 struct CopyAssignable<false> {
317 constexpr CopyAssignable() = default;
318 constexpr CopyAssignable(const CopyAssignable&) V8_NOEXCEPT = default;
319 constexpr CopyAssignable(CopyAssignable&&) V8_NOEXCEPT = default;
320 CopyAssignable& operator=(const CopyAssignable&) V8_NOEXCEPT = delete;
321 CopyAssignable& operator=(CopyAssignable&&) V8_NOEXCEPT = default;
322 };
323
324 template <bool is_move_assignable>
325 struct MoveAssignable {};
326
327 template <>
328 struct MoveAssignable<false> {
329 constexpr MoveAssignable() = default;
330 constexpr MoveAssignable(const MoveAssignable&) V8_NOEXCEPT = default;
331 constexpr MoveAssignable(MoveAssignable&&) V8_NOEXCEPT = default;
332 MoveAssignable& operator=(const MoveAssignable&) V8_NOEXCEPT = default;
333 MoveAssignable& operator=(MoveAssignable&&) V8_NOEXCEPT = delete;
334 };
335
336 // Helper to conditionally enable converting constructors and assign operators.
337 template <typename T, typename U>
338 struct IsConvertibleFromOptional
339 : std::integral_constant<
340 bool, std::is_constructible<T, Optional<U>&>::value ||
341 std::is_constructible<T, const Optional<U>&>::value ||
342 std::is_constructible<T, Optional<U>&&>::value ||
343 std::is_constructible<T, const Optional<U>&&>::value ||
344 std::is_convertible<Optional<U>&, T>::value ||
345 std::is_convertible<const Optional<U>&, T>::value ||
346 std::is_convertible<Optional<U>&&, T>::value ||
347 std::is_convertible<const Optional<U>&&, T>::value> {};
348
349 template <typename T, typename U>
350 struct IsAssignableFromOptional
351 : std::integral_constant<
352 bool, IsConvertibleFromOptional<T, U>::value ||
353 std::is_assignable<T&, Optional<U>&>::value ||
354 std::is_assignable<T&, const Optional<U>&>::value ||
355 std::is_assignable<T&, Optional<U>&&>::value ||
356 std::is_assignable<T&, const Optional<U>&&>::value> {};
357
358 // Forward compatibility for C++17.
359 // Introduce one more deeper nested namespace to avoid leaking using std::swap.
360 namespace swappable_impl {
361 using std::swap;
362
363 struct IsSwappableImpl {
364 // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
365 // is available for T. Otherwise, Check's overload resolution falls back
366 // to Check(...) declared below thanks to SFINAE, so returns false_type.
367 template <typename T>
368 static auto Check(int i)
369 -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
370
371 template <typename T>
372 static std::false_type Check(...);
373 };
374 } // namespace swappable_impl
375
376 template <typename T>
377 struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
378
379 // Forward compatibility for C++20.
380 template <typename T>
381 using RemoveCvRefT =
382 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
383
384 } // namespace internal
385
386 // On Windows, by default, empty-base class optimization does not work,
387 // which means even if the base class is empty struct, it still consumes one
388 // byte for its body. __declspec(empty_bases) enables the optimization.
389 // cf)
390 // https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
391 #ifdef OS_WIN
392 #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
393 #else
394 #define OPTIONAL_DECLSPEC_EMPTY_BASES
395 #endif
396
397 // base::Optional is a Chromium version of the C++17 optional class:
398 // std::optional documentation:
399 // http://en.cppreference.com/w/cpp/utility/optional
400 // Chromium documentation:
401 // https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
402 //
403 // These are the differences between the specification and the implementation:
404 // - Constructors do not use 'constexpr' as it is a C++14 extension.
405 // - 'constexpr' might be missing in some places for reasons specified locally.
406 // - No exceptions are thrown, because they are banned from Chromium.
407 // All copy/move constructors or assignment operators are marked V8_NOEXCEPT.
408 // - All the non-members are in the 'base' namespace instead of 'std'.
409 //
410 // Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
411 // T's constructor (specifically via IsConvertibleFromOptional), and in the
412 // check whether T can be constructible from Optional<T>, which is recursive
413 // so it does not work. As of Feb 2018, std::optional C++17 implementation in
414 // both clang and gcc has same limitation. MSVC SFINAE looks to have different
415 // behavior, but anyway it reports an error, too.
416 template <typename T>
417 class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
418 : public internal::OptionalBase<T>,
419 public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
420 public internal::MoveConstructible<std::is_move_constructible<T>::value>,
421 public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
422 std::is_copy_assignable<T>::value>,
423 public internal::MoveAssignable<std::is_move_constructible<T>::value &&
424 std::is_move_assignable<T>::value> {
425 public:
426 #undef OPTIONAL_DECLSPEC_EMPTY_BASES
427 using value_type = T;
428
429 // Defer default/copy/move constructor implementation to OptionalBase.
430 constexpr Optional() = default;
431 constexpr Optional(const Optional& other) V8_NOEXCEPT = default;
432 constexpr Optional(Optional&& other) V8_NOEXCEPT = default;
433
Optional(nullopt_t)434 constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
435
436 // Converting copy constructor. "explicit" only if
437 // std::is_convertible<const U&, T>::value is false. It is implemented by
438 // declaring two almost same constructors, but that condition in enable_if
439 // is different, so that either one is chosen, thanks to SFINAE.
440 template <typename U,
441 typename std::enable_if<
442 std::is_constructible<T, const U&>::value &&
443 !internal::IsConvertibleFromOptional<T, U>::value &&
444 std::is_convertible<const U&, T>::value,
445 bool>::type = false>
446 Optional(const Optional<U>& other) V8_NOEXCEPT
OptionalBase(other)447 : internal::OptionalBase<T>(other) {}
448
449 template <typename U,
450 typename std::enable_if<
451 std::is_constructible<T, const U&>::value &&
452 !internal::IsConvertibleFromOptional<T, U>::value &&
453 !std::is_convertible<const U&, T>::value,
454 bool>::type = false>
455 explicit Optional(const Optional<U>& other) V8_NOEXCEPT
OptionalBase(other)456 : internal::OptionalBase<T>(other) {}
457
458 // Converting move constructor. Similar to converting copy constructor,
459 // declaring two (explicit and non-explicit) constructors.
460 template <typename U,
461 typename std::enable_if<
462 std::is_constructible<T, U&&>::value &&
463 !internal::IsConvertibleFromOptional<T, U>::value &&
464 std::is_convertible<U&&, T>::value,
465 bool>::type = false>
466 Optional(Optional<U>&& other) V8_NOEXCEPT
move(other)467 : internal::OptionalBase<T>(std::move(other)) {}
468
469 template <typename U,
470 typename std::enable_if<
471 std::is_constructible<T, U&&>::value &&
472 !internal::IsConvertibleFromOptional<T, U>::value &&
473 !std::is_convertible<U&&, T>::value,
474 bool>::type = false>
475 explicit Optional(Optional<U>&& other) V8_NOEXCEPT
move(other)476 : internal::OptionalBase<T>(std::move(other)) {}
477
478 template <class... Args>
Optional(in_place_t, Args&&... args)479 constexpr explicit Optional(in_place_t, Args&&... args)
480 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
481
482 template <class U, class... Args,
483 class = typename std::enable_if<std::is_constructible<
484 value_type, std::initializer_list<U>&, Args...>::value>::type>
Optional(in_place_t, std::initializer_list<U> il, Args&&... args)485 constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
486 Args&&... args)
487 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
488
489 // Forward value constructor. Similar to converting constructors,
490 // conditionally explicit.
491 template <
492 typename U = value_type,
493 typename std::enable_if<
494 std::is_constructible<T, U&&>::value &&
495 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
496 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
497 std::is_convertible<U&&, T>::value,
498 bool>::type = false>
Optional(U&& value)499 constexpr Optional(U&& value) // NOLINT(runtime/explicit)
500 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
501
502 template <
503 typename U = value_type,
504 typename std::enable_if<
505 std::is_constructible<T, U&&>::value &&
506 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
507 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
508 !std::is_convertible<U&&, T>::value,
509 bool>::type = false>
Optional(U&& value)510 constexpr explicit Optional(U&& value)
511 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
512
513 ~Optional() = default;
514
515 // Defer copy-/move- assign operator implementation to OptionalBase.
516 Optional& operator=(const Optional& other) V8_NOEXCEPT = default;
517 Optional& operator=(Optional&& other) V8_NOEXCEPT = default;
518
operator =(nullopt_t)519 Optional& operator=(nullopt_t) {
520 FreeIfNeeded();
521 return *this;
522 }
523
524 // Perfect-forwarded assignment.
525 template <typename U>
526 typename std::enable_if<
527 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
528 std::is_constructible<T, U>::value &&
529 std::is_assignable<T&, U>::value &&
530 (!std::is_scalar<T>::value ||
531 !std::is_same<typename std::decay<U>::type, T>::value),
532 Optional&>::type
533 operator=(U&& value) V8_NOEXCEPT {
534 InitOrAssign(std::forward<U>(value));
535 return *this;
536 }
537
538 // Copy assign the state of other.
539 template <typename U>
540 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
541 std::is_constructible<T, const U&>::value &&
542 std::is_assignable<T&, const U&>::value,
543 Optional&>::type
544 operator=(const Optional<U>& other) V8_NOEXCEPT {
545 CopyAssign(other);
546 return *this;
547 }
548
549 // Move assign the state of other.
550 template <typename U>
551 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
552 std::is_constructible<T, U>::value &&
553 std::is_assignable<T&, U>::value,
554 Optional&>::type
555 operator=(Optional<U>&& other) V8_NOEXCEPT {
556 MoveAssign(std::move(other));
557 return *this;
558 }
559
operator ->() const560 constexpr const T* operator->() const {
561 DCHECK(storage_.is_populated_);
562 return &storage_.value_;
563 }
564
operator ->()565 constexpr T* operator->() {
566 DCHECK(storage_.is_populated_);
567 return &storage_.value_;
568 }
569
operator *() const570 constexpr const T& operator*() const& {
571 DCHECK(storage_.is_populated_);
572 return storage_.value_;
573 }
574
operator *()575 constexpr T& operator*() & {
576 DCHECK(storage_.is_populated_);
577 return storage_.value_;
578 }
579
operator *() const580 constexpr const T&& operator*() const&& {
581 DCHECK(storage_.is_populated_);
582 return std::move(storage_.value_);
583 }
584
operator *()585 constexpr T&& operator*() && {
586 DCHECK(storage_.is_populated_);
587 return std::move(storage_.value_);
588 }
589
operator bool() const590 constexpr explicit operator bool() const { return storage_.is_populated_; }
591
has_value() const592 constexpr bool has_value() const { return storage_.is_populated_; }
593
value()594 T& value() & {
595 CHECK(storage_.is_populated_);
596 return storage_.value_;
597 }
598
value() const599 const T& value() const & {
600 CHECK(storage_.is_populated_);
601 return storage_.value_;
602 }
603
value()604 T&& value() && {
605 CHECK(storage_.is_populated_);
606 return std::move(storage_.value_);
607 }
608
value() const609 const T&& value() const && {
610 CHECK(storage_.is_populated_);
611 return std::move(storage_.value_);
612 }
613
614 template <class U>
value_or(U&& default_value) const615 constexpr T value_or(U&& default_value) const & {
616 // TODO(mlamouri): add the following assert when possible:
617 // static_assert(std::is_copy_constructible<T>::value,
618 // "T must be copy constructible");
619 static_assert(std::is_convertible<U, T>::value,
620 "U must be convertible to T");
621 return storage_.is_populated_
622 ? storage_.value_
623 : static_cast<T>(std::forward<U>(default_value));
624 }
625
626 template <class U>
value_or(U&& default_value)627 T value_or(U&& default_value) && {
628 // TODO(mlamouri): add the following assert when possible:
629 // static_assert(std::is_move_constructible<T>::value,
630 // "T must be move constructible");
631 static_assert(std::is_convertible<U, T>::value,
632 "U must be convertible to T");
633 return storage_.is_populated_
634 ? std::move(storage_.value_)
635 : static_cast<T>(std::forward<U>(default_value));
636 }
637
swap(Optional& other)638 void swap(Optional& other) {
639 if (!storage_.is_populated_ && !other.storage_.is_populated_) return;
640
641 if (storage_.is_populated_ != other.storage_.is_populated_) {
642 if (storage_.is_populated_) {
643 other.storage_.Init(std::move(storage_.value_));
644 FreeIfNeeded();
645 } else {
646 storage_.Init(std::move(other.storage_.value_));
647 other.FreeIfNeeded();
648 }
649 return;
650 }
651
652 DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
653 using std::swap;
654 swap(**this, *other);
655 }
656
reset()657 void reset() { FreeIfNeeded(); }
658
659 template <class... Args>
emplace(Args&&.... args)660 T& emplace(Args&&... args) {
661 FreeIfNeeded();
662 storage_.Init(std::forward<Args>(args)...);
663 return storage_.value_;
664 }
665
666 template <class U, class... Args>
667 typename std::enable_if<
668 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
669 T&>::type
emplace(std::initializer_list<U> il, Args&&... args)670 emplace(std::initializer_list<U> il, Args&&... args) {
671 FreeIfNeeded();
672 storage_.Init(il, std::forward<Args>(args)...);
673 return storage_.value_;
674 }
675
676 private:
677 // Accessing template base class's protected member needs explicit
678 // declaration to do so.
679 using internal::OptionalBase<T>::CopyAssign;
680 using internal::OptionalBase<T>::FreeIfNeeded;
681 using internal::OptionalBase<T>::InitOrAssign;
682 using internal::OptionalBase<T>::MoveAssign;
683 using internal::OptionalBase<T>::storage_;
684 };
685
686 // Here after defines comparation operators. The definition follows
687 // http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
688 // while bool() casting is replaced by has_value() to meet the chromium
689 // style guide.
690 template <class T, class U>
operator ==(const Optional<T>& lhs, const Optional<U>& rhs)691 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
692 if (lhs.has_value() != rhs.has_value()) return false;
693 if (!lhs.has_value()) return true;
694 return *lhs == *rhs;
695 }
696
697 template <class T, class U>
operator !=(const Optional<T>& lhs, const Optional<U>& rhs)698 bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
699 if (lhs.has_value() != rhs.has_value()) return true;
700 if (!lhs.has_value()) return false;
701 return *lhs != *rhs;
702 }
703
704 template <class T, class U>
operator <(const Optional<T>& lhs, const Optional<U>& rhs)705 bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
706 if (!rhs.has_value()) return false;
707 if (!lhs.has_value()) return true;
708 return *lhs < *rhs;
709 }
710
711 template <class T, class U>
operator <=(const Optional<T>& lhs, const Optional<U>& rhs)712 bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
713 if (!lhs.has_value()) return true;
714 if (!rhs.has_value()) return false;
715 return *lhs <= *rhs;
716 }
717
718 template <class T, class U>
operator >(const Optional<T>& lhs, const Optional<U>& rhs)719 bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
720 if (!lhs.has_value()) return false;
721 if (!rhs.has_value()) return true;
722 return *lhs > *rhs;
723 }
724
725 template <class T, class U>
operator >=(const Optional<T>& lhs, const Optional<U>& rhs)726 bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
727 if (!rhs.has_value()) return true;
728 if (!lhs.has_value()) return false;
729 return *lhs >= *rhs;
730 }
731
732 template <class T>
operator ==(const Optional<T>& opt, nullopt_t)733 constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
734 return !opt;
735 }
736
737 template <class T>
operator ==(nullopt_t, const Optional<T>& opt)738 constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
739 return !opt;
740 }
741
742 template <class T>
operator !=(const Optional<T>& opt, nullopt_t)743 constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
744 return opt.has_value();
745 }
746
747 template <class T>
operator !=(nullopt_t, const Optional<T>& opt)748 constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
749 return opt.has_value();
750 }
751
752 template <class T>
operator <(const Optional<T>& opt, nullopt_t)753 constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
754 return false;
755 }
756
757 template <class T>
operator <(nullopt_t, const Optional<T>& opt)758 constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
759 return opt.has_value();
760 }
761
762 template <class T>
operator <=(const Optional<T>& opt, nullopt_t)763 constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
764 return !opt;
765 }
766
767 template <class T>
operator <=(nullopt_t, const Optional<T>& opt)768 constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
769 return true;
770 }
771
772 template <class T>
operator >(const Optional<T>& opt, nullopt_t)773 constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
774 return opt.has_value();
775 }
776
777 template <class T>
operator >(nullopt_t, const Optional<T>& opt)778 constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
779 return false;
780 }
781
782 template <class T>
operator >=(const Optional<T>& opt, nullopt_t)783 constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
784 return true;
785 }
786
787 template <class T>
operator >=(nullopt_t, const Optional<T>& opt)788 constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
789 return !opt;
790 }
791
792 template <class T, class U>
operator ==(const Optional<T>& opt, const U& value)793 constexpr bool operator==(const Optional<T>& opt, const U& value) {
794 return opt.has_value() ? *opt == value : false;
795 }
796
797 template <class T, class U>
operator ==(const U& value, const Optional<T>& opt)798 constexpr bool operator==(const U& value, const Optional<T>& opt) {
799 return opt.has_value() ? value == *opt : false;
800 }
801
802 template <class T, class U>
operator !=(const Optional<T>& opt, const U& value)803 constexpr bool operator!=(const Optional<T>& opt, const U& value) {
804 return opt.has_value() ? *opt != value : true;
805 }
806
807 template <class T, class U>
operator !=(const U& value, const Optional<T>& opt)808 constexpr bool operator!=(const U& value, const Optional<T>& opt) {
809 return opt.has_value() ? value != *opt : true;
810 }
811
812 template <class T, class U>
operator <(const Optional<T>& opt, const U& value)813 constexpr bool operator<(const Optional<T>& opt, const U& value) {
814 return opt.has_value() ? *opt < value : true;
815 }
816
817 template <class T, class U>
operator <(const U& value, const Optional<T>& opt)818 constexpr bool operator<(const U& value, const Optional<T>& opt) {
819 return opt.has_value() ? value < *opt : false;
820 }
821
822 template <class T, class U>
operator <=(const Optional<T>& opt, const U& value)823 constexpr bool operator<=(const Optional<T>& opt, const U& value) {
824 return opt.has_value() ? *opt <= value : true;
825 }
826
827 template <class T, class U>
operator <=(const U& value, const Optional<T>& opt)828 constexpr bool operator<=(const U& value, const Optional<T>& opt) {
829 return opt.has_value() ? value <= *opt : false;
830 }
831
832 template <class T, class U>
operator >(const Optional<T>& opt, const U& value)833 constexpr bool operator>(const Optional<T>& opt, const U& value) {
834 return opt.has_value() ? *opt > value : false;
835 }
836
837 template <class T, class U>
operator >(const U& value, const Optional<T>& opt)838 constexpr bool operator>(const U& value, const Optional<T>& opt) {
839 return opt.has_value() ? value > *opt : true;
840 }
841
842 template <class T, class U>
operator >=(const Optional<T>& opt, const U& value)843 constexpr bool operator>=(const Optional<T>& opt, const U& value) {
844 return opt.has_value() ? *opt >= value : false;
845 }
846
847 template <class T, class U>
operator >=(const U& value, const Optional<T>& opt)848 constexpr bool operator>=(const U& value, const Optional<T>& opt) {
849 return opt.has_value() ? value >= *opt : true;
850 }
851
852 template <class T>
make_optional(T&& value)853 constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
854 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
855 }
856
857 template <class T, class... Args>
make_optional(Args&&.... args)858 constexpr Optional<T> make_optional(Args&&... args) {
859 return Optional<T>(in_place, std::forward<Args>(args)...);
860 }
861
862 template <class T, class U, class... Args>
make_optional(std::initializer_list<U> il, Args&&... args)863 constexpr Optional<T> make_optional(std::initializer_list<U> il,
864 Args&&... args) {
865 return Optional<T>(in_place, il, std::forward<Args>(args)...);
866 }
867
868 // Partial specialization for a function template is not allowed. Also, it is
869 // not allowed to add overload function to std namespace, while it is allowed
870 // to specialize the template in std. Thus, swap() (kind of) overloading is
871 // defined in base namespace, instead.
872 template <class T>
873 typename std::enable_if<std::is_move_constructible<T>::value &&
874 internal::IsSwappable<T>::value>::type
swap(Optional<T>& lhs, Optional<T>& rhs)875 swap(Optional<T>& lhs, Optional<T>& rhs) {
876 lhs.swap(rhs);
877 }
878
879 } // namespace base
880 } // namespace v8
881
882 #endif // V8_BASE_OPTIONAL_H_
883