tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Maybe.h (36308B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* A class for optional values and in-place lazy construction. */
      8 
      9 #ifndef mozilla_Maybe_h
     10 #define mozilla_Maybe_h
     11 
     12 #include <functional>
     13 #include <new>  // for placement new
     14 #include <ostream>
     15 #include <type_traits>
     16 #include <utility>
     17 
     18 #include "mozilla/Assertions.h"
     19 #include "mozilla/Attributes.h"
     20 #include "mozilla/MaybeStorageBase.h"
     21 #include "mozilla/MemoryChecking.h"
     22 #include "mozilla/OperatorNewExtensions.h"
     23 #include "mozilla/Poison.h"
     24 #include "mozilla/ThreadSafety.h"
     25 
     26 class nsCycleCollectionTraversalCallback;
     27 
     28 template <typename T>
     29 inline void CycleCollectionNoteChild(
     30    nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName,
     31    uint32_t aFlags);
     32 
     33 namespace mozilla {
     34 
     35 struct Nothing {};
     36 
     37 constexpr bool operator==(const Nothing&, const Nothing&) { return true; }
     38 
     39 template <class T>
     40 class Maybe;
     41 
     42 namespace detail {
     43 
     44 // You would think that poisoning Maybe instances could just be a call
     45 // to mozWritePoison.  Unfortunately, using a simple call to
     46 // mozWritePoison generates poor code on MSVC for small structures.  The
     47 // generated code contains (always not-taken) branches and does a bunch
     48 // of setup for `rep stos{l,q}`, even though we know at compile time
     49 // exactly how many words we're poisoning.  Instead, we're going to
     50 // force MSVC to generate the code we want via recursive templates.
     51 
     52 // Write the given poisonValue into p at offset*sizeof(uintptr_t).
     53 template <size_t offset>
     54 inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) {
     55  memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue,
     56         sizeof(poisonValue));
     57 }
     58 
     59 template <size_t Offset, size_t NOffsets>
     60 struct InlinePoisoner {
     61  static void poison(void* p, const uintptr_t poisonValue) {
     62    WritePoisonAtOffset<Offset>(p, poisonValue);
     63    InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue);
     64  }
     65 };
     66 
     67 template <size_t N>
     68 struct InlinePoisoner<N, N> {
     69  static void poison(void*, const uintptr_t) {
     70    // All done!
     71  }
     72 };
     73 
     74 // We can't generate inline code for large structures, though, because we'll
     75 // blow out recursive template instantiation limits, and the code would be
     76 // bloated to boot.  So provide a fallback to the out-of-line poisoner.
     77 template <size_t ObjectSize>
     78 struct OutOfLinePoisoner {
     79  static MOZ_NEVER_INLINE void poison(void* p, const uintptr_t) {
     80    mozWritePoison(p, ObjectSize);
     81  }
     82 };
     83 
     84 template <typename T>
     85 inline void PoisonObject(T* p) {
     86  const uintptr_t POISON = mozPoisonValue();
     87  std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)),
     88                     InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
     89                     OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON);
     90 }
     91 
     92 template <typename T>
     93 struct MaybePoisoner {
     94  static const size_t N = sizeof(T);
     95 
     96  static void poison(void* aPtr) {
     97 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     98    if (N >= sizeof(uintptr_t)) {
     99      PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr));
    100    }
    101 #endif
    102    MOZ_MAKE_MEM_UNDEFINED(aPtr, N);
    103  }
    104 };
    105 
    106 template <typename T,
    107          bool TriviallyDestructibleAndCopyable =
    108              IsTriviallyDestructibleAndCopyable<T>,
    109          bool Copyable = std::is_copy_constructible_v<T>,
    110          bool Movable = std::is_move_constructible_v<T>>
    111 class Maybe_CopyMove_Enabler;
    112 
    113 #define MOZ_MAYBE_COPY_OPS()                                                \
    114  Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) {            \
    115    if (downcast(aOther).isSome()) {                                        \
    116      downcast(*this).emplace(*downcast(aOther));                           \
    117    }                                                                       \
    118  }                                                                         \
    119                                                                            \
    120  Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \
    121    return downcast(*this).template operator= <T>(downcast(aOther));        \
    122  }
    123 
    124 #define MOZ_MAYBE_MOVE_OPS()                                             \
    125  constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {    \
    126    if (downcast(aOther).isSome()) {                                     \
    127      downcast(*this).emplace(std::move(*downcast(aOther)));             \
    128      downcast(aOther).reset();                                          \
    129    }                                                                    \
    130  }                                                                      \
    131                                                                         \
    132  constexpr Maybe_CopyMove_Enabler& operator=(                           \
    133      Maybe_CopyMove_Enabler&& aOther) {                                 \
    134    downcast(*this).template operator= <T>(std::move(downcast(aOther))); \
    135                                                                         \
    136    return *this;                                                        \
    137  }
    138 
    139 #define MOZ_MAYBE_DOWNCAST()                                          \
    140  static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
    141    return static_cast<Maybe<T>&>(aObj);                              \
    142  }                                                                   \
    143  static constexpr const Maybe<T>& downcast(                          \
    144      const Maybe_CopyMove_Enabler& aObj) {                           \
    145    return static_cast<const Maybe<T>&>(aObj);                        \
    146  }
    147 
    148 template <typename T>
    149 class Maybe_CopyMove_Enabler<T, true, true, true> {
    150 public:
    151  Maybe_CopyMove_Enabler() = default;
    152 
    153  Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
    154  Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
    155  constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
    156    downcast(aOther).reset();
    157  }
    158  constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
    159    downcast(aOther).reset();
    160    return *this;
    161  }
    162 
    163 private:
    164  MOZ_MAYBE_DOWNCAST()
    165 };
    166 
    167 template <typename T>
    168 class Maybe_CopyMove_Enabler<T, true, false, true> {
    169 public:
    170  Maybe_CopyMove_Enabler() = default;
    171 
    172  Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
    173  Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
    174  constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
    175    downcast(aOther).reset();
    176  }
    177  constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
    178    downcast(aOther).reset();
    179    return *this;
    180  }
    181 
    182 private:
    183  MOZ_MAYBE_DOWNCAST()
    184 };
    185 
    186 template <typename T>
    187 class Maybe_CopyMove_Enabler<T, false, true, true> {
    188 public:
    189  Maybe_CopyMove_Enabler() = default;
    190 
    191  MOZ_MAYBE_COPY_OPS()
    192  MOZ_MAYBE_MOVE_OPS()
    193 
    194 private:
    195  MOZ_MAYBE_DOWNCAST()
    196 };
    197 
    198 template <typename T>
    199 class Maybe_CopyMove_Enabler<T, false, false, true> {
    200 public:
    201  Maybe_CopyMove_Enabler() = default;
    202 
    203  Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
    204  Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
    205  MOZ_MAYBE_MOVE_OPS()
    206 
    207 private:
    208  MOZ_MAYBE_DOWNCAST()
    209 };
    210 
    211 template <typename T>
    212 class Maybe_CopyMove_Enabler<T, false, true, false> {
    213 public:
    214  Maybe_CopyMove_Enabler() = default;
    215 
    216  MOZ_MAYBE_COPY_OPS()
    217  Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
    218  Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
    219 
    220 private:
    221  MOZ_MAYBE_DOWNCAST()
    222 };
    223 
    224 template <typename T, bool TriviallyDestructibleAndCopyable>
    225 class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false,
    226                             false> {
    227 public:
    228  Maybe_CopyMove_Enabler() = default;
    229 
    230  Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
    231  Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
    232  Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
    233  Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
    234 };
    235 
    236 #undef MOZ_MAYBE_COPY_OPS
    237 #undef MOZ_MAYBE_MOVE_OPS
    238 #undef MOZ_MAYBE_DOWNCAST
    239 
    240 template <typename T, bool TriviallyDestructibleAndCopyable =
    241                          IsTriviallyDestructibleAndCopyable<T>>
    242 struct MaybeStorage;
    243 
    244 template <typename T>
    245 struct MaybeStorage<T, false> : MaybeStorageBase<T> {
    246 protected:
    247  char mIsSome = false;  // not bool -- guarantees minimal space consumption
    248 
    249  constexpr MaybeStorage() = default;
    250  explicit MaybeStorage(const T& aVal)
    251      : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
    252  explicit MaybeStorage(T&& aVal)
    253      : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
    254 
    255  template <typename... Args>
    256  explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
    257      : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
    258        mIsSome{true} {}
    259 
    260 public:
    261  // Copy and move operations are no-ops, since copying is moving is implemented
    262  // by Maybe_CopyMove_Enabler.
    263 
    264  MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {}
    265  MaybeStorage& operator=(const MaybeStorage&) { return *this; }
    266  MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {}
    267  MaybeStorage& operator=(MaybeStorage&&) { return *this; }
    268 
    269  ~MaybeStorage() {
    270    if (mIsSome) {
    271      this->addr()->T::~T();
    272    }
    273  }
    274 };
    275 
    276 template <typename T>
    277 struct MaybeStorage<T, true> : MaybeStorageBase<T> {
    278 protected:
    279  char mIsSome = false;  // not bool -- guarantees minimal space consumption
    280 
    281  constexpr MaybeStorage() = default;
    282  constexpr explicit MaybeStorage(const T& aVal)
    283      : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
    284  constexpr explicit MaybeStorage(T&& aVal)
    285      : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
    286 
    287  template <typename... Args>
    288  constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
    289      : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
    290        mIsSome{true} {}
    291 };
    292 
    293 template <typename T>
    294 struct IsMaybeImpl : std::false_type {};
    295 
    296 template <typename T>
    297 struct IsMaybeImpl<Maybe<T>> : std::true_type {};
    298 
    299 template <typename T>
    300 using IsMaybe = IsMaybeImpl<std::decay_t<T>>;
    301 
    302 }  // namespace detail
    303 
    304 template <typename T, typename U = std::remove_cv_t<std::remove_reference_t<T>>>
    305 constexpr Maybe<U> Some(T&& aValue);
    306 
    307 /*
    308 * Maybe is a container class which contains either zero or one elements. It
    309 * serves two roles. It can represent values which are *semantically* optional,
    310 * augmenting a type with an explicit 'Nothing' value. In this role, it provides
    311 * methods that make it easy to work with values that may be missing, along with
    312 * equality and comparison operators so that Maybe values can be stored in
    313 * containers. Maybe values can be constructed conveniently in expressions using
    314 * type inference, as follows:
    315 *
    316 *   void doSomething(Maybe<Foo> aFoo) {
    317 *     if (aFoo)                  // Make sure that aFoo contains a value...
    318 *       aFoo->takeAction();      // and then use |aFoo->| to access it.
    319 *   }                            // |*aFoo| also works!
    320 *
    321 *   doSomething(Nothing());      // Passes a Maybe<Foo> containing no value.
    322 *   doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
    323 *
    324 * You'll note that it's important to check whether a Maybe contains a value
    325 * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
    326 * can avoid these checks, and sometimes write more readable code, using
    327 * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
    328 * in the Maybe and provide a default for the 'Nothing' case.  You can also use
    329 * |apply()| to call a function only if the Maybe holds a value, and |map()| to
    330 * transform the value in the Maybe, returning another Maybe with a possibly
    331 * different type.
    332 *
    333 * Maybe's other role is to support lazily constructing objects without using
    334 * dynamic storage. A Maybe directly contains storage for a value, but it's
    335 * empty by default. |emplace()|, as mentioned above, can be used to construct a
    336 * value in Maybe's storage.  The value a Maybe contains can be destroyed by
    337 * calling |reset()|; this will happen automatically if a Maybe is destroyed
    338 * while holding a value.
    339 *
    340 * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
    341 * value meaning 'Nothing' and any other value meaning 'Some'. You can convert
    342 * from such a pointer to a Maybe value using 'ToMaybe()'.
    343 *
    344 * Maybe is inspired by similar types in the standard library of many other
    345 * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
    346 * very similar to std::optional, which was proposed for C++14 and originated in
    347 * Boost. The most important differences between Maybe and std::optional are:
    348 *
    349 *   - std::optional<T> may be compared with T. We deliberately forbid that.
    350 *   - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
    351 *     lacks corresponding methods for |refOr()| and |ptrOr()|.
    352 *   - std::optional lacks |map()| and |apply()|, making it less suitable for
    353 *     functional-style code.
    354 *   - std::optional lacks many convenience functions that Maybe has. Most
    355 *     unfortunately, it lacks equivalents of the type-inferred constructor
    356 *     functions |Some()| and |Nothing()|.
    357 */
    358 template <class T>
    359 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_GSL_OWNER Maybe
    360    : private detail::MaybeStorage<T>,
    361      public detail::Maybe_CopyMove_Enabler<T> {
    362  template <typename, bool, bool, bool>
    363  friend class detail::Maybe_CopyMove_Enabler;
    364 
    365  template <typename U, typename V>
    366  friend constexpr Maybe<V> Some(U&& aValue);
    367 
    368  struct SomeGuard {};
    369 
    370  template <typename U>
    371  constexpr Maybe(U&& aValue, SomeGuard)
    372      : detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
    373 
    374  using detail::MaybeStorage<T>::mIsSome;
    375  using detail::MaybeStorage<T>::mStorage;
    376 
    377  void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
    378 
    379 public:
    380  using ValueType = T;
    381 
    382  MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
    383 
    384  MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
    385 
    386  template <typename... Args>
    387  constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
    388      : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
    389 
    390  /**
    391   * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
    392   * a const U&.
    393   */
    394  template <typename U,
    395            std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
    396  MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
    397    if (aOther.isSome()) {
    398      emplace(*aOther);
    399    }
    400  }
    401 
    402  template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
    403                                         bool> = true>
    404  explicit Maybe(const Maybe<U>& aOther) = delete;
    405 
    406  /**
    407   * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from
    408   * a U&&.
    409   */
    410  template <typename U,
    411            std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
    412  MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
    413    if (aOther.isSome()) {
    414      emplace(std::move(*aOther));
    415      aOther.reset();
    416    }
    417  }
    418  template <typename U,
    419            std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
    420  explicit Maybe(Maybe<U>&& aOther) = delete;
    421 
    422  template <typename U,
    423            std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
    424  Maybe& operator=(const Maybe<U>& aOther) {
    425    if (aOther.isSome()) {
    426      if (mIsSome) {
    427        ref() = aOther.ref();
    428      } else {
    429        emplace(*aOther);
    430      }
    431    } else {
    432      reset();
    433    }
    434    return *this;
    435  }
    436 
    437  template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
    438                                         bool> = true>
    439  Maybe& operator=(const Maybe<U>& aOther) = delete;
    440 
    441  template <typename U,
    442            std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
    443  Maybe& operator=(Maybe<U>&& aOther) {
    444    if (aOther.isSome()) {
    445      if (mIsSome) {
    446        ref() = std::move(aOther.ref());
    447      } else {
    448        emplace(std::move(*aOther));
    449      }
    450      aOther.reset();
    451    } else {
    452      reset();
    453    }
    454 
    455    return *this;
    456  }
    457 
    458  template <typename U,
    459            std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
    460  Maybe& operator=(Maybe<U>&& aOther) = delete;
    461 
    462  constexpr Maybe& operator=(Nothing) {
    463    reset();
    464    return *this;
    465  }
    466 
    467  /* Methods that check whether this Maybe contains a value */
    468  constexpr explicit operator bool() const { return isSome(); }
    469  constexpr bool isSome() const { return mIsSome; }
    470  constexpr bool isNothing() const { return !mIsSome; }
    471 
    472  /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
    473   */
    474  constexpr T value() const&;
    475  constexpr T value() &&;
    476  constexpr T value() const&&;
    477 
    478  /**
    479   * Move the contents of this Maybe<T> out of internal storage and return it
    480   * without calling the destructor. The internal storage is also reset to
    481   * avoid multiple calls. Unsafe unless |isSome()|.
    482   */
    483  constexpr T extract() {
    484    MOZ_RELEASE_ASSERT(isSome());
    485    T v = std::move(mStorage.val);
    486    reset();
    487    return v;
    488  }
    489 
    490  /**
    491   * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T>
    492   * and leaving |Nothing()| in its place.
    493   */
    494  Maybe<T> take() { return std::exchange(*this, Nothing()); }
    495 
    496  /*
    497   * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
    498   * the default value provided.
    499   *
    500   * Note: If the value passed to aDefault is not the result of a trivial
    501   * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|,
    502   * use |valueOrFrom| instead, e.g.
    503   * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures
    504   * that the expensive expression is only evaluated when its result will
    505   * actually be used.
    506   */
    507  template <typename V>
    508  constexpr T valueOr(V&& aDefault) const {
    509    if (isSome()) {
    510      return ref();
    511    }
    512    return std::forward<V>(aDefault);
    513  }
    514 
    515  /*
    516   * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
    517   * the value returned from the function or functor provided.
    518   */
    519  template <typename F>
    520  constexpr T valueOrFrom(F&& aFunc) const {
    521    if (isSome()) {
    522      return ref();
    523    }
    524    return aFunc();
    525  }
    526 
    527  /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|.
    528   */
    529  T* ptr();
    530  constexpr const T* ptr() const;
    531 
    532  /*
    533   * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
    534   * returns the default value provided.
    535   */
    536  T* ptrOr(T* aDefault) {
    537    if (isSome()) {
    538      return ptr();
    539    }
    540    return aDefault;
    541  }
    542 
    543  constexpr const T* ptrOr(const T* aDefault) const {
    544    if (isSome()) {
    545      return ptr();
    546    }
    547    return aDefault;
    548  }
    549 
    550  /*
    551   * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
    552   * returns the value returned from the function or functor provided.
    553   */
    554  template <typename F>
    555  T* ptrOrFrom(F&& aFunc) {
    556    if (isSome()) {
    557      return ptr();
    558    }
    559    return aFunc();
    560  }
    561 
    562  template <typename F>
    563  const T* ptrOrFrom(F&& aFunc) const {
    564    if (isSome()) {
    565      return ptr();
    566    }
    567    return aFunc();
    568  }
    569 
    570  constexpr T* operator->();
    571  constexpr const T* operator->() const;
    572 
    573  /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
    574  constexpr T& ref() & MOZ_LIFETIME_BOUND;
    575  constexpr const T& ref() const& MOZ_LIFETIME_BOUND;
    576  constexpr T&& ref() && MOZ_LIFETIME_BOUND;
    577  constexpr const T&& ref() const&& MOZ_LIFETIME_BOUND;
    578 
    579  /*
    580   * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
    581   * the default value provided.
    582   */
    583  constexpr T& refOr(T& aDefault MOZ_LIFETIME_BOUND) MOZ_LIFETIME_BOUND {
    584    if (isSome()) {
    585      return ref();
    586    }
    587    return aDefault;
    588  }
    589 
    590  constexpr const T& refOr(const T& aDefault MOZ_LIFETIME_BOUND) const
    591      MOZ_LIFETIME_BOUND {
    592    if (isSome()) {
    593      return ref();
    594    }
    595    return aDefault;
    596  }
    597 
    598  /*
    599   * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
    600   * value returned from the function or functor provided.
    601   */
    602  template <typename F>
    603  constexpr T& refOrFrom(F&& aFunc) {
    604    if (isSome()) {
    605      return ref();
    606    }
    607    return aFunc();
    608  }
    609 
    610  template <typename F>
    611  constexpr const T& refOrFrom(F&& aFunc) const {
    612    if (isSome()) {
    613      return ref();
    614    }
    615    return aFunc();
    616  }
    617 
    618  constexpr T& operator*() & MOZ_LIFETIME_BOUND;
    619  constexpr const T& operator*() const& MOZ_LIFETIME_BOUND;
    620  constexpr T&& operator*() && MOZ_LIFETIME_BOUND;
    621  constexpr const T&& operator*() const&& MOZ_LIFETIME_BOUND;
    622 
    623  /* If |isSome()|, runs the provided function or functor on the contents of
    624   * this Maybe. */
    625  template <typename Func>
    626  constexpr Maybe& apply(Func&& aFunc) & {
    627    if (isSome()) {
    628      std::forward<Func>(aFunc)(ref());
    629    }
    630    return *this;
    631  }
    632 
    633  template <typename Func>
    634  constexpr const Maybe& apply(Func&& aFunc) const& {
    635    if (isSome()) {
    636      std::forward<Func>(aFunc)(ref());
    637    }
    638    return *this;
    639  }
    640 
    641  template <typename Func>
    642  constexpr Maybe& apply(Func&& aFunc) && {
    643    if (isSome()) {
    644      std::forward<Func>(aFunc)(extract());
    645    }
    646    return *this;
    647  }
    648 
    649  template <typename Func>
    650  constexpr Maybe& apply(Func&& aFunc) const&& {
    651    if (isSome()) {
    652      std::forward<Func>(aFunc)(extract());
    653    }
    654    return *this;
    655  }
    656 
    657  /*
    658   * If |isSome()|, runs the provided function and returns the result wrapped
    659   * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same
    660   * value type as what the provided function would have returned.
    661   */
    662  template <typename Func>
    663  constexpr auto map(Func&& aFunc) & {
    664    if (isSome()) {
    665      return Some(std::forward<Func>(aFunc)(ref()));
    666    }
    667    return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
    668  }
    669 
    670  template <typename Func>
    671  constexpr auto map(Func&& aFunc) const& {
    672    if (isSome()) {
    673      return Some(std::forward<Func>(aFunc)(ref()));
    674    }
    675    return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
    676  }
    677 
    678  template <typename Func>
    679  constexpr auto map(Func&& aFunc) && {
    680    if (isSome()) {
    681      return Some(std::forward<Func>(aFunc)(extract()));
    682    }
    683    return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
    684  }
    685 
    686  template <typename Func>
    687  constexpr auto map(Func&& aFunc) const&& {
    688    if (isSome()) {
    689      return Some(std::forward<Func>(aFunc)(extract()));
    690    }
    691    return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
    692  }
    693 
    694  /*
    695   * If |isSome()|, runs the provided function or functor on the contents of
    696   * this Maybe and returns the result. Note that the provided function or
    697   * functor must return a Maybe<U> of any type U.
    698   * If |isNothing()|, returns an empty Maybe value with the same type as what
    699   * the provided function would have returned.
    700   */
    701  template <typename Func>
    702  constexpr auto andThen(Func&& aFunc) & {
    703    static_assert(std::is_invocable_v<Func, T&>);
    704    using U = std::invoke_result_t<Func, T&>;
    705    static_assert(detail::IsMaybe<U>::value);
    706    if (isSome()) {
    707      return std::invoke(std::forward<Func>(aFunc), ref());
    708    }
    709    return std::remove_cv_t<std::remove_reference_t<U>>{};
    710  }
    711 
    712  template <typename Func>
    713  constexpr auto andThen(Func&& aFunc) const& {
    714    static_assert(std::is_invocable_v<Func, const T&>);
    715    using U = std::invoke_result_t<Func, const T&>;
    716    static_assert(detail::IsMaybe<U>::value);
    717    if (isSome()) {
    718      return std::invoke(std::forward<Func>(aFunc), ref());
    719    }
    720    return std::remove_cv_t<std::remove_reference_t<U>>{};
    721  }
    722 
    723  template <typename Func>
    724  constexpr auto andThen(Func&& aFunc) && {
    725    static_assert(std::is_invocable_v<Func, T&&>);
    726    using U = std::invoke_result_t<Func, T&&>;
    727    static_assert(detail::IsMaybe<U>::value);
    728    if (isSome()) {
    729      return std::invoke(std::forward<Func>(aFunc), extract());
    730    }
    731    return std::remove_cv_t<std::remove_reference_t<U>>{};
    732  }
    733 
    734  template <typename Func>
    735  constexpr auto andThen(Func&& aFunc) const&& {
    736    static_assert(std::is_invocable_v<Func, const T&&>);
    737    using U = std::invoke_result_t<Func, const T&&>;
    738    static_assert(detail::IsMaybe<U>::value);
    739    if (isSome()) {
    740      return std::invoke(std::forward<Func>(aFunc), extract());
    741    }
    742    return std::remove_cv_t<std::remove_reference_t<U>>{};
    743  }
    744 
    745  /*
    746   * If |isNothing()|, runs the provided function or functor and returns its
    747   * result. If |isSome()|, returns the contained value wrapped in a Maybe.
    748   */
    749  template <typename Func>
    750  constexpr Maybe orElse(Func&& aFunc) & {
    751    static_assert(std::is_invocable_v<Func>);
    752    using U = std::invoke_result_t<Func>;
    753    static_assert(
    754        std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
    755    if (isSome()) {
    756      return *this;
    757    }
    758    return std::invoke(std::forward<Func>(aFunc));
    759  }
    760 
    761  template <typename Func>
    762  constexpr Maybe orElse(Func&& aFunc) const& {
    763    static_assert(std::is_invocable_v<Func>);
    764    using U = std::invoke_result_t<Func>;
    765    static_assert(
    766        std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
    767    if (isSome()) {
    768      return *this;
    769    }
    770    return std::invoke(std::forward<Func>(aFunc));
    771  }
    772 
    773  template <typename Func>
    774  constexpr Maybe orElse(Func&& aFunc) && {
    775    static_assert(std::is_invocable_v<Func>);
    776    using U = std::invoke_result_t<Func>;
    777    static_assert(
    778        std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
    779    if (isSome()) {
    780      return std::move(*this);
    781    }
    782    return std::invoke(std::forward<Func>(aFunc));
    783  }
    784 
    785  template <typename Func>
    786  constexpr Maybe orElse(Func&& aFunc) const&& {
    787    static_assert(std::is_invocable_v<Func>);
    788    using U = std::invoke_result_t<Func>;
    789    static_assert(
    790        std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
    791    if (isSome()) {
    792      return std::move(*this);
    793    }
    794    return std::invoke(std::forward<Func>(aFunc));
    795  }
    796 
    797  /* begin() and end() implementation */
    798 private:
    799  template <typename U>
    800  struct Iterator {
    801    using iterator_type = Iterator<U>;
    802    using value_type = U;
    803    using difference_type = std::ptrdiff_t;
    804    using reference = value_type&;
    805    using pointer = value_type*;
    806    using iterator_category = std::forward_iterator_tag;
    807 
    808    constexpr Iterator() = default;
    809    constexpr explicit Iterator(pointer aValue) : mValue(aValue) {}
    810 
    811    constexpr reference operator*() const { return *mValue; };
    812 
    813    constexpr pointer operator->() const { return mValue; }
    814 
    815    constexpr iterator_type& operator++() {
    816      mValue = nullptr;
    817      return *this;
    818    }
    819 
    820    constexpr iterator_type operator++(int) {
    821      iterator_type it{mValue};
    822      mValue = nullptr;
    823      return it;
    824    }
    825 
    826    constexpr auto operator<=>(const Iterator&) const = default;
    827 
    828   private:
    829    pointer mValue;
    830  };
    831 
    832 public:
    833  using iterator = Iterator<T>;
    834  using const_iterator = Iterator<const T>;
    835 
    836  constexpr iterator begin() { return iterator{ptrOr(nullptr)}; }
    837  constexpr const_iterator begin() const {
    838    return const_iterator{ptrOr(nullptr)};
    839  }
    840  constexpr const_iterator cbegin() const { return begin(); }
    841 
    842  constexpr iterator end() { return iterator{nullptr}; }
    843  constexpr const_iterator end() const { return const_iterator{nullptr}; }
    844  constexpr const_iterator cend() const { return end(); }
    845 
    846  /* If |isSome()|, empties this Maybe and destroys its contents. */
    847  constexpr void reset() {
    848    if (isSome()) {
    849      if constexpr (!std::is_trivially_destructible_v<T>) {
    850        /*
    851         * Static analyzer gets confused if we have Maybe<MutexAutoLock>,
    852         * so we suppress thread-safety warnings here
    853         */
    854        MOZ_PUSH_IGNORE_THREAD_SAFETY
    855        ref().T::~T();
    856        MOZ_POP_THREAD_SAFETY
    857        poisonData();
    858      }
    859      mIsSome = false;
    860    }
    861  }
    862 
    863  /*
    864   * Constructs a T value in-place in this empty Maybe<T>'s storage. The
    865   * arguments to |emplace()| are the parameters to T's constructor.
    866   */
    867  template <typename... Args>
    868  constexpr void emplace(Args&&... aArgs);
    869 
    870  template <typename U>
    871  constexpr std::enable_if_t<std::is_same_v<T, U> &&
    872                             std::is_copy_constructible_v<U> &&
    873                             !std::is_move_constructible_v<U>>
    874  emplace(U&& aArgs) {
    875    emplace(aArgs);
    876  }
    877 
    878  friend std::ostream& operator<<(std::ostream& aStream,
    879                                  const Maybe<T>& aMaybe) {
    880    if (aMaybe) {
    881      aStream << aMaybe.ref();
    882    } else {
    883      aStream << "<Nothing>";
    884    }
    885    return aStream;
    886  }
    887 };
    888 
    889 template <typename T>
    890 class Maybe<T&> {
    891 public:
    892  constexpr Maybe() = default;
    893  constexpr MOZ_IMPLICIT Maybe(Nothing) {}
    894 
    895  void emplace(T& aRef) { mValue = &aRef; }
    896 
    897  /* Methods that check whether this Maybe contains a value */
    898  constexpr explicit operator bool() const { return isSome(); }
    899  constexpr bool isSome() const { return mValue; }
    900  constexpr bool isNothing() const { return !mValue; }
    901 
    902  T& ref() const {
    903    MOZ_RELEASE_ASSERT(isSome());
    904    return *mValue;
    905  }
    906 
    907  T* operator->() const { return &ref(); }
    908  T& operator*() const { return ref(); }
    909 
    910  // Deliberately not defining value and ptr accessors, as these may be
    911  // confusing on a reference-typed Maybe.
    912 
    913  // XXX Should we define refOr?
    914 
    915  void reset() { mValue = nullptr; }
    916 
    917  template <typename Func>
    918  const Maybe& apply(Func&& aFunc) const {
    919    if (isSome()) {
    920      std::forward<Func>(aFunc)(ref());
    921    }
    922    return *this;
    923  }
    924 
    925  template <typename Func>
    926  auto map(Func&& aFunc) const {
    927    Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
    928    if (isSome()) {
    929      val.emplace(std::forward<Func>(aFunc)(ref()));
    930    }
    931    return val;
    932  }
    933 
    934  template <typename Func>
    935  constexpr auto andThen(Func&& aFunc) const {
    936    static_assert(std::is_invocable_v<Func, T&>);
    937    using U = std::invoke_result_t<Func, T&>;
    938    static_assert(detail::IsMaybe<U>::value);
    939    if (isSome()) {
    940      return std::invoke(std::forward<Func>(aFunc), ref());
    941    }
    942    return std::remove_cv_t<std::remove_reference_t<U>>{};
    943  }
    944 
    945  template <typename Func>
    946  constexpr Maybe orElse(Func&& aFunc) const {
    947    static_assert(std::is_invocable_v<Func>);
    948    using U = std::invoke_result_t<Func>;
    949    static_assert(
    950        std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
    951    if (isSome()) {
    952      return *this;
    953    }
    954    return std::invoke(std::forward<Func>(aFunc));
    955  }
    956 
    957  bool refEquals(const Maybe<T&>& aOther) const {
    958    return mValue == aOther.mValue;
    959  }
    960 
    961  bool refEquals(const T& aOther) const { return mValue == &aOther; }
    962 
    963 private:
    964  T* mValue = nullptr;
    965 };
    966 
    967 template <typename T>
    968 constexpr T Maybe<T>::value() const& {
    969  MOZ_RELEASE_ASSERT(isSome());
    970  return ref();
    971 }
    972 
    973 template <typename T>
    974 constexpr T Maybe<T>::value() && {
    975  MOZ_RELEASE_ASSERT(isSome());
    976  return std::move(ref());
    977 }
    978 
    979 template <typename T>
    980 constexpr T Maybe<T>::value() const&& {
    981  MOZ_RELEASE_ASSERT(isSome());
    982  return std::move(ref());
    983 }
    984 
    985 template <typename T>
    986 T* Maybe<T>::ptr() {
    987  MOZ_RELEASE_ASSERT(isSome());
    988  return &ref();
    989 }
    990 
    991 template <typename T>
    992 constexpr const T* Maybe<T>::ptr() const {
    993  MOZ_RELEASE_ASSERT(isSome());
    994  return &ref();
    995 }
    996 
    997 template <typename T>
    998 constexpr T* Maybe<T>::operator->() {
    999  MOZ_RELEASE_ASSERT(isSome());
   1000  return ptr();
   1001 }
   1002 
   1003 template <typename T>
   1004 constexpr const T* Maybe<T>::operator->() const {
   1005  MOZ_RELEASE_ASSERT(isSome());
   1006  return ptr();
   1007 }
   1008 
   1009 template <typename T>
   1010 constexpr T& Maybe<T>::ref() & {
   1011  MOZ_RELEASE_ASSERT(isSome());
   1012  return mStorage.val;
   1013 }
   1014 
   1015 template <typename T>
   1016 constexpr const T& Maybe<T>::ref() const& {
   1017  MOZ_RELEASE_ASSERT(isSome());
   1018  return mStorage.val;
   1019 }
   1020 
   1021 template <typename T>
   1022 constexpr T&& Maybe<T>::ref() && {
   1023  MOZ_RELEASE_ASSERT(isSome());
   1024  return std::move(mStorage.val);
   1025 }
   1026 
   1027 template <typename T>
   1028 constexpr const T&& Maybe<T>::ref() const&& {
   1029  MOZ_RELEASE_ASSERT(isSome());
   1030  return std::move(mStorage.val);
   1031 }
   1032 
   1033 template <typename T>
   1034 constexpr T& Maybe<T>::operator*() & {
   1035  MOZ_RELEASE_ASSERT(isSome());
   1036  return ref();
   1037 }
   1038 
   1039 template <typename T>
   1040 constexpr const T& Maybe<T>::operator*() const& {
   1041  MOZ_RELEASE_ASSERT(isSome());
   1042  return ref();
   1043 }
   1044 
   1045 template <typename T>
   1046 constexpr T&& Maybe<T>::operator*() && {
   1047  MOZ_RELEASE_ASSERT(isSome());
   1048  return std::move(ref());
   1049 }
   1050 
   1051 template <typename T>
   1052 constexpr const T&& Maybe<T>::operator*() const&& {
   1053  MOZ_RELEASE_ASSERT(isSome());
   1054  return std::move(ref());
   1055 }
   1056 
   1057 template <typename T>
   1058 template <typename... Args>
   1059 constexpr void Maybe<T>::emplace(Args&&... aArgs) {
   1060  MOZ_RELEASE_ASSERT(!isSome());
   1061  ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
   1062  mIsSome = true;
   1063 }
   1064 
   1065 /*
   1066 * Some() creates a Maybe<T> value containing the provided T value. If T has a
   1067 * move constructor, it's used to make this as efficient as possible.
   1068 *
   1069 * Some() selects the type of Maybe it returns by removing any const, volatile,
   1070 * or reference qualifiers from the type of the value you pass to it. This gives
   1071 * it more intuitive behavior when used in expressions, but it also means that
   1072 * if you need to construct a Maybe value that holds a const, volatile, or
   1073 * reference value, you need to use emplace() instead.
   1074 */
   1075 template <typename T, typename U>
   1076 constexpr Maybe<U> Some(T&& aValue) {
   1077  return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
   1078 }
   1079 
   1080 template <typename T>
   1081 constexpr Maybe<T&> SomeRef(T& aValue) {
   1082  Maybe<T&> value;
   1083  value.emplace(aValue);
   1084  return value;
   1085 }
   1086 
   1087 template <typename T>
   1088 constexpr Maybe<T&> ToMaybeRef(T* const aPtr) {
   1089  return aPtr ? SomeRef(*aPtr) : Nothing{};
   1090 }
   1091 
   1092 template <typename T>
   1093 Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) {
   1094  if (aPtr) {
   1095    return Some(*aPtr);
   1096  }
   1097  return Nothing();
   1098 }
   1099 
   1100 /*
   1101 * Two Maybe<T> values are equal if
   1102 * - both are Nothing, or
   1103 * - both are Some, and the values they contain are equal.
   1104 */
   1105 template <typename T>
   1106 constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1107  static_assert(!std::is_reference_v<T>,
   1108                "operator== is not defined for Maybe<T&>, compare values or "
   1109                "addresses explicitly instead");
   1110  if (aLHS.isNothing() != aRHS.isNothing()) {
   1111    return false;
   1112  }
   1113  return aLHS.isNothing() || *aLHS == *aRHS;
   1114 }
   1115 
   1116 template <typename T>
   1117 constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1118  return !(aLHS == aRHS);
   1119 }
   1120 
   1121 /*
   1122 * We support comparison to Nothing to allow reasonable expressions like:
   1123 *   if (maybeValue == Nothing()) { ... }
   1124 */
   1125 template <typename T>
   1126 constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
   1127  return aLHS.isNothing();
   1128 }
   1129 
   1130 template <typename T>
   1131 constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
   1132  return !(aLHS == aRHS);
   1133 }
   1134 
   1135 template <typename T>
   1136 constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
   1137  return aRHS.isNothing();
   1138 }
   1139 
   1140 template <typename T>
   1141 constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
   1142  return !(aLHS == aRHS);
   1143 }
   1144 
   1145 /*
   1146 * Maybe<T> values are ordered in the same way T values are ordered, except that
   1147 * Nothing comes before anything else.
   1148 */
   1149 template <typename T>
   1150 constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1151  if (aLHS.isNothing()) {
   1152    return aRHS.isSome();
   1153  }
   1154  if (aRHS.isNothing()) {
   1155    return false;
   1156  }
   1157  return *aLHS < *aRHS;
   1158 }
   1159 
   1160 template <typename T>
   1161 constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1162  return !(aLHS < aRHS || aLHS == aRHS);
   1163 }
   1164 
   1165 template <typename T>
   1166 constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1167  return aLHS < aRHS || aLHS == aRHS;
   1168 }
   1169 
   1170 template <typename T>
   1171 constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
   1172  return !(aLHS < aRHS);
   1173 }
   1174 
   1175 template <typename T>
   1176 inline void ImplCycleCollectionTraverse(
   1177    nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField,
   1178    const char* aName, uint32_t aFlags = 0) {
   1179  if (aField) {
   1180    ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags);
   1181  }
   1182 }
   1183 
   1184 template <typename T>
   1185 inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) {
   1186  if (aField) {
   1187    ImplCycleCollectionUnlink(aField.ref());
   1188  }
   1189 }
   1190 
   1191 }  // namespace mozilla
   1192 
   1193 #endif /* mozilla_Maybe_h */