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_tnullopt_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 refered 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. OptionalStorageBaseOptionalStorageBase48 constexpr OptionalStorageBase() : empty_('\0') {} 49 50 template <class... Args> OptionalStorageBaseOptionalStorageBase51 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. ~OptionalStorageBaseOptionalStorageBase65 ~OptionalStorageBase() { 66 if (is_populated_) value_.~T(); 67 } 68 69 template <class... Args> InitOptionalStorageBase70 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. 90 constexpr OptionalStorageBase() : empty_('\0') {} 91 92 template <class... Args> 93 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> 111 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> 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> 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> 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> 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 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 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 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 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 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 476 : internal::OptionalBase<T>(std::move(other)) {} 477 478 template <class... 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> 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> 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> 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 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 560 constexpr const T* operator->() const { 561 CONSTEXPR_DCHECK(storage_.is_populated_); 562 return &storage_.value_; 563 } 564 565 constexpr T* operator->() { 566 CONSTEXPR_DCHECK(storage_.is_populated_); 567 return &storage_.value_; 568 } 569 570 constexpr const T& operator*() const& { 571 CONSTEXPR_DCHECK(storage_.is_populated_); 572 return storage_.value_; 573 } 574 575 constexpr T& operator*() & { 576 CONSTEXPR_DCHECK(storage_.is_populated_); 577 return storage_.value_; 578 } 579 580 constexpr const T&& operator*() const&& { 581 CONSTEXPR_DCHECK(storage_.is_populated_); 582 return std::move(storage_.value_); 583 } 584 585 constexpr T&& operator*() && { 586 CONSTEXPR_DCHECK(storage_.is_populated_); 587 return std::move(storage_.value_); 588 } 589 590 constexpr explicit operator bool() const { return storage_.is_populated_; } 591 592 constexpr bool has_value() const { return storage_.is_populated_; } 593 594 T& value() & { 595 CHECK(storage_.is_populated_); 596 return storage_.value_; 597 } 598 599 const T& value() const & { 600 CHECK(storage_.is_populated_); 601 return storage_.value_; 602 } 603 604 T&& value() && { 605 CHECK(storage_.is_populated_); 606 return std::move(storage_.value_); 607 } 608 609 const T&& value() const && { 610 CHECK(storage_.is_populated_); 611 return std::move(storage_.value_); 612 } 613 614 template <class U> 615 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> 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 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 657 void reset() { FreeIfNeeded(); } 658 659 template <class... 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 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> 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> 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> 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> 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> 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> 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> 733 constexpr bool operator==(const Optional<T>& opt, nullopt_t) { 734 return !opt; 735 } 736 737 template <class T> 738 constexpr bool operator==(nullopt_t, const Optional<T>& opt) { 739 return !opt; 740 } 741 742 template <class T> 743 constexpr bool operator!=(const Optional<T>& opt, nullopt_t) { 744 return opt.has_value(); 745 } 746 747 template <class T> 748 constexpr bool operator!=(nullopt_t, const Optional<T>& opt) { 749 return opt.has_value(); 750 } 751 752 template <class T> 753 constexpr bool operator<(const Optional<T>& opt, nullopt_t) { 754 return false; 755 } 756 757 template <class T> 758 constexpr bool operator<(nullopt_t, const Optional<T>& opt) { 759 return opt.has_value(); 760 } 761 762 template <class T> 763 constexpr bool operator<=(const Optional<T>& opt, nullopt_t) { 764 return !opt; 765 } 766 767 template <class T> 768 constexpr bool operator<=(nullopt_t, const Optional<T>& opt) { 769 return true; 770 } 771 772 template <class T> 773 constexpr bool operator>(const Optional<T>& opt, nullopt_t) { 774 return opt.has_value(); 775 } 776 777 template <class T> 778 constexpr bool operator>(nullopt_t, const Optional<T>& opt) { 779 return false; 780 } 781 782 template <class T> 783 constexpr bool operator>=(const Optional<T>& opt, nullopt_t) { 784 return true; 785 } 786 787 template <class T> 788 constexpr bool operator>=(nullopt_t, const Optional<T>& opt) { 789 return !opt; 790 } 791 792 template <class T, class U> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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 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