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