tor-browser

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

Variant.h (33851B)


      1 /* -*- Mode: C++; tab-width: 8; 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 template class for tagged unions. */
      8 
      9 #include <algorithm>
     10 #include <new>
     11 #include <stdint.h>
     12 
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/HashFunctions.h"
     15 #include "mozilla/OperatorNewExtensions.h"
     16 
     17 #include <type_traits>
     18 #include <utility>
     19 
     20 #ifndef mozilla_Variant_h
     21 #  define mozilla_Variant_h
     22 
     23 namespace IPC {
     24 template <typename T>
     25 struct ParamTraits;
     26 }  // namespace IPC
     27 
     28 namespace mozilla {
     29 
     30 template <typename... Ts>
     31 class Variant;
     32 
     33 namespace detail {
     34 
     35 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
     36 template <size_t N, typename... Ts>
     37 struct Nth;
     38 
     39 template <typename T, typename... Ts>
     40 struct Nth<0, T, Ts...> {
     41  using Type = T;
     42 };
     43 
     44 template <size_t N, typename T, typename... Ts>
     45 struct Nth<N, T, Ts...> {
     46  using Type = typename Nth<N - 1, Ts...>::Type;
     47 };
     48 
     49 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
     50 template <typename T, typename... Variants>
     51 struct SelectVariantTypeHelper;
     52 
     53 template <typename T>
     54 struct SelectVariantTypeHelper<T> {
     55  static constexpr size_t count = 0;
     56 };
     57 
     58 template <typename T, typename... Variants>
     59 struct SelectVariantTypeHelper<T, T, Variants...> {
     60  typedef T Type;
     61  static constexpr size_t count =
     62      1 + SelectVariantTypeHelper<T, Variants...>::count;
     63 };
     64 
     65 template <typename T, typename... Variants>
     66 struct SelectVariantTypeHelper<T, const T, Variants...> {
     67  typedef const T Type;
     68  static constexpr size_t count =
     69      1 + SelectVariantTypeHelper<T, Variants...>::count;
     70 };
     71 
     72 template <typename T, typename... Variants>
     73 struct SelectVariantTypeHelper<T, const T&, Variants...> {
     74  typedef const T& Type;
     75  static constexpr size_t count =
     76      1 + SelectVariantTypeHelper<T, Variants...>::count;
     77 };
     78 
     79 template <typename T, typename... Variants>
     80 struct SelectVariantTypeHelper<T, T&&, Variants...> {
     81  typedef T&& Type;
     82  static constexpr size_t count =
     83      1 + SelectVariantTypeHelper<T, Variants...>::count;
     84 };
     85 
     86 template <typename T, typename Head, typename... Variants>
     87 struct SelectVariantTypeHelper<T, Head, Variants...>
     88    : public SelectVariantTypeHelper<T, Variants...> {};
     89 
     90 /**
     91 * SelectVariantType takes a type T and a list of variant types Variants and
     92 * yields a type Type, selected from Variants, that can store a value of type T
     93 * or a reference to type T. If no such type was found, Type is not defined.
     94 * SelectVariantType also has a `count` member that contains the total number of
     95 * selectable types (which will be used to check that a requested type is not
     96 * ambiguously present twice.)
     97 */
     98 template <typename T, typename... Variants>
     99 struct SelectVariantType
    100    : public SelectVariantTypeHelper<
    101          std::remove_const_t<std::remove_reference_t<T>>, Variants...> {};
    102 
    103 // Compute a fast, compact type that can be used to hold integral values that
    104 // distinctly map to every type in Ts.
    105 template <typename... Ts>
    106 struct VariantTag {
    107 private:
    108  static const size_t TypeCount = sizeof...(Ts);
    109 
    110 public:
    111  using Type = std::conditional_t<
    112      (TypeCount <= 2), bool,
    113      std::conditional_t<(TypeCount <= size_t(UINT_FAST8_MAX)), uint_fast8_t,
    114                         size_t  // stop caring past a certain
    115                                 // point :-)
    116                         >>;
    117 };
    118 
    119 // TagHelper gets the given sentinel tag value for the given type T. This has to
    120 // be split out from VariantImplementation because you can't nest a partial
    121 // template specialization within a template class.
    122 
    123 template <typename Tag, size_t N, typename T, typename U, typename Next,
    124          bool isMatch>
    125 struct TagHelper;
    126 
    127 // In the case where T != U, we continue recursion.
    128 template <typename Tag, size_t N, typename T, typename U, typename Next>
    129 struct TagHelper<Tag, N, T, U, Next, false> {
    130  static Tag tag() { return Next::template tag<U>(); }
    131 };
    132 
    133 // In the case where T == U, return the tag number.
    134 template <typename Tag, size_t N, typename T, typename U, typename Next>
    135 struct TagHelper<Tag, N, T, U, Next, true> {
    136  static Tag tag() { return Tag(N); }
    137 };
    138 
    139 // The VariantImplementation template provides the guts of mozilla::Variant.  We
    140 // create a VariantImplementation for each T in Ts... which handles
    141 // construction, destruction, etc for when the Variant's type is T.  If the
    142 // Variant's type isn't T, it punts the request on to the next
    143 // VariantImplementation.
    144 
    145 template <typename Tag, size_t N, typename... Ts>
    146 struct VariantImplementation;
    147 
    148 // The singly typed Variant / recursion base case.
    149 template <typename Tag, size_t N, typename T>
    150 struct VariantImplementation<Tag, N, T> {
    151  template <typename U>
    152  static Tag tag() {
    153    static_assert(std::is_same_v<T, U>, "mozilla::Variant: tag: bad type!");
    154    return Tag(N);
    155  }
    156 
    157  template <typename Variant>
    158  static void copyConstruct(void* aLhs, const Variant& aRhs) {
    159    ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
    160  }
    161 
    162  template <typename Variant>
    163  static void moveConstruct(void* aLhs, Variant&& aRhs) {
    164    ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
    165  }
    166 
    167  template <typename Variant>
    168  static void destroy(Variant& aV) {
    169    aV.template as<N>().~T();
    170  }
    171 
    172  template <typename Variant>
    173  static bool equal(const Variant& aLhs, const Variant& aRhs) {
    174    return aLhs.template as<N>() == aRhs.template as<N>();
    175  }
    176 
    177  template <typename Matcher, typename ConcreteVariant>
    178  static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) {
    179    if constexpr (std::is_invocable_v<Matcher, Tag,
    180                                      decltype(std::forward<ConcreteVariant>(aV)
    181                                                   .template as<N>())>) {
    182      return std::forward<Matcher>(aMatcher)(
    183          Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
    184    } else {
    185      return std::forward<Matcher>(aMatcher)(
    186          std::forward<ConcreteVariant>(aV).template as<N>());
    187    }
    188  }
    189 
    190  template <typename ConcreteVariant, typename Matcher>
    191  static decltype(auto) matchN(ConcreteVariant&& aV, Matcher&& aMatcher) {
    192    if constexpr (std::is_invocable_v<Matcher, Tag,
    193                                      decltype(std::forward<ConcreteVariant>(aV)
    194                                                   .template as<N>())>) {
    195      return std::forward<Matcher>(aMatcher)(
    196          Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
    197    } else {
    198      return std::forward<Matcher>(aMatcher)(
    199          std::forward<ConcreteVariant>(aV).template as<N>());
    200    }
    201  }
    202 };
    203 
    204 // VariantImplementation for some variant type T.
    205 template <typename Tag, size_t N, typename T, typename... Ts>
    206 struct VariantImplementation<Tag, N, T, Ts...> {
    207  // The next recursive VariantImplementation.
    208  using Next = VariantImplementation<Tag, N + 1, Ts...>;
    209 
    210  template <typename U>
    211  static Tag tag() {
    212    return TagHelper<Tag, N, T, U, Next, std::is_same_v<T, U>>::tag();
    213  }
    214 
    215  template <typename Variant>
    216  static void copyConstruct(void* aLhs, const Variant& aRhs) {
    217    if (aRhs.template is<N>()) {
    218      ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
    219    } else {
    220      Next::copyConstruct(aLhs, aRhs);
    221    }
    222  }
    223 
    224  template <typename Variant>
    225  static void moveConstruct(void* aLhs, Variant&& aRhs) {
    226    if (aRhs.template is<N>()) {
    227      ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
    228    } else {
    229      Next::moveConstruct(aLhs, std::move(aRhs));
    230    }
    231  }
    232 
    233  template <typename Variant>
    234  static void destroy(Variant& aV) {
    235    if (aV.template is<N>()) {
    236      aV.template as<N>().~T();
    237    } else {
    238      Next::destroy(aV);
    239    }
    240  }
    241 
    242  template <typename Variant>
    243  static bool equal(const Variant& aLhs, const Variant& aRhs) {
    244    if (aLhs.template is<N>()) {
    245      MOZ_ASSERT(aRhs.template is<N>());
    246      return aLhs.template as<N>() == aRhs.template as<N>();
    247    } else {
    248      return Next::equal(aLhs, aRhs);
    249    }
    250  }
    251 
    252  template <typename Matcher, typename ConcreteVariant>
    253  static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) {
    254    if (aV.template is<N>()) {
    255      if constexpr (std::is_invocable_v<Matcher, Tag,
    256                                        decltype(std::forward<ConcreteVariant>(
    257                                                     aV)
    258                                                     .template as<N>())>) {
    259        return std::forward<Matcher>(aMatcher)(
    260            Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
    261      } else {
    262        return std::forward<Matcher>(aMatcher)(
    263            std::forward<ConcreteVariant>(aV).template as<N>());
    264      }
    265    } else {
    266      // If you're seeing compilation errors here like "no matching
    267      // function for call to 'match'" then that means that the
    268      // Matcher doesn't exhaust all variant types. There must exist a
    269      // Matcher::operator()(T&) for every variant type T.
    270      //
    271      // If you're seeing compilation errors here like "cannot initialize
    272      // return object of type <...> with an rvalue of type <...>" then that
    273      // means that the Matcher::operator()(T&) overloads are returning
    274      // different types. They must all return the same type.
    275      return Next::match(std::forward<Matcher>(aMatcher),
    276                         std::forward<ConcreteVariant>(aV));
    277    }
    278  }
    279 
    280  template <typename ConcreteVariant, typename Mi, typename... Ms>
    281  static decltype(auto) matchN(ConcreteVariant&& aV, Mi&& aMi, Ms&&... aMs) {
    282    if (aV.template is<N>()) {
    283      if constexpr (std::is_invocable_v<Mi, Tag,
    284                                        decltype(std::forward<ConcreteVariant>(
    285                                                     aV)
    286                                                     .template as<N>())>) {
    287        static_assert(
    288            std::is_same_v<
    289                decltype(std::forward<Mi>(aMi)(
    290                    Tag(N),
    291                    std::forward<ConcreteVariant>(aV).template as<N>())),
    292                decltype(Next::matchN(std::forward<ConcreteVariant>(aV),
    293                                      std::forward<Ms>(aMs)...))>,
    294            "all matchers must have the same return type");
    295        return std::forward<Mi>(aMi)(
    296            Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
    297      } else {
    298        static_assert(
    299            std::is_same_v<
    300                decltype(std::forward<Mi>(aMi)(
    301                    std::forward<ConcreteVariant>(aV).template as<N>())),
    302                decltype(Next::matchN(std::forward<ConcreteVariant>(aV),
    303                                      std::forward<Ms>(aMs)...))>,
    304            "all matchers must have the same return type");
    305        return std::forward<Mi>(aMi)(
    306            std::forward<ConcreteVariant>(aV).template as<N>());
    307      }
    308    } else {
    309      // If you're seeing compilation errors here like "no matching
    310      // function for call to 'match'" then that means that the
    311      // Matchers don't exhaust all variant types. There must exist a
    312      // Matcher (with its operator()(T&)) for every variant type T, in the
    313      // exact same order.
    314      return Next::matchN(std::forward<ConcreteVariant>(aV),
    315                          std::forward<Ms>(aMs)...);
    316    }
    317  }
    318 };
    319 
    320 /**
    321 * AsVariantTemporary stores a value of type T to allow construction of a
    322 * Variant value via type inference. Because T is copied and there's no
    323 * guarantee that the copy can be elided, AsVariantTemporary is best used with
    324 * primitive or very small types.
    325 */
    326 template <typename T>
    327 struct AsVariantTemporary {
    328  explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {}
    329 
    330  template <typename U>
    331  explicit AsVariantTemporary(U&& aValue) : mValue(std::forward<U>(aValue)) {}
    332 
    333  AsVariantTemporary(const AsVariantTemporary& aOther)
    334      : mValue(aOther.mValue) {}
    335 
    336  AsVariantTemporary(AsVariantTemporary&& aOther)
    337      : mValue(std::move(aOther.mValue)) {}
    338 
    339  AsVariantTemporary() = delete;
    340  void operator=(const AsVariantTemporary&) = delete;
    341  void operator=(AsVariantTemporary&&) = delete;
    342 
    343  std::remove_const_t<std::remove_reference_t<T>> mValue;
    344 };
    345 
    346 }  // namespace detail
    347 
    348 // Used to unambiguously specify one of the Variant's type.
    349 template <typename T>
    350 struct VariantType {
    351  using Type = T;
    352 };
    353 
    354 // Used to specify one of the Variant's type by index.
    355 template <size_t N>
    356 struct VariantIndex {
    357  static constexpr size_t index = N;
    358 };
    359 
    360 /**
    361 * # mozilla::Variant
    362 *
    363 * A variant / tagged union / heterogenous disjoint union / sum-type template
    364 * class. Similar in concept to (but not derived from) `boost::variant`.
    365 *
    366 * Sometimes, you may wish to use a C union with non-POD types. However, this is
    367 * forbidden in C++ because it is not clear which type in the union should have
    368 * its constructor and destructor run on creation and deletion
    369 * respectively. This is the problem that `mozilla::Variant` solves.
    370 *
    371 * Since C++17, std::variant exists. `mozilla::Variant` differs conceptually
    372 * from it by (a.) having a richer `.match` API (compared to `std::visit`) and
    373 * (b.) having a different assignment semantic. Assigning to an `std::variant`
    374 * assigns to the underlying value, while assigning to a `mozilla::Variant`
    375 * deletes the previous value then move-constructs a new value. This makes it
    376 * possible to store *and* update const values.
    377 *
    378 * ## Usage
    379 *
    380 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
    381 * its variant types (ignoring const and references). It does *not* support
    382 * construction from subclasses of variant types or types that coerce to one of
    383 * the variant types.
    384 *
    385 *     Variant<char, uint32_t> v1('a');
    386 *     Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
    387 *     Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
    388 *     Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
    389 *
    390 * Because specifying the full type of a Variant value is often verbose,
    391 * there are two easier ways to construct values:
    392 *
    393 * A. AsVariant() can be used to construct a Variant value using type inference
    394 * in contexts such as expressions or when returning values from functions.
    395 * Because AsVariant() must copy or move the value into a temporary and this
    396 * cannot necessarily be elided by the compiler, it's mostly appropriate only
    397 * for use with primitive or very small types.
    398 *
    399 *     Variant<char, uint32_t> Foo() { return AsVariant('x'); }
    400 *     // ...
    401 *     Variant<char, uint32_t> v1 = Foo();  // v1 holds char('x').
    402 *
    403 * B. Brace-construction with VariantType or VariantIndex; this also allows
    404 * in-place construction with any number of arguments.
    405 *
    406 *     struct AB { AB(int, int){...} };
    407 *     static Variant<AB, bool> foo()
    408 *     {
    409 *       return {VariantIndex<0>{}, 1, 2};
    410 *     }
    411 *     // ...
    412 *     Variant<AB, bool> v0 = Foo();  // v0 holds AB(1,2).
    413 *
    414 * All access to the contained value goes through type-safe accessors.
    415 * Either the stored type, or the type index may be provided.
    416 *
    417 *     void
    418 *     Foo(Variant<A, B, C> v)
    419 *     {
    420 *       if (v.is<A>()) {
    421 *         A& ref = v.as<A>();
    422 *         ...
    423 *       } else (v.is<1>()) { // Instead of v.is<B>.
    424 *         ...
    425 *       } else {
    426 *         ...
    427 *       }
    428 *     }
    429 *
    430 * In some situation, a Variant may be constructed from templated types, in
    431 * which case it is possible that the same type could be given multiple times by
    432 * an external developer. Or seemingly-different types could be aliases.
    433 * In this case, repeated types can only be accessed through their index, to
    434 * prevent ambiguous access by type.
    435 *
    436 *    // Bad!
    437 *    template <typename T>
    438 *    struct ResultOrError
    439 *    {
    440 *      Variant<T, int> m;
    441 *      ResultOrError() : m(int(0)) {} // Error '0' by default
    442 *      ResultOrError(const T& r) : m(r) {}
    443 *      bool IsResult() const { return m.is<T>(); }
    444 *      bool IsError() const { return m.is<int>(); }
    445 *    };
    446 *    // Now instantiante with the result being an int too:
    447 *    ResultOrError<int> myResult(123); // Fail!
    448 *    // In Variant<int, int>, which 'int' are we refering to, from inside
    449 *    // ResultOrError functions?
    450 *
    451 *    // Good!
    452 *    template <typename T>
    453 *    struct ResultOrError
    454 *    {
    455 *      Variant<T, int> m;
    456 *      ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
    457 *      ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
    458 *      bool IsResult() const { return m.is<0>(); } // 0 -> T
    459 *      bool IsError() const { return m.is<1>(); } // 1 -> int
    460 *    };
    461 *    // Now instantiante with the result being an int too:
    462 *    ResultOrError<int> myResult(123); // It now works!
    463 *
    464 * Attempting to use the contained value as type `T1` when the `Variant`
    465 * instance contains a value of type `T2` causes an assertion failure.
    466 *
    467 *     A a;
    468 *     Variant<A, B, C> v(a);
    469 *     v.as<B>(); // <--- Assertion failure!
    470 *
    471 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
    472 * member of the set of `Ts...` is a compiler error.
    473 *
    474 *     A a;
    475 *     Variant<A, B, C> v(a);
    476 *     v.as<SomeRandomType>(); // <--- Compiler error!
    477 *
    478 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
    479 * out of the containing `Variant` instance with the `extract<T>` method:
    480 *
    481 *     Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
    482 *     auto ptr = v.extract<UniquePtr<A>>();
    483 *
    484 * Finally, you can exhaustively match on the contained variant and branch into
    485 * different code paths depending on which type is contained. This is preferred
    486 * to manually checking every variant type T with is<T>() because it provides
    487 * compile-time checking that you handled every type, rather than runtime
    488 * assertion failures.
    489 *
    490 *     // Bad!
    491 *     char* foo(Variant<A, B, C, D>& v) {
    492 *       if (v.is<A>()) {
    493 *         return ...;
    494 *       } else if (v.is<B>()) {
    495 *         return ...;
    496 *       } else {
    497 *         return doSomething(v.as<C>()); // Forgot about case D!
    498 *       }
    499 *     }
    500 *
    501 *     // Instead, a single function object (that can deal with all possible
    502 *     // options) may be provided:
    503 *     struct FooMatcher
    504 *     {
    505 *       // The return type of all matchers must be identical.
    506 *       char* operator()(A& a) { ... }
    507 *       char* operator()(B& b) { ... }
    508 *       char* operator()(C& c) { ... }
    509 *       char* operator()(D& d) { ... } // Compile-time error to forget D!
    510 *     }
    511 *     char* foo(Variant<A, B, C, D>& v) {
    512 *       return v.match(FooMatcher());
    513 *     }
    514 *
    515 *     // In some situations, a single generic lambda may also be appropriate:
    516 *     char* foo(Variant<A, B, C, D>& v) {
    517 *       return v.match([](auto&) {...});
    518 *     }
    519 *
    520 *     // Alternatively, multiple function objects may be provided, each one
    521 *     // corresponding to an option, in the same order:
    522 *     char* foo(Variant<A, B, C, D>& v) {
    523 *       return v.match([](A&) { ... },
    524 *                      [](B&) { ... },
    525 *                      [](C&) { ... },
    526 *                      [](D&) { ... });
    527 *     }
    528 *
    529 *     // In rare cases, the index of the currently-active alternative is
    530 *     // needed, it may be obtained by adding a first parameter in the matcner
    531 *     // callback, which will receive the index in its most compact type (just
    532 *     // use `size_t` if the exact type is not important), e.g.:
    533 *     char* foo(Variant<A, B, C, D>& v) {
    534 *       return v.match([](auto aIndex, auto& aAlternative) {...});
    535 *       // --OR--
    536 *       return v.match([](size_t aIndex, auto& aAlternative) {...});
    537 *     }
    538 *
    539 * ## Examples
    540 *
    541 * A tree is either an empty leaf, or a node with a value and two children:
    542 *
    543 *     struct Leaf { };
    544 *
    545 *     template<typename T>
    546 *     struct Node
    547 *     {
    548 *       T value;
    549 *       Tree<T>* left;
    550 *       Tree<T>* right;
    551 *     };
    552 *
    553 *     template<typename T>
    554 *     using Tree = Variant<Leaf, Node<T>>;
    555 *
    556 * A copy-on-write string is either a non-owning reference to some existing
    557 * string, or an owning reference to our copy:
    558 *
    559 *     class CopyOnWriteString
    560 *     {
    561 *       Variant<const char*, UniquePtr<char[]>> string;
    562 *
    563 *       ...
    564 *     };
    565 *
    566 * Because Variant must be aligned suitable to hold any value stored within it,
    567 * and because |alignas| requirements don't affect platform ABI with respect to
    568 * how parameters are laid out in memory, Variant can't be used as the type of a
    569 * function parameter.  Pass Variant to functions by pointer or reference
    570 * instead.
    571 */
    572 template <typename... Ts>
    573 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS
    574 MOZ_NON_PARAM MOZ_GSL_OWNER Variant {
    575  friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
    576 
    577  using Tag = typename detail::VariantTag<Ts...>::Type;
    578  using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
    579 
    580  static constexpr size_t RawDataAlignment = std::max({alignof(Ts)...});
    581  static constexpr size_t RawDataSize = std::max({sizeof(Ts)...});
    582 
    583  // Raw storage for the contained variant value.
    584  alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
    585 
    586  // Each type is given a unique tag value that lets us keep track of the
    587  // contained variant value's type.
    588  Tag tag;
    589 
    590  // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
    591  // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
    592  // through |void*|.  Placing the latter cast in these separate functions
    593  // breaks the chain such that affected GCC versions no longer warn/error.
    594  void* ptr() { return rawData; }
    595 
    596  const void* ptr() const { return rawData; }
    597 
    598 public:
    599  /** Perfect forwarding construction for some variant type T. */
    600  template <typename RefT,
    601            // RefT captures both const& as well as && (as intended, to support
    602            // perfect forwarding), so we have to remove those qualifiers here
    603            // when ensuring that T is a variant of this type, and getting T's
    604            // tag, etc.
    605            typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
    606  explicit Variant(RefT&& aT) : tag(Impl::template tag<T>()) {
    607    static_assert(
    608        detail::SelectVariantType<RefT, Ts...>::count == 1,
    609        "Variant can only be selected by type if that type is unique");
    610    ::new (KnownNotNull, ptr()) T(std::forward<RefT>(aT));
    611  }
    612 
    613  /**
    614   * Perfect forwarding construction for some variant type T, by
    615   * explicitly giving the type.
    616   * This is necessary to construct from any number of arguments,
    617   * or to convert from a type that is not in the Variant's type list.
    618   */
    619  template <typename T, typename... Args>
    620  MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs)
    621      : tag(Impl::template tag<T>()) {
    622    ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
    623  }
    624 
    625  /**
    626   * Perfect forwarding construction for some variant type T, by
    627   * explicitly giving the type index.
    628   * This is necessary to construct from any number of arguments,
    629   * or to convert from a type that is not in the Variant's type list,
    630   * or to construct a type that is present more than once in the Variant.
    631   */
    632  template <size_t N, typename... Args>
    633  MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs) : tag(N) {
    634    using T = typename detail::Nth<N, Ts...>::Type;
    635    ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
    636  }
    637 
    638  /**
    639   * Constructs this Variant from an AsVariantTemporary<T> such that T can be
    640   * stored in one of the types allowable in this Variant. This is used in the
    641   * implementation of AsVariant().
    642   */
    643  template <typename RefT>
    644  MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
    645      : tag(Impl::template tag<
    646            typename detail::SelectVariantType<RefT, Ts...>::Type>()) {
    647    using T = typename detail::SelectVariantType<RefT, Ts...>::Type;
    648    static_assert(
    649        detail::SelectVariantType<RefT, Ts...>::count == 1,
    650        "Variant can only be selected by type if that type is unique");
    651    ::new (KnownNotNull, ptr()) T(std::move(aValue.mValue));
    652  }
    653 
    654  /** Copy construction. */
    655  Variant(const Variant& aRhs) : tag(aRhs.tag) {
    656    Impl::copyConstruct(ptr(), aRhs);
    657  }
    658 
    659  /** Move construction. */
    660  Variant(Variant&& aRhs) : tag(aRhs.tag) {
    661    Impl::moveConstruct(ptr(), std::move(aRhs));
    662  }
    663 
    664  /** Copy assignment. */
    665  Variant& operator=(const Variant& aRhs) {
    666    MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
    667    this->~Variant();
    668    ::new (KnownNotNull, this) Variant(aRhs);
    669    return *this;
    670  }
    671 
    672  /** Move assignment. */
    673  Variant& operator=(Variant&& aRhs) {
    674    MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
    675    this->~Variant();
    676    ::new (KnownNotNull, this) Variant(std::move(aRhs));
    677    return *this;
    678  }
    679 
    680  /** Move assignment from AsVariant(). */
    681  template <typename T>
    682  Variant& operator=(detail::AsVariantTemporary<T>&& aValue) {
    683    static_assert(
    684        detail::SelectVariantType<T, Ts...>::count == 1,
    685        "Variant can only be selected by type if that type is unique");
    686    this->~Variant();
    687    ::new (KnownNotNull, this) Variant(std::move(aValue));
    688    return *this;
    689  }
    690 
    691  ~Variant() { Impl::destroy(*this); }
    692 
    693  template <typename T, typename... Args>
    694  T& emplace(Args&&... aTs) {
    695    Impl::destroy(*this);
    696    tag = Impl::template tag<T>();
    697    ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
    698    return as<T>();
    699  }
    700 
    701  template <size_t N, typename... Args>
    702  typename detail::Nth<N, Ts...>::Type& emplace(Args&&... aTs) {
    703    using T = typename detail::Nth<N, Ts...>::Type;
    704    Impl::destroy(*this);
    705    tag = N;
    706    ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
    707    return as<N>();
    708  }
    709 
    710  /** Check which variant type is currently contained. */
    711  template <typename T>
    712  bool is() const {
    713    static_assert(
    714        detail::SelectVariantType<T, Ts...>::count == 1,
    715        "provided a type not uniquely found in this Variant's type list");
    716    return Impl::template tag<T>() == tag;
    717  }
    718 
    719  template <size_t N>
    720  bool is() const {
    721    static_assert(N < sizeof...(Ts),
    722                  "provided an index outside of this Variant's type list");
    723    return N == size_t(tag);
    724  }
    725 
    726  /**
    727   * Operator == overload that defers to the variant type's operator==
    728   * implementation if the rhs is tagged as the same type as this one.
    729   */
    730  bool operator==(const Variant& aRhs) const {
    731    return tag == aRhs.tag && Impl::equal(*this, aRhs);
    732  }
    733 
    734  /**
    735   * Operator != overload that defers to the negation of the variant type's
    736   * operator== implementation if the rhs is tagged as the same type as this
    737   * one.
    738   */
    739  bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); }
    740 
    741  // Accessors for working with the contained variant value.
    742 
    743  /** Mutable lvalue-reference. */
    744  template <typename T>
    745      T& as() & MOZ_LIFETIME_BOUND {
    746    static_assert(
    747        detail::SelectVariantType<T, Ts...>::count == 1,
    748        "provided a type not uniquely found in this Variant's type list");
    749    MOZ_RELEASE_ASSERT(is<T>());
    750    return *static_cast<T*>(ptr());
    751  }
    752 
    753  template <size_t N>
    754      typename detail::Nth<N, Ts...>::Type& as() & MOZ_LIFETIME_BOUND {
    755    static_assert(N < sizeof...(Ts),
    756                  "provided an index outside of this Variant's type list");
    757    MOZ_RELEASE_ASSERT(is<N>());
    758    return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
    759  }
    760 
    761  /** Immutable const lvalue-reference. */
    762  template <typename T>
    763  const T& as() const& MOZ_LIFETIME_BOUND {
    764    static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
    765                  "provided a type not found in this Variant's type list");
    766    MOZ_RELEASE_ASSERT(is<T>());
    767    return *static_cast<const T*>(ptr());
    768  }
    769 
    770  template <size_t N>
    771  const typename detail::Nth<N, Ts...>::Type& as() const& MOZ_LIFETIME_BOUND {
    772    static_assert(N < sizeof...(Ts),
    773                  "provided an index outside of this Variant's type list");
    774    MOZ_RELEASE_ASSERT(is<N>());
    775    return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
    776  }
    777 
    778  /** Mutable rvalue-reference. */
    779  template <typename T>
    780      T&& as() && MOZ_LIFETIME_BOUND {
    781    static_assert(
    782        detail::SelectVariantType<T, Ts...>::count == 1,
    783        "provided a type not uniquely found in this Variant's type list");
    784    MOZ_RELEASE_ASSERT(is<T>());
    785    return std::move(*static_cast<T*>(ptr()));
    786  }
    787 
    788  template <size_t N>
    789      typename detail::Nth<N, Ts...>::Type&& as() && MOZ_LIFETIME_BOUND {
    790    static_assert(N < sizeof...(Ts),
    791                  "provided an index outside of this Variant's type list");
    792    MOZ_RELEASE_ASSERT(is<N>());
    793    return std::move(
    794        *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr()));
    795  }
    796 
    797  /** Immutable const rvalue-reference. */
    798  template <typename T>
    799  const T&& as() const&& MOZ_LIFETIME_BOUND {
    800    static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
    801                  "provided a type not found in this Variant's type list");
    802    MOZ_RELEASE_ASSERT(is<T>());
    803    return std::move(*static_cast<const T*>(ptr()));
    804  }
    805 
    806  template <size_t N>
    807  const typename detail::Nth<N, Ts...>::Type&& as() const&& MOZ_LIFETIME_BOUND {
    808    static_assert(N < sizeof...(Ts),
    809                  "provided an index outside of this Variant's type list");
    810    MOZ_RELEASE_ASSERT(is<N>());
    811    return std::move(
    812        *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr()));
    813  }
    814 
    815  /**
    816   * Extract the contained variant value from this container into a temporary
    817   * value.  On completion, the value in the variant will be in a
    818   * safely-destructible state, as determined by the behavior of T's move
    819   * constructor when provided the variant's internal value.
    820   */
    821  template <typename T>
    822  T extract() {
    823    static_assert(
    824        detail::SelectVariantType<T, Ts...>::count == 1,
    825        "provided a type not uniquely found in this Variant's type list");
    826    MOZ_ASSERT(is<T>());
    827    return T(std::move(as<T>()));
    828  }
    829 
    830  template <size_t N>
    831  typename detail::Nth<N, Ts...>::Type extract() {
    832    static_assert(N < sizeof...(Ts),
    833                  "provided an index outside of this Variant's type list");
    834    MOZ_RELEASE_ASSERT(is<N>());
    835    return typename detail::Nth<N, Ts...>::Type(std::move(as<N>()));
    836  }
    837 
    838  // Exhaustive matching of all variant types on the contained value.
    839 
    840  /** Match on an immutable const lvalue-reference. */
    841  template <typename Matcher>
    842  decltype(auto) match(Matcher&& aMatcher) const& {
    843    return Impl::match(std::forward<Matcher>(aMatcher), *this);
    844  }
    845 
    846  template <typename M0, typename M1, typename... Ms>
    847  decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const& {
    848    return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
    849                  std::forward<Ms>(aMs)...);
    850  }
    851 
    852  /** Match on a mutable non-const lvalue-reference. */
    853  template <typename Matcher>
    854  decltype(auto) match(Matcher&& aMatcher) & {
    855    return Impl::match(std::forward<Matcher>(aMatcher), *this);
    856  }
    857 
    858  template <typename M0, typename M1, typename... Ms>
    859  decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) & {
    860    return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
    861                  std::forward<Ms>(aMs)...);
    862  }
    863 
    864  /** Match on an immutable const rvalue-reference. */
    865  template <typename Matcher>
    866  decltype(auto) match(Matcher&& aMatcher) const&& {
    867    return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this));
    868  }
    869 
    870  template <typename M0, typename M1, typename... Ms>
    871  decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const&& {
    872    return matchN(std::move(*this), std::forward<M0>(aM0),
    873                  std::forward<M1>(aM1), std::forward<Ms>(aMs)...);
    874  }
    875 
    876  /** Match on a mutable non-const rvalue-reference. */
    877  template <typename Matcher>
    878  decltype(auto) match(Matcher&& aMatcher) && {
    879    return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this));
    880  }
    881 
    882  template <typename M0, typename M1, typename... Ms>
    883  decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) && {
    884    return matchN(std::move(*this), std::forward<M0>(aM0),
    885                  std::forward<M1>(aM1), std::forward<Ms>(aMs)...);
    886  }
    887 
    888  /**
    889   * Incorporate the current variant's tag into hashValue.
    890   * Note that this does not hash the actual contents; you must take
    891   * care of that yourself, perhaps by using a match.
    892   */
    893  mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const {
    894    return mozilla::AddToHash(hashValue, tag);
    895  }
    896 
    897 private:
    898  template <typename ConcreteVariant, typename M0, typename M1, typename... Ms>
    899  static decltype(auto) matchN(ConcreteVariant&& aVariant, M0&& aM0, M1&& aM1,
    900                               Ms&&... aMs) {
    901    static_assert(
    902        2 + sizeof...(Ms) == sizeof...(Ts),
    903        "Variant<T...>::match() takes either one callable argument that "
    904        "accepts every type T; or one for each type T, in order");
    905    return Impl::matchN(std::forward<ConcreteVariant>(aVariant),
    906                        std::forward<M0>(aM0), std::forward<M1>(aM1),
    907                        std::forward<Ms>(aMs)...);
    908  }
    909 };
    910 
    911 /*
    912 * AsVariant() is used to construct a Variant<T,...> value containing the
    913 * provided T value using type inference. It can be used to construct Variant
    914 * values in expressions or return them from functions without specifying the
    915 * entire Variant type.
    916 *
    917 * Because AsVariant() must copy or move the value into a temporary and this
    918 * cannot necessarily be elided by the compiler, it's mostly appropriate only
    919 * for use with primitive or very small types.
    920 *
    921 * AsVariant() returns a AsVariantTemporary value which is implicitly
    922 * convertible to any Variant that can hold a value of type T.
    923 */
    924 template <typename T>
    925 detail::AsVariantTemporary<T> AsVariant(T&& aValue) {
    926  return detail::AsVariantTemporary<T>(std::forward<T>(aValue));
    927 }
    928 
    929 }  // namespace mozilla
    930 
    931 #endif /* mozilla_Variant_h */