LCOV - code coverage report
Current view: top level - src/base - optional.h (source / functions) Hit Total Coverage
Test: app.info Lines: 56 61 91.8 %
Date: 2019-04-17 Functions: 21 22 95.5 %

          Line data    Source code
       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 {
      27             :   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.
      48      331580 :   constexpr OptionalStorageBase() : empty_('\0') {}
      49             : 
      50             :   template <class... Args>
      51             :   constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
      52      726645 :       : 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.
      65       35341 :   ~OptionalStorageBase() {
      66     1690055 :     if (is_populated_) value_.~T();
      67     1654417 :   }
      68             : 
      69             :   template <class... Args>
      70        1205 :   void Init(Args&&... args) {
      71             :     DCHECK(!is_populated_);
      72       74674 :     ::new (&value_) T(std::forward<Args>(args)...);
      73       79030 :     is_populated_ = true;
      74        1205 :   }
      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    11495947 :   constexpr OptionalStorageBase() : empty_('\0') {}
      91             : 
      92             :   template <class... Args>
      93             :   constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
      94      566313 :       : 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     8781606 :     ::new (&value_) T(std::forward<Args>(args)...);
     114     8766243 :     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             : #if defined(__GNUC__) && __GNUC__ < 5
     135             : // gcc <5 does not implement std::is_trivially_copy_constructible.
     136             : // Conservatively assume false for this configuration.
     137             : // TODO(clemensh): Remove this once we drop support for gcc <5.
     138             : #define TRIVIALLY_COPY_CONSTRUCTIBLE(T) false
     139             : #define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) false
     140             : #else
     141             : #define TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
     142             :   std::is_trivially_copy_constructible<T>::value
     143             : #define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \
     144             :   std::is_trivially_move_constructible<T>::value
     145             : #endif
     146             : template <typename T, bool = TRIVIALLY_COPY_CONSTRUCTIBLE(T),
     147             :           bool = TRIVIALLY_MOVE_CONSTRUCTIBLE(T)>
     148             : #undef TRIVIALLY_COPY_CONSTRUCTIBLE
     149     1654417 : struct OptionalStorage : OptionalStorageBase<T> {
     150             :   // This is no trivially {copy,move} constructible case. Other cases are
     151             :   // defined below as specializations.
     152             : 
     153             :   // Accessing the members of template base class requires explicit
     154             :   // declaration.
     155             :   using OptionalStorageBase<T>::is_populated_;
     156             :   using OptionalStorageBase<T>::value_;
     157             :   using OptionalStorageBase<T>::Init;
     158             : 
     159             :   // Inherit constructors (specifically, the in_place constructor).
     160             :   using OptionalStorageBase<T>::OptionalStorageBase;
     161             : 
     162             :   // User defined constructor deletes the default constructor.
     163             :   // Define it explicitly.
     164             :   OptionalStorage() = default;
     165             : 
     166      162531 :   OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
     167      162796 :     if (other.is_populated_) Init(other.value_);
     168      162531 :   }
     169             : 
     170             :   OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
     171       71546 :     if (other.is_populated_) Init(std::move(other.value_));
     172             :   }
     173             : };
     174             : 
     175             : template <typename T>
     176             : struct OptionalStorage<T, true /* trivially copy constructible */,
     177             :                        false /* trivially move constructible */>
     178             :     : OptionalStorageBase<T> {
     179             :   using OptionalStorageBase<T>::is_populated_;
     180             :   using OptionalStorageBase<T>::value_;
     181             :   using OptionalStorageBase<T>::Init;
     182             :   using OptionalStorageBase<T>::OptionalStorageBase;
     183             : 
     184             :   OptionalStorage() = default;
     185             :   OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT = default;
     186             : 
     187             :   OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
     188             :     if (other.is_populated_) Init(std::move(other.value_));
     189             :   }
     190             : };
     191             : 
     192             : template <typename T>
     193             : struct OptionalStorage<T, false /* trivially copy constructible */,
     194             :                        true /* trivially move constructible */>
     195             :     : OptionalStorageBase<T> {
     196             :   using OptionalStorageBase<T>::is_populated_;
     197             :   using OptionalStorageBase<T>::value_;
     198             :   using OptionalStorageBase<T>::Init;
     199             :   using OptionalStorageBase<T>::OptionalStorageBase;
     200             : 
     201             :   OptionalStorage() = default;
     202             :   OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT = default;
     203             : 
     204             :   OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
     205             :     if (other.is_populated_) Init(other.value_);
     206             :   }
     207             : };
     208             : 
     209             : template <typename T>
     210             : struct OptionalStorage<T, true /* trivially copy constructible */,
     211             :                        true /* trivially move constructible */>
     212             :     : OptionalStorageBase<T> {
     213             :   // If both trivially {copy,move} constructible are true, it is not necessary
     214             :   // to use user-defined constructors. So, just inheriting constructors
     215             :   // from the base class works.
     216             :   using OptionalStorageBase<T>::OptionalStorageBase;
     217             : };
     218             : 
     219             : // Base class to support conditionally usable copy-/move- constructors
     220             : // and assign operators.
     221             : template <typename T>
     222             : class OptionalBase {
     223             :   // This class provides implementation rather than public API, so everything
     224             :   // should be hidden. Often we use composition, but we cannot in this case
     225             :   // because of C++ language restriction.
     226             :  protected:
     227             :   constexpr OptionalBase() = default;
     228      160486 :   constexpr OptionalBase(const OptionalBase& other) V8_NOEXCEPT = default;
     229             :   constexpr OptionalBase(OptionalBase&& other) V8_NOEXCEPT = default;
     230             : 
     231             :   template <class... Args>
     232             :   constexpr explicit OptionalBase(in_place_t, Args&&... args)
     233             :       : storage_(in_place, std::forward<Args>(args)...) {}
     234             : 
     235             :   // Implementation of converting constructors.
     236             :   template <typename U>
     237             :   explicit OptionalBase(const OptionalBase<U>& other) V8_NOEXCEPT {
     238             :     if (other.storage_.is_populated_) storage_.Init(other.storage_.value_);
     239             :   }
     240             : 
     241             :   template <typename U>
     242             :   explicit OptionalBase(OptionalBase<U>&& other) V8_NOEXCEPT {
     243             :     if (other.storage_.is_populated_)
     244             :       storage_.Init(std::move(other.storage_.value_));
     245             :   }
     246             : 
     247     1654417 :   ~OptionalBase() = default;
     248             : 
     249             :   OptionalBase& operator=(const OptionalBase& other) V8_NOEXCEPT {
     250           0 :     CopyAssign(other);
     251             :     return *this;
     252             :   }
     253             : 
     254             :   OptionalBase& operator=(OptionalBase&& other) V8_NOEXCEPT {
     255        6300 :     MoveAssign(std::move(other));
     256             :     return *this;
     257             :   }
     258             : 
     259             :   template <typename U>
     260           0 :   void CopyAssign(const OptionalBase<U>& other) {
     261        8068 :     if (other.storage_.is_populated_)
     262           0 :       InitOrAssign(other.storage_.value_);
     263             :     else
     264             :       FreeIfNeeded();
     265           0 :   }
     266             : 
     267             :   template <typename U>
     268        6300 :   void MoveAssign(OptionalBase<U>&& other) {
     269       29603 :     if (other.storage_.is_populated_)
     270         218 :       InitOrAssign(std::move(other.storage_.value_));
     271             :     else
     272          62 :       FreeIfNeeded();
     273        6300 :   }
     274             : 
     275             :   template <typename U>
     276       29195 :   void InitOrAssign(U&& value) {
     277     8805047 :     if (storage_.is_populated_)
     278      471923 :       storage_.value_ = std::forward<U>(value);
     279             :     else
     280             :       storage_.Init(std::forward<U>(value));
     281       29195 :   }
     282             : 
     283        1291 :   void FreeIfNeeded() {
     284      958129 :     if (!storage_.is_populated_) return;
     285        1337 :     storage_.value_.~T();
     286      481029 :     storage_.is_populated_ = false;
     287             :   }
     288             : 
     289             :   // For implementing conversion, allow access to other typed OptionalBase
     290             :   // class.
     291             :   template <typename U>
     292             :   friend class OptionalBase;
     293             : 
     294             :   OptionalStorage<T> storage_;
     295             : };
     296             : 
     297             : // The following {Copy,Move}{Constructible,Assignable} structs are helpers to
     298             : // implement constructor/assign-operator overloading. Specifically, if T is
     299             : // is not movable but copyable, Optional<T>'s move constructor should not
     300             : // participate in overload resolution. This inheritance trick implements that.
     301             : template <bool is_copy_constructible>
     302             : struct CopyConstructible {};
     303             : 
     304             : template <>
     305             : struct CopyConstructible<false> {
     306             :   constexpr CopyConstructible() = default;
     307             :   constexpr CopyConstructible(const CopyConstructible&) V8_NOEXCEPT = delete;
     308             :   constexpr CopyConstructible(CopyConstructible&&) V8_NOEXCEPT = default;
     309             :   CopyConstructible& operator=(const CopyConstructible&) V8_NOEXCEPT = default;
     310             :   CopyConstructible& operator=(CopyConstructible&&) V8_NOEXCEPT = default;
     311             : };
     312             : 
     313             : template <bool is_move_constructible>
     314             : struct MoveConstructible {};
     315             : 
     316             : template <>
     317             : struct MoveConstructible<false> {
     318             :   constexpr MoveConstructible() = default;
     319             :   constexpr MoveConstructible(const MoveConstructible&) V8_NOEXCEPT = default;
     320             :   constexpr MoveConstructible(MoveConstructible&&) V8_NOEXCEPT = delete;
     321             :   MoveConstructible& operator=(const MoveConstructible&) V8_NOEXCEPT = default;
     322             :   MoveConstructible& operator=(MoveConstructible&&) V8_NOEXCEPT = default;
     323             : };
     324             : 
     325             : template <bool is_copy_assignable>
     326             : struct CopyAssignable {};
     327             : 
     328             : template <>
     329             : struct CopyAssignable<false> {
     330             :   constexpr CopyAssignable() = default;
     331             :   constexpr CopyAssignable(const CopyAssignable&) V8_NOEXCEPT = default;
     332             :   constexpr CopyAssignable(CopyAssignable&&) V8_NOEXCEPT = default;
     333             :   CopyAssignable& operator=(const CopyAssignable&) V8_NOEXCEPT = delete;
     334             :   CopyAssignable& operator=(CopyAssignable&&) V8_NOEXCEPT = default;
     335             : };
     336             : 
     337             : template <bool is_move_assignable>
     338             : struct MoveAssignable {};
     339             : 
     340             : template <>
     341             : struct MoveAssignable<false> {
     342             :   constexpr MoveAssignable() = default;
     343             :   constexpr MoveAssignable(const MoveAssignable&) V8_NOEXCEPT = default;
     344             :   constexpr MoveAssignable(MoveAssignable&&) V8_NOEXCEPT = default;
     345             :   MoveAssignable& operator=(const MoveAssignable&) V8_NOEXCEPT = default;
     346             :   MoveAssignable& operator=(MoveAssignable&&) V8_NOEXCEPT = delete;
     347             : };
     348             : 
     349             : // Helper to conditionally enable converting constructors and assign operators.
     350             : template <typename T, typename U>
     351             : struct IsConvertibleFromOptional
     352             :     : std::integral_constant<
     353             :           bool, std::is_constructible<T, Optional<U>&>::value ||
     354             :                     std::is_constructible<T, const Optional<U>&>::value ||
     355             :                     std::is_constructible<T, Optional<U>&&>::value ||
     356             :                     std::is_constructible<T, const Optional<U>&&>::value ||
     357             :                     std::is_convertible<Optional<U>&, T>::value ||
     358             :                     std::is_convertible<const Optional<U>&, T>::value ||
     359             :                     std::is_convertible<Optional<U>&&, T>::value ||
     360             :                     std::is_convertible<const Optional<U>&&, T>::value> {};
     361             : 
     362             : template <typename T, typename U>
     363             : struct IsAssignableFromOptional
     364             :     : std::integral_constant<
     365             :           bool, IsConvertibleFromOptional<T, U>::value ||
     366             :                     std::is_assignable<T&, Optional<U>&>::value ||
     367             :                     std::is_assignable<T&, const Optional<U>&>::value ||
     368             :                     std::is_assignable<T&, Optional<U>&&>::value ||
     369             :                     std::is_assignable<T&, const Optional<U>&&>::value> {};
     370             : 
     371             : // Forward compatibility for C++17.
     372             : // Introduce one more deeper nested namespace to avoid leaking using std::swap.
     373             : namespace swappable_impl {
     374             : using std::swap;
     375             : 
     376             : struct IsSwappableImpl {
     377             :   // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
     378             :   // is available for T. Otherwise, Check's overload resolution falls back
     379             :   // to Check(...) declared below thanks to SFINAE, so returns false_type.
     380             :   template <typename T>
     381             :   static auto Check(int i)
     382             :       -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
     383             : 
     384             :   template <typename T>
     385             :   static std::false_type Check(...);
     386             : };
     387             : }  // namespace swappable_impl
     388             : 
     389             : template <typename T>
     390             : struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
     391             : 
     392             : // Forward compatibility for C++20.
     393             : template <typename T>
     394             : using RemoveCvRefT =
     395             :     typename std::remove_cv<typename std::remove_reference<T>::type>::type;
     396             : 
     397             : }  // namespace internal
     398             : 
     399             : // On Windows, by default, empty-base class optimization does not work,
     400             : // which means even if the base class is empty struct, it still consumes one
     401             : // byte for its body. __declspec(empty_bases) enables the optimization.
     402             : // cf)
     403             : // https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
     404             : #ifdef OS_WIN
     405             : #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
     406             : #else
     407             : #define OPTIONAL_DECLSPEC_EMPTY_BASES
     408             : #endif
     409             : 
     410             : // base::Optional is a Chromium version of the C++17 optional class:
     411             : // std::optional documentation:
     412             : // http://en.cppreference.com/w/cpp/utility/optional
     413             : // Chromium documentation:
     414             : // https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
     415             : //
     416             : // These are the differences between the specification and the implementation:
     417             : // - Constructors do not use 'constexpr' as it is a C++14 extension.
     418             : // - 'constexpr' might be missing in some places for reasons specified locally.
     419             : // - No exceptions are thrown, because they are banned from Chromium.
     420             : //   All copy/move constructors or assignment operators are marked V8_NOEXCEPT.
     421             : // - All the non-members are in the 'base' namespace instead of 'std'.
     422             : //
     423             : // Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
     424             : // T's constructor (specifically via IsConvertibleFromOptional), and in the
     425             : // check whether T can be constructible from Optional<T>, which is recursive
     426             : // so it does not work. As of Feb 2018, std::optional C++17 implementation in
     427             : // both clang and gcc has same limitation. MSVC SFINAE looks to have different
     428             : // behavior, but anyway it reports an error, too.
     429             : template <typename T>
     430        6300 : class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
     431             :     : public internal::OptionalBase<T>,
     432             :       public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
     433             :       public internal::MoveConstructible<std::is_move_constructible<T>::value>,
     434             :       public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
     435             :                                       std::is_copy_assignable<T>::value>,
     436             :       public internal::MoveAssignable<std::is_move_constructible<T>::value &&
     437             :                                       std::is_move_assignable<T>::value> {
     438             :  public:
     439             : #undef OPTIONAL_DECLSPEC_EMPTY_BASES
     440             :   using value_type = T;
     441             : 
     442             :   // Defer default/copy/move constructor implementation to OptionalBase.
     443             :   constexpr Optional() = default;
     444             :   constexpr Optional(const Optional& other) V8_NOEXCEPT = default;
     445             :   constexpr Optional(Optional&& other) V8_NOEXCEPT = default;
     446             : 
     447             :   constexpr Optional(nullopt_t) {}  // NOLINT(runtime/explicit)
     448             : 
     449             :   // Converting copy constructor. "explicit" only if
     450             :   // std::is_convertible<const U&, T>::value is false. It is implemented by
     451             :   // declaring two almost same constructors, but that condition in enable_if
     452             :   // is different, so that either one is chosen, thanks to SFINAE.
     453             :   template <typename U,
     454             :             typename std::enable_if<
     455             :                 std::is_constructible<T, const U&>::value &&
     456             :                     !internal::IsConvertibleFromOptional<T, U>::value &&
     457             :                     std::is_convertible<const U&, T>::value,
     458             :                 bool>::type = false>
     459             :   Optional(const Optional<U>& other) V8_NOEXCEPT
     460             :       : internal::OptionalBase<T>(other) {}
     461             : 
     462             :   template <typename U,
     463             :             typename std::enable_if<
     464             :                 std::is_constructible<T, const U&>::value &&
     465             :                     !internal::IsConvertibleFromOptional<T, U>::value &&
     466             :                     !std::is_convertible<const U&, T>::value,
     467             :                 bool>::type = false>
     468             :   explicit Optional(const Optional<U>& other) V8_NOEXCEPT
     469             :       : internal::OptionalBase<T>(other) {}
     470             : 
     471             :   // Converting move constructor. Similar to converting copy constructor,
     472             :   // declaring two (explicit and non-explicit) constructors.
     473             :   template <typename U,
     474             :             typename std::enable_if<
     475             :                 std::is_constructible<T, U&&>::value &&
     476             :                     !internal::IsConvertibleFromOptional<T, U>::value &&
     477             :                     std::is_convertible<U&&, T>::value,
     478             :                 bool>::type = false>
     479             :   Optional(Optional<U>&& other) V8_NOEXCEPT
     480             :       : internal::OptionalBase<T>(std::move(other)) {}
     481             : 
     482             :   template <typename U,
     483             :             typename std::enable_if<
     484             :                 std::is_constructible<T, U&&>::value &&
     485             :                     !internal::IsConvertibleFromOptional<T, U>::value &&
     486             :                     !std::is_convertible<U&&, T>::value,
     487             :                 bool>::type = false>
     488             :   explicit Optional(Optional<U>&& other) V8_NOEXCEPT
     489             :       : internal::OptionalBase<T>(std::move(other)) {}
     490             : 
     491             :   template <class... Args>
     492             :   constexpr explicit Optional(in_place_t, Args&&... args)
     493             :       : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
     494             : 
     495             :   template <class U, class... Args,
     496             :             class = typename std::enable_if<std::is_constructible<
     497             :                 value_type, std::initializer_list<U>&, Args...>::value>::type>
     498             :   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
     499             :                               Args&&... args)
     500             :       : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
     501             : 
     502             :   // Forward value constructor. Similar to converting constructors,
     503             :   // conditionally explicit.
     504             :   template <
     505             :       typename U = value_type,
     506             :       typename std::enable_if<
     507             :           std::is_constructible<T, U&&>::value &&
     508             :               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
     509             :               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
     510             :               std::is_convertible<U&&, T>::value,
     511             :           bool>::type = false>
     512             :   constexpr Optional(U&& value)  // NOLINT(runtime/explicit)
     513             :       : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
     514             : 
     515             :   template <
     516             :       typename U = value_type,
     517             :       typename std::enable_if<
     518             :           std::is_constructible<T, U&&>::value &&
     519             :               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
     520             :               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
     521             :               !std::is_convertible<U&&, T>::value,
     522             :           bool>::type = false>
     523             :   constexpr explicit Optional(U&& value)
     524             :       : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
     525             : 
     526     1654417 :   ~Optional() = default;
     527             : 
     528             :   // Defer copy-/move- assign operator implementation to OptionalBase.
     529             :   Optional& operator=(const Optional& other) V8_NOEXCEPT = default;
     530             :   Optional& operator=(Optional&& other) V8_NOEXCEPT = default;
     531             : 
     532             :   Optional& operator=(nullopt_t) {
     533        1229 :     FreeIfNeeded();
     534             :     return *this;
     535             :   }
     536             : 
     537             :   // Perfect-forwarded assignment.
     538             :   template <typename U>
     539             :   typename std::enable_if<
     540             :       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
     541             :           std::is_constructible<T, U>::value &&
     542             :           std::is_assignable<T&, U>::value &&
     543             :           (!std::is_scalar<T>::value ||
     544             :            !std::is_same<typename std::decay<U>::type, T>::value),
     545             :       Optional&>::type
     546             :   operator=(U&& value) V8_NOEXCEPT {
     547       22521 :     InitOrAssign(std::forward<U>(value));
     548             :     return *this;
     549             :   }
     550             : 
     551             :   // Copy assign the state of other.
     552             :   template <typename U>
     553             :   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
     554             :                               std::is_constructible<T, const U&>::value &&
     555             :                               std::is_assignable<T&, const U&>::value,
     556             :                           Optional&>::type
     557             :   operator=(const Optional<U>& other) V8_NOEXCEPT {
     558             :     CopyAssign(other);
     559             :     return *this;
     560             :   }
     561             : 
     562             :   // Move assign the state of other.
     563             :   template <typename U>
     564             :   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
     565             :                               std::is_constructible<T, U>::value &&
     566             :                               std::is_assignable<T&, U>::value,
     567             :                           Optional&>::type
     568             :   operator=(Optional<U>&& other) V8_NOEXCEPT {
     569             :     MoveAssign(std::move(other));
     570             :     return *this;
     571             :   }
     572             : 
     573             :   const T* operator->() const {
     574             :     DCHECK(storage_.is_populated_);
     575             :     return &storage_.value_;
     576             :   }
     577             : 
     578             :   T* operator->() {
     579             :     DCHECK(storage_.is_populated_);
     580             :     return &storage_.value_;
     581             :   }
     582             : 
     583             :   const T& operator*() const & {
     584             :     DCHECK(storage_.is_populated_);
     585       35362 :     return storage_.value_;
     586             :   }
     587             : 
     588             :   T& operator*() & {
     589             :     DCHECK(storage_.is_populated_);
     590       97613 :     return storage_.value_;
     591             :   }
     592             : 
     593             :   const T&& operator*() const && {
     594             :     DCHECK(storage_.is_populated_);
     595             :     return std::move(storage_.value_);
     596             :   }
     597             : 
     598             :   T&& operator*() && {
     599             :     DCHECK(storage_.is_populated_);
     600             :     return std::move(storage_.value_);
     601             :   }
     602             : 
     603             :   constexpr explicit operator bool() const { return storage_.is_populated_; }
     604             : 
     605             :   constexpr bool has_value() const { return storage_.is_populated_; }
     606             : 
     607             :   T& value() & {
     608      949231 :     CHECK(storage_.is_populated_);
     609       83830 :     return storage_.value_;
     610             :   }
     611             : 
     612             :   const T& value() const & {
     613     1072479 :     CHECK(storage_.is_populated_);
     614           0 :     return storage_.value_;
     615             :   }
     616             : 
     617             :   T&& value() && {
     618       12340 :     CHECK(storage_.is_populated_);
     619             :     return std::move(storage_.value_);
     620             :   }
     621             : 
     622             :   const T&& value() const && {
     623             :     CHECK(storage_.is_populated_);
     624             :     return std::move(storage_.value_);
     625             :   }
     626             : 
     627             :   template <class U>
     628             :   constexpr T value_or(U&& default_value) const & {
     629             :     // TODO(mlamouri): add the following assert when possible:
     630             :     // static_assert(std::is_copy_constructible<T>::value,
     631             :     //               "T must be copy constructible");
     632             :     static_assert(std::is_convertible<U, T>::value,
     633             :                   "U must be convertible to T");
     634             :     return storage_.is_populated_
     635             :                ? storage_.value_
     636             :                : static_cast<T>(std::forward<U>(default_value));
     637             :   }
     638             : 
     639             :   template <class U>
     640             :   T value_or(U&& default_value) && {
     641             :     // TODO(mlamouri): add the following assert when possible:
     642             :     // static_assert(std::is_move_constructible<T>::value,
     643             :     //               "T must be move constructible");
     644             :     static_assert(std::is_convertible<U, T>::value,
     645             :                   "U must be convertible to T");
     646             :     return storage_.is_populated_
     647             :                ? std::move(storage_.value_)
     648             :                : static_cast<T>(std::forward<U>(default_value));
     649             :   }
     650             : 
     651             :   void swap(Optional& other) {
     652             :     if (!storage_.is_populated_ && !other.storage_.is_populated_) return;
     653             : 
     654             :     if (storage_.is_populated_ != other.storage_.is_populated_) {
     655             :       if (storage_.is_populated_) {
     656             :         other.storage_.Init(std::move(storage_.value_));
     657             :         FreeIfNeeded();
     658             :       } else {
     659             :         storage_.Init(std::move(other.storage_.value_));
     660             :         other.FreeIfNeeded();
     661             :       }
     662             :       return;
     663             :     }
     664             : 
     665             :     DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
     666             :     using std::swap;
     667             :     swap(**this, *other);
     668             :   }
     669             : 
     670             :   void reset() { FreeIfNeeded(); }
     671             : 
     672             :   template <class... Args>
     673        9247 :   T& emplace(Args&&... args) {
     674             :     FreeIfNeeded();
     675        1205 :     storage_.Init(std::forward<Args>(args)...);
     676        9247 :     return storage_.value_;
     677             :   }
     678             : 
     679             :   template <class U, class... Args>
     680             :   typename std::enable_if<
     681             :       std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
     682             :       T&>::type
     683             :   emplace(std::initializer_list<U> il, Args&&... args) {
     684             :     FreeIfNeeded();
     685             :     storage_.Init(il, std::forward<Args>(args)...);
     686             :     return storage_.value_;
     687             :   }
     688             : 
     689             :  private:
     690             :   // Accessing template base class's protected member needs explicit
     691             :   // declaration to do so.
     692             :   using internal::OptionalBase<T>::CopyAssign;
     693             :   using internal::OptionalBase<T>::FreeIfNeeded;
     694             :   using internal::OptionalBase<T>::InitOrAssign;
     695             :   using internal::OptionalBase<T>::MoveAssign;
     696             :   using internal::OptionalBase<T>::storage_;
     697             : };
     698             : 
     699             : // Here after defines comparation operators. The definition follows
     700             : // http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
     701             : // while bool() casting is replaced by has_value() to meet the chromium
     702             : // style guide.
     703             : template <class T, class U>
     704             : bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
     705        2876 :   if (lhs.has_value() != rhs.has_value()) return false;
     706        2485 :   if (!lhs.has_value()) return true;
     707        1909 :   return *lhs == *rhs;
     708             : }
     709             : 
     710             : template <class T, class U>
     711             : bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
     712        1588 :   if (lhs.has_value() != rhs.has_value()) return true;
     713        1588 :   if (!lhs.has_value()) return false;
     714        1588 :   return *lhs != *rhs;
     715             : }
     716             : 
     717             : template <class T, class U>
     718             : bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
     719             :   if (!rhs.has_value()) return false;
     720             :   if (!lhs.has_value()) return true;
     721             :   return *lhs < *rhs;
     722             : }
     723             : 
     724             : template <class T, class U>
     725             : bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
     726             :   if (!lhs.has_value()) return true;
     727             :   if (!rhs.has_value()) return false;
     728             :   return *lhs <= *rhs;
     729             : }
     730             : 
     731             : template <class T, class U>
     732             : bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
     733             :   if (!lhs.has_value()) return false;
     734             :   if (!rhs.has_value()) return true;
     735             :   return *lhs > *rhs;
     736             : }
     737             : 
     738             : template <class T, class U>
     739             : bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
     740             :   if (!rhs.has_value()) return true;
     741             :   if (!lhs.has_value()) return false;
     742             :   return *lhs >= *rhs;
     743             : }
     744             : 
     745             : template <class T>
     746             : constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
     747         438 :   return !opt;
     748             : }
     749             : 
     750             : template <class T>
     751             : constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
     752             :   return !opt;
     753             : }
     754             : 
     755             : template <class T>
     756             : constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
     757             :   return opt.has_value();
     758             : }
     759             : 
     760             : template <class T>
     761             : constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
     762             :   return opt.has_value();
     763             : }
     764             : 
     765             : template <class T>
     766             : constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
     767             :   return false;
     768             : }
     769             : 
     770             : template <class T>
     771             : constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
     772             :   return opt.has_value();
     773             : }
     774             : 
     775             : template <class T>
     776             : constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
     777             :   return !opt;
     778             : }
     779             : 
     780             : template <class T>
     781             : constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
     782             :   return true;
     783             : }
     784             : 
     785             : template <class T>
     786             : constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
     787             :   return opt.has_value();
     788             : }
     789             : 
     790             : template <class T>
     791             : constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
     792             :   return false;
     793             : }
     794             : 
     795             : template <class T>
     796             : constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
     797             :   return true;
     798             : }
     799             : 
     800             : template <class T>
     801             : constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
     802             :   return !opt;
     803             : }
     804             : 
     805             : template <class T, class U>
     806             : constexpr bool operator==(const Optional<T>& opt, const U& value) {
     807           2 :   return opt.has_value() ? *opt == value : false;
     808             : }
     809             : 
     810             : template <class T, class U>
     811             : constexpr bool operator==(const U& value, const Optional<T>& opt) {
     812             :   return opt.has_value() ? value == *opt : false;
     813             : }
     814             : 
     815             : template <class T, class U>
     816             : constexpr bool operator!=(const Optional<T>& opt, const U& value) {
     817             :   return opt.has_value() ? *opt != value : true;
     818             : }
     819             : 
     820             : template <class T, class U>
     821             : constexpr bool operator!=(const U& value, const Optional<T>& opt) {
     822             :   return opt.has_value() ? value != *opt : true;
     823             : }
     824             : 
     825             : template <class T, class U>
     826             : constexpr bool operator<(const Optional<T>& opt, const U& value) {
     827             :   return opt.has_value() ? *opt < value : true;
     828             : }
     829             : 
     830             : template <class T, class U>
     831             : constexpr bool operator<(const U& value, const Optional<T>& opt) {
     832             :   return opt.has_value() ? value < *opt : false;
     833             : }
     834             : 
     835             : template <class T, class U>
     836             : constexpr bool operator<=(const Optional<T>& opt, const U& value) {
     837             :   return opt.has_value() ? *opt <= value : true;
     838             : }
     839             : 
     840             : template <class T, class U>
     841             : constexpr bool operator<=(const U& value, const Optional<T>& opt) {
     842             :   return opt.has_value() ? value <= *opt : false;
     843             : }
     844             : 
     845             : template <class T, class U>
     846             : constexpr bool operator>(const Optional<T>& opt, const U& value) {
     847             :   return opt.has_value() ? *opt > value : false;
     848             : }
     849             : 
     850             : template <class T, class U>
     851             : constexpr bool operator>(const U& value, const Optional<T>& opt) {
     852             :   return opt.has_value() ? value > *opt : true;
     853             : }
     854             : 
     855             : template <class T, class U>
     856             : constexpr bool operator>=(const Optional<T>& opt, const U& value) {
     857             :   return opt.has_value() ? *opt >= value : false;
     858             : }
     859             : 
     860             : template <class T, class U>
     861             : constexpr bool operator>=(const U& value, const Optional<T>& opt) {
     862             :   return opt.has_value() ? value >= *opt : true;
     863             : }
     864             : 
     865             : template <class T>
     866             : constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
     867             :   return Optional<typename std::decay<T>::type>(std::forward<T>(value));
     868             : }
     869             : 
     870             : template <class T, class... Args>
     871             : constexpr Optional<T> make_optional(Args&&... args) {
     872             :   return Optional<T>(in_place, std::forward<Args>(args)...);
     873             : }
     874             : 
     875             : template <class T, class U, class... Args>
     876             : constexpr Optional<T> make_optional(std::initializer_list<U> il,
     877             :                                     Args&&... args) {
     878             :   return Optional<T>(in_place, il, std::forward<Args>(args)...);
     879             : }
     880             : 
     881             : // Partial specialization for a function template is not allowed. Also, it is
     882             : // not allowed to add overload function to std namespace, while it is allowed
     883             : // to specialize the template in std. Thus, swap() (kind of) overloading is
     884             : // defined in base namespace, instead.
     885             : template <class T>
     886             : typename std::enable_if<std::is_move_constructible<T>::value &&
     887             :                         internal::IsSwappable<T>::value>::type
     888             : swap(Optional<T>& lhs, Optional<T>& rhs) {
     889             :   lhs.swap(rhs);
     890             : }
     891             : 
     892             : }  // namespace base
     893             : }  // namespace v8
     894             : 
     895             : #endif  // V8_BASE_OPTIONAL_H_

Generated by: LCOV version 1.10