LCOV - code coverage report
Current view: top level - mfbt - Variant.h (source / functions) Hit Total Coverage
Test: output.info Lines: 115 123 93.5 %
Date: 2017-07-14 16:53:18 Functions: 640 2434 26.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <new>
      10             : #include <stdint.h>
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/Move.h"
      14             : #include "mozilla/OperatorNewExtensions.h"
      15             : #include "mozilla/TemplateLib.h"
      16             : #include "mozilla/TypeTraits.h"
      17             : 
      18             : #ifndef mozilla_Variant_h
      19             : #define mozilla_Variant_h
      20             : 
      21             : namespace mozilla {
      22             : 
      23             : template<typename... Ts>
      24             : class Variant;
      25             : 
      26             : namespace detail {
      27             : 
      28             : // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
      29             : template<size_t N, typename... Ts>
      30             : struct Nth;
      31             : 
      32             : template<typename T, typename... Ts>
      33             : struct Nth<0, T, Ts...>
      34             : {
      35             :   using Type = T;
      36             : };
      37             : 
      38             : template<size_t N, typename T, typename... Ts>
      39             : struct Nth<N, T, Ts...>
      40             : {
      41             :   using Type = typename Nth<N - 1, Ts...>::Type;
      42             : };
      43             : 
      44             : /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
      45             : template<typename T, typename... Variants>
      46             : struct SelectVariantTypeHelper;
      47             : 
      48             : template<typename T>
      49             : struct SelectVariantTypeHelper<T>
      50             : {
      51             :   static constexpr size_t count = 0;
      52             : };
      53             : 
      54             : template<typename T, typename... Variants>
      55             : struct SelectVariantTypeHelper<T, T, Variants...>
      56             : {
      57             :   typedef T Type;
      58             :   static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
      59             : };
      60             : 
      61             : template<typename T, typename... Variants>
      62             : struct SelectVariantTypeHelper<T, const T, Variants...>
      63             : {
      64             :   typedef const T Type;
      65             :   static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
      66             : };
      67             : 
      68             : template<typename T, typename... Variants>
      69             : struct SelectVariantTypeHelper<T, const T&, Variants...>
      70             : {
      71             :   typedef const T& Type;
      72             :   static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
      73             : };
      74             : 
      75             : template<typename T, typename... Variants>
      76             : struct SelectVariantTypeHelper<T, T&&, Variants...>
      77             : {
      78             :   typedef T&& Type;
      79             :   static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
      80             : };
      81             : 
      82             : template<typename T, typename Head, typename... Variants>
      83             : struct SelectVariantTypeHelper<T, Head, Variants...>
      84             :   : public SelectVariantTypeHelper<T, Variants...>
      85             : { };
      86             : 
      87             : /**
      88             :  * SelectVariantType takes a type T and a list of variant types Variants and
      89             :  * yields a type Type, selected from Variants, that can store a value of type T
      90             :  * or a reference to type T. If no such type was found, Type is not defined.
      91             :  * SelectVariantType also has a `count` member that contains the total number of
      92             :  * selectable types (which will be used to check that a requested type is not
      93             :  * ambiguously present twice.)
      94             :  */
      95             : template <typename T, typename... Variants>
      96             : struct SelectVariantType
      97             :   : public SelectVariantTypeHelper<typename RemoveConst<typename RemoveReference<T>::Type>::Type,
      98             :                                    Variants...>
      99             : { };
     100             : 
     101             : // Compute a fast, compact type that can be used to hold integral values that
     102             : // distinctly map to every type in Ts.
     103             : template<typename... Ts>
     104             : struct VariantTag
     105             : {
     106             : private:
     107             :   static const size_t TypeCount = sizeof...(Ts);
     108             : 
     109             : public:
     110             :   using Type =
     111             :     typename Conditional<TypeCount < 3,
     112             :                          bool,
     113             :                          typename Conditional<TypeCount < (1 << 8),
     114             :                                               uint_fast8_t,
     115             :                                               size_t // stop caring past a certain point :-)
     116             :                                               >::Type
     117             :                          >::Type;
     118             : };
     119             : 
     120             : // TagHelper gets the given sentinel tag value for the given type T. This has to
     121             : // be split out from VariantImplementation because you can't nest a partial
     122             : // template specialization within a template class.
     123             : 
     124             : template<typename Tag, size_t N, typename T, typename U, typename Next, 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             : {
     131      815721 :   static Tag tag() { return Next::template tag<U>(); }
     132             : };
     133             : 
     134             : // In the case where T == U, return the tag number.
     135             : template<typename Tag, size_t N, typename T, typename U, typename Next>
     136             : struct TagHelper<Tag, N, T, U, Next, true>
     137             : {
     138      405416 :   static Tag tag() { return Tag(N); }
     139             : };
     140             : 
     141             : // The VariantImplementation template provides the guts of mozilla::Variant.  We
     142             : // create a VariantImplementation for each T in Ts... which handles
     143             : // construction, destruction, etc for when the Variant's type is T.  If the
     144             : // Variant's type isn't T, it punts the request on to the next
     145             : // VariantImplementation.
     146             : 
     147             : template<typename Tag, size_t N, typename... Ts>
     148             : struct VariantImplementation;
     149             : 
     150             : // The singly typed Variant / recursion base case.
     151             : template<typename Tag, size_t N, typename T>
     152             : struct VariantImplementation<Tag, N, T>
     153             : {
     154             :   template<typename U>
     155      364473 :   static Tag tag() {
     156             :     static_assert(mozilla::IsSame<T, U>::value,
     157             :                   "mozilla::Variant: tag: bad type!");
     158      364473 :     return Tag(N);
     159             :   }
     160             : 
     161             :   template<typename Variant>
     162        6644 :   static void copyConstruct(void* aLhs, const Variant& aRhs) {
     163        6644 :     ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
     164        6644 :   }
     165             : 
     166             :   template<typename Variant>
     167       17174 :   static void moveConstruct(void* aLhs, Variant&& aRhs) {
     168       17174 :     ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
     169       17174 :   }
     170             : 
     171             :   template<typename Variant>
     172       42971 :   static void destroy(Variant& aV) {
     173       42971 :     aV.template as<N>().~T();
     174       42971 :   }
     175             : 
     176             :   template<typename Variant>
     177             :   static bool
     178          68 :   equal(const Variant& aLhs, const Variant& aRhs) {
     179          68 :       return aLhs.template as<N>() == aRhs.template as<N>();
     180             :   }
     181             : 
     182             :   template<typename Matcher, typename ConcreteVariant>
     183             :   static auto
     184      464933 :   match(Matcher&& aMatcher, ConcreteVariant& aV)
     185             :     -> decltype(aMatcher.match(aV.template as<N>()))
     186             :   {
     187      464933 :     return aMatcher.match(aV.template as<N>());
     188             :   }
     189             : };
     190             : 
     191             : // VariantImplementation for some variant type T.
     192             : template<typename Tag, size_t N, typename T, typename... Ts>
     193             : struct VariantImplementation<Tag, N, T, Ts...>
     194             : {
     195             :   // The next recursive VariantImplementation.
     196             :   using Next = VariantImplementation<Tag, N + 1, Ts...>;
     197             : 
     198             :   template<typename U>
     199     1221136 :   static Tag tag() {
     200     1221136 :     return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
     201             :   }
     202             : 
     203             :   template<typename Variant>
     204       67424 :   static void copyConstruct(void* aLhs, const Variant& aRhs) {
     205       67424 :     if (aRhs.template is<N>()) {
     206       65924 :       ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
     207             :     } else {
     208        1500 :       Next::copyConstruct(aLhs, aRhs);
     209             :     }
     210       67424 :   }
     211             : 
     212             :   template<typename Variant>
     213      105804 :   static void moveConstruct(void* aLhs, Variant&& aRhs) {
     214      105804 :     if (aRhs.template is<N>()) {
     215       53641 :       ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
     216             :     } else {
     217       52163 :       Next::moveConstruct(aLhs, Move(aRhs));
     218             :     }
     219      105804 :   }
     220             : 
     221             :   template<typename Variant>
     222      376110 :   static void destroy(Variant& aV) {
     223      376110 :     if (aV.template is<N>()) {
     224      269917 :       aV.template as<N>().~T();
     225             :     } else {
     226      106196 :       Next::destroy(aV);
     227             :     }
     228      376182 :   }
     229             : 
     230             :   template<typename Variant>
     231       30139 :   static bool equal(const Variant& aLhs, const Variant& aRhs) {
     232       30139 :     if (aLhs.template is<N>()) {
     233       30062 :       MOZ_ASSERT(aRhs.template is<N>());
     234       30062 :       return aLhs.template as<N>() == aRhs.template as<N>();
     235             :     } else {
     236          77 :       return Next::equal(aLhs, aRhs);
     237             :     }
     238             :   }
     239             : 
     240             :   template<typename Matcher, typename ConcreteVariant>
     241             :   static auto
     242      252444 :   match(Matcher&& aMatcher, ConcreteVariant& aV)
     243             :     -> decltype(aMatcher.match(aV.template as<N>()))
     244             :   {
     245      252444 :     if (aV.template is<N>()) {
     246      198982 :       return aMatcher.match(aV.template as<N>());
     247             :     } else {
     248             :       // If you're seeing compilation errors here like "no matching
     249             :       // function for call to 'match'" then that means that the
     250             :       // Matcher doesn't exhaust all variant types. There must exist a
     251             :       // Matcher::match(T&) for every variant type T.
     252             :       //
     253             :       // If you're seeing compilation errors here like "cannot
     254             :       // initialize return object of type <...> with an rvalue of type
     255             :       // <...>" then that means that the Matcher::match(T&) overloads
     256             :       // are returning different types. They must all return the same
     257             :       // Matcher::ReturnType type.
     258       53462 :       return Next::match(aMatcher, aV);
     259             :     }
     260             :   }
     261             : };
     262             : 
     263             : /**
     264             :  * AsVariantTemporary stores a value of type T to allow construction of a
     265             :  * Variant value via type inference. Because T is copied and there's no
     266             :  * guarantee that the copy can be elided, AsVariantTemporary is best used with
     267             :  * primitive or very small types.
     268             :  */
     269             : template <typename T>
     270           0 : struct AsVariantTemporary
     271             : {
     272       57214 :   explicit AsVariantTemporary(const T& aValue)
     273       57214 :     : mValue(aValue)
     274       57214 :   {}
     275             : 
     276             :   template<typename U>
     277         104 :   explicit AsVariantTemporary(U&& aValue)
     278         104 :     : mValue(Forward<U>(aValue))
     279         104 :   {}
     280             : 
     281             :   AsVariantTemporary(const AsVariantTemporary& aOther)
     282             :     : mValue(aOther.mValue)
     283             :   {}
     284             : 
     285           0 :   AsVariantTemporary(AsVariantTemporary&& aOther)
     286           0 :     : mValue(Move(aOther.mValue))
     287           0 :   {}
     288             : 
     289             :   AsVariantTemporary() = delete;
     290             :   void operator=(const AsVariantTemporary&) = delete;
     291             :   void operator=(AsVariantTemporary&&) = delete;
     292             : 
     293             :   typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
     294             : };
     295             : 
     296             : } // namespace detail
     297             : 
     298             : // Used to unambiguously specify one of the Variant's type.
     299             : template<typename T> struct VariantType { using Type = T; };
     300             : 
     301             : // Used to specify one of the Variant's type by index.
     302             : template<size_t N> struct VariantIndex { static constexpr size_t index = N; };
     303             : 
     304             : /**
     305             :  * # mozilla::Variant
     306             :  *
     307             :  * A variant / tagged union / heterogenous disjoint union / sum-type template
     308             :  * class. Similar in concept to (but not derived from) `boost::variant`.
     309             :  *
     310             :  * Sometimes, you may wish to use a C union with non-POD types. However, this is
     311             :  * forbidden in C++ because it is not clear which type in the union should have
     312             :  * its constructor and destructor run on creation and deletion
     313             :  * respectively. This is the problem that `mozilla::Variant` solves.
     314             :  *
     315             :  * ## Usage
     316             :  *
     317             :  * A `mozilla::Variant` instance is constructed (via move or copy) from one of
     318             :  * its variant types (ignoring const and references). It does *not* support
     319             :  * construction from subclasses of variant types or types that coerce to one of
     320             :  * the variant types.
     321             :  *
     322             :  *     Variant<char, uint32_t> v1('a');
     323             :  *     Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
     324             :  *     Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
     325             :  *     Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
     326             :  *
     327             :  * Because specifying the full type of a Variant value is often verbose,
     328             :  * there are two easier ways to construct values:
     329             :  *
     330             :  * A. AsVariant() can be used to construct a Variant value using type inference
     331             :  * in contexts such as expressions or when returning values from functions.
     332             :  * Because AsVariant() must copy or move the value into a temporary and this
     333             :  * cannot necessarily be elided by the compiler, it's mostly appropriate only
     334             :  * for use with primitive or very small types.
     335             :  *
     336             :  *     Variant<char, uint32_t> Foo() { return AsVariant('x'); }
     337             :  *     // ...
     338             :  *     Variant<char, uint32_t> v1 = Foo();  // v1 holds char('x').
     339             :  *
     340             :  * B. Brace-construction with VariantType or VariantIndex; this also allows
     341             :  * in-place construction with any number of arguments.
     342             :  *
     343             :  *     struct AB { AB(int, int){...} };
     344             :  *     static Variant<AB, bool> foo()
     345             :  *     {
     346             :  *       return {VariantIndex<0>{}, 1, 2};
     347             :  *     }
     348             :  *     // ...
     349             :  *     Variant<AB, bool> v0 = Foo();  // v0 holds AB(1,2).
     350             :  *
     351             :  * All access to the contained value goes through type-safe accessors.
     352             :  * Either the stored type, or the type index may be provided.
     353             :  *
     354             :  *     void
     355             :  *     Foo(Variant<A, B, C> v)
     356             :  *     {
     357             :  *       if (v.is<A>()) {
     358             :  *         A& ref = v.as<A>();
     359             :  *         ...
     360             :  *       } else (v.is<1>()) { // Instead of v.is<B>.
     361             :  *         ...
     362             :  *       } else {
     363             :  *         ...
     364             :  *       }
     365             :  *     }
     366             :  *
     367             :  * In some situation, a Variant may be constructed from templated types, in
     368             :  * which case it is possible that the same type could be given multiple times by
     369             :  * an external developer. Or seemingly-different types could be aliases.
     370             :  * In this case, repeated types can only be accessed through their index, to
     371             :  * prevent ambiguous access by type.
     372             :  *
     373             :  *    // Bad!
     374             :  *    template <typename T>
     375             :  *    struct ResultOrError
     376             :  *    {
     377             :  *      Variant<T, int> m;
     378             :  *      ResultOrError() : m(int(0)) {} // Error '0' by default
     379             :  *      ResultOrError(const T& r) : m(r) {}
     380             :  *      bool IsResult() const { return m.is<T>(); }
     381             :  *      bool IsError() const { return m.is<int>(); }
     382             :  *    };
     383             :  *    // Now instantiante with the result being an int too:
     384             :  *    ResultOrError<int> myResult(123); // Fail!
     385             :  *    // In Variant<int, int>, which 'int' are we refering to, from inside
     386             :  *    // ResultOrError functions?
     387             :  *
     388             :  *    // Good!
     389             :  *    template <typename T>
     390             :  *    struct ResultOrError
     391             :  *    {
     392             :  *      Variant<T, int> m;
     393             :  *      ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
     394             :  *      ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
     395             :  *      bool IsResult() const { return m.is<0>(); } // 0 -> T
     396             :  *      bool IsError() const { return m.is<1>(); } // 1 -> int
     397             :  *    };
     398             :  *    // Now instantiante with the result being an int too:
     399             :  *    ResultOrError<int> myResult(123); // It now works!
     400             :  *
     401             :  * Attempting to use the contained value as type `T1` when the `Variant`
     402             :  * instance contains a value of type `T2` causes an assertion failure.
     403             :  *
     404             :  *     A a;
     405             :  *     Variant<A, B, C> v(a);
     406             :  *     v.as<B>(); // <--- Assertion failure!
     407             :  *
     408             :  * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
     409             :  * member of the set of `Ts...` is a compiler error.
     410             :  *
     411             :  *     A a;
     412             :  *     Variant<A, B, C> v(a);
     413             :  *     v.as<SomeRandomType>(); // <--- Compiler error!
     414             :  *
     415             :  * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
     416             :  * out of the containing `Variant` instance with the `extract<T>` method:
     417             :  *
     418             :  *     Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
     419             :  *     auto ptr = v.extract<UniquePtr<A>>();
     420             :  *
     421             :  * Finally, you can exhaustively match on the contained variant and branch into
     422             :  * different code paths depending on which type is contained. This is preferred
     423             :  * to manually checking every variant type T with is<T>() because it provides
     424             :  * compile-time checking that you handled every type, rather than runtime
     425             :  * assertion failures.
     426             :  *
     427             :  *     // Bad!
     428             :  *     char* foo(Variant<A, B, C, D>& v) {
     429             :  *       if (v.is<A>()) {
     430             :  *         return ...;
     431             :  *       } else if (v.is<B>()) {
     432             :  *         return ...;
     433             :  *       } else {
     434             :  *         return doSomething(v.as<C>()); // Forgot about case D!
     435             :  *       }
     436             :  *     }
     437             :  *
     438             :  *     // Good!
     439             :  *     struct FooMatcher
     440             :  *     {
     441             :  *       // The return type of all matchers must be identical.
     442             :  *       char* match(A& a) { ... }
     443             :  *       char* match(B& b) { ... }
     444             :  *       char* match(C& c) { ... }
     445             :  *       char* match(D& d) { ... } // Compile-time error to forget D!
     446             :  *     }
     447             :  *     char* foo(Variant<A, B, C, D>& v) {
     448             :  *       return v.match(FooMatcher());
     449             :  *     }
     450             :  *
     451             :  * ## Examples
     452             :  *
     453             :  * A tree is either an empty leaf, or a node with a value and two children:
     454             :  *
     455             :  *     struct Leaf { };
     456             :  *
     457             :  *     template<typename T>
     458             :  *     struct Node
     459             :  *     {
     460             :  *       T value;
     461             :  *       Tree<T>* left;
     462             :  *       Tree<T>* right;
     463             :  *     };
     464             :  *
     465             :  *     template<typename T>
     466             :  *     using Tree = Variant<Leaf, Node<T>>;
     467             :  *
     468             :  * A copy-on-write string is either a non-owning reference to some existing
     469             :  * string, or an owning reference to our copy:
     470             :  *
     471             :  *     class CopyOnWriteString
     472             :  *     {
     473             :  *       Variant<const char*, UniquePtr<char[]>> string;
     474             :  *
     475             :  *       ...
     476             :  *     };
     477             :  *
     478             :  * Because Variant must be aligned suitable to hold any value stored within it,
     479             :  * and because |alignas| requirements don't affect platform ABI with respect to
     480             :  * how parameters are laid out in memory, Variant can't be used as the type of a
     481             :  * function parameter.  Pass Variant to functions by pointer or reference
     482             :  * instead.
     483             :  */
     484             : template<typename... Ts>
     485             : class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
     486             : {
     487             :   using Tag = typename detail::VariantTag<Ts...>::Type;
     488             :   using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
     489             : 
     490             :   static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
     491             :   static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
     492             : 
     493             :   // Raw storage for the contained variant value.
     494             :   alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
     495             : 
     496             :   // Each type is given a unique tag value that lets us keep track of the
     497             :   // contained variant value's type.
     498             :   Tag tag;
     499             : 
     500             :   // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
     501             :   // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
     502             :   // through |void*|.  Placing the latter cast in these separate functions
     503             :   // breaks the chain such that affected GCC versions no longer warn/error.
     504      885049 :   void* ptr() {
     505      885049 :     return rawData;
     506             :   }
     507             : 
     508      712255 :   const void* ptr() const {
     509      712255 :     return rawData;
     510             :   }
     511             : 
     512             : public:
     513             :   /** Perfect forwarding construction for some variant type T. */
     514             :   template<typename RefT,
     515             :            // RefT captures both const& as well as && (as intended, to support
     516             :            // perfect forwarding), so we have to remove those qualifiers here
     517             :            // when ensuring that T is a variant of this type, and getting T's
     518             :            // tag, etc.
     519             :            typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
     520      123916 :   explicit Variant(RefT&& aT)
     521      123916 :     : tag(Impl::template tag<T>())
     522             :   {
     523             :     static_assert(detail::SelectVariantType<RefT, Ts...>::count == 1,
     524             :                   "Variant can only be selected by type if that type is unique");
     525      123916 :     ::new (KnownNotNull, ptr()) T(Forward<RefT>(aT));
     526      123916 :   }
     527             : 
     528             :   /**
     529             :    * Perfect forwarding construction for some variant type T, by
     530             :    * explicitly giving the type.
     531             :    * This is necessary to construct from any number of arguments,
     532             :    * or to convert from a type that is not in the Variant's type list.
     533             :    */
     534             :   template<typename T, typename... Args>
     535             :   MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs)
     536             :     : tag(Impl::template tag<T>())
     537             :   {
     538             :     ::new (KnownNotNull, ptr()) T(Forward<Args>(aTs)...);
     539             :   }
     540             : 
     541             :   /**
     542             :    * Perfect forwarding construction for some variant type T, by
     543             :    * explicitly giving the type index.
     544             :    * This is necessary to construct from any number of arguments,
     545             :    * or to convert from a type that is not in the Variant's type list,
     546             :    * or to construct a type that is present more than once in the Variant.
     547             :    */
     548             :   template<size_t N, typename... Args>
     549          26 :   MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs)
     550          26 :     : tag(N)
     551             :   {
     552             :     using T = typename detail::Nth<N, Ts...>::Type;
     553          26 :     ::new (KnownNotNull, ptr()) T(Forward<Args>(aTs)...);
     554          26 :   }
     555             : 
     556             :   /**
     557             :    * Constructs this Variant from an AsVariantTemporary<T> such that T can be
     558             :    * stored in one of the types allowable in this Variant. This is used in the
     559             :    * implementation of AsVariant().
     560             :    */
     561             :   template<typename RefT>
     562       57316 :   MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
     563       57316 :     : tag(Impl::template tag<typename detail::SelectVariantType<RefT, Ts...>::Type>())
     564             :   {
     565             :     using T = typename detail::SelectVariantType<RefT, Ts...>::Type;
     566             :     static_assert(detail::SelectVariantType<RefT, Ts...>::count == 1,
     567             :                   "Variant can only be selected by type if that type is unique");
     568       57308 :     ::new (KnownNotNull, ptr()) T(Move(aValue.mValue));
     569       57302 :   }
     570             : 
     571             :   /** Copy construction. */
     572       72568 :   Variant(const Variant& aRhs)
     573       72568 :     : tag(aRhs.tag)
     574             :   {
     575       72568 :     Impl::copyConstruct(ptr(), aRhs);
     576       72568 :   }
     577             : 
     578             :   /** Move construction. */
     579       70815 :   Variant(Variant&& aRhs)
     580       70815 :     : tag(aRhs.tag)
     581             :   {
     582       70815 :     Impl::moveConstruct(ptr(), Move(aRhs));
     583       70815 :   }
     584             : 
     585             :   /** Copy assignment. */
     586       18555 :   Variant& operator=(const Variant& aRhs) {
     587       18555 :     MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
     588       18555 :     this->~Variant();
     589       18555 :     ::new (KnownNotNull, this) Variant(aRhs);
     590       18555 :     return *this;
     591             :   }
     592             : 
     593             :   /** Move assignment. */
     594       38003 :   Variant& operator=(Variant&& aRhs) {
     595       38003 :     MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
     596       38003 :     this->~Variant();
     597       38003 :     ::new (KnownNotNull, this) Variant(Move(aRhs));
     598       38003 :     return *this;
     599             :   }
     600             : 
     601             :   /** Move assignment from AsVariant(). */
     602             :   template<typename T>
     603           0 :   Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
     604             :   {
     605             :     static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
     606             :                   "Variant can only be selected by type if that type is unique");
     607           0 :     this->~Variant();
     608           0 :     ::new (KnownNotNull, this) Variant(Move(aValue));
     609           0 :     return *this;
     610             :   }
     611             : 
     612      312902 :   ~Variant()
     613             :   {
     614      312902 :     Impl::destroy(*this);
     615      312959 :   }
     616             : 
     617             :   /** Check which variant type is currently contained. */
     618             :   template<typename T>
     619      589784 :   bool is() const {
     620             :     static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
     621             :                   "provided a type not uniquely found in this Variant's type list");
     622      589784 :     return Impl::template tag<T>() == tag;
     623             :   }
     624             : 
     625             :   template<size_t N>
     626     2113069 :   bool is() const
     627             :   {
     628             :     static_assert(N < sizeof...(Ts),
     629             :                   "provided an index outside of this Variant's type list");
     630     2113069 :     return N == size_t(tag);
     631             :   }
     632             : 
     633             :   /**
     634             :    * Operator == overload that defers to the variant type's operator==
     635             :    * implementation if the rhs is tagged as the same type as this one.
     636             :    */
     637       30130 :   bool operator==(const Variant& aRhs) const {
     638       30130 :     return tag == aRhs.tag && Impl::equal(*this, aRhs);
     639             :   }
     640             : 
     641             :   /**
     642             :    * Operator != overload that defers to the negation of the variant type's
     643             :    * operator== implementation if the rhs is tagged as the same type as this
     644             :    * one.
     645             :    */
     646        2101 :   bool operator!=(const Variant& aRhs) const {
     647        2101 :     return !(*this == aRhs);
     648             :   }
     649             : 
     650             :   // Accessors for working with the contained variant value.
     651             : 
     652             :   /** Mutable reference. */
     653             :   template<typename T>
     654       87880 :   T& as() {
     655             :     static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
     656             :                   "provided a type not uniquely found in this Variant's type list");
     657       87880 :     MOZ_RELEASE_ASSERT(is<T>());
     658       87789 :     return *static_cast<T*>(ptr());
     659             :   }
     660             : 
     661             :   template<size_t N>
     662      474720 :   typename detail::Nth<N, Ts...>::Type& as()
     663             :   {
     664             :     static_assert(N < sizeof...(Ts),
     665             :                   "provided an index outside of this Variant's type list");
     666      474720 :     MOZ_RELEASE_ASSERT(is<N>());
     667      474729 :     return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
     668             :   }
     669             : 
     670             :   /** Immutable const reference. */
     671             :   template<typename T>
     672        6463 :   const T& as() const {
     673             :     static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
     674             :                   "provided a type not found in this Variant's type list");
     675        6463 :     MOZ_RELEASE_ASSERT(is<T>());
     676        6463 :     return *static_cast<const T*>(ptr());
     677             :   }
     678             : 
     679             :   template<size_t N>
     680      705792 :   const typename detail::Nth<N, Ts...>::Type& as() const
     681             :   {
     682             :     static_assert(N < sizeof...(Ts),
     683             :                   "provided an index outside of this Variant's type list");
     684      705792 :     MOZ_RELEASE_ASSERT(is<N>());
     685      705792 :     return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
     686             :   }
     687             : 
     688             :   /**
     689             :    * Extract the contained variant value from this container into a temporary
     690             :    * value.  On completion, the value in the variant will be in a
     691             :    * safely-destructible state, as determined by the behavior of T's move
     692             :    * constructor when provided the variant's internal value.
     693             :    */
     694             :   template<typename T>
     695             :   T extract() {
     696             :     static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
     697             :                   "provided a type not uniquely found in this Variant's type list");
     698             :     MOZ_ASSERT(is<T>());
     699             :     return T(Move(as<T>()));
     700             :   }
     701             : 
     702             :   template<size_t N>
     703       70815 :   typename detail::Nth<N, Ts...>::Type extract()
     704             :   {
     705             :     static_assert(N < sizeof...(Ts),
     706             :                   "provided an index outside of this Variant's type list");
     707       70815 :     MOZ_RELEASE_ASSERT(is<N>());
     708       70815 :     return typename detail::Nth<N, Ts...>::Type(Move(as<N>()));
     709             :   }
     710             : 
     711             :   // Exhaustive matching of all variant types on the contained value.
     712             : 
     713             :   /** Match on an immutable const reference. */
     714             :   template<typename Matcher>
     715             :   auto
     716      572965 :   match(Matcher&& aMatcher) const
     717             :     -> decltype(Impl::match(aMatcher, *this))
     718             :   {
     719      572965 :     return Impl::match(aMatcher, *this);
     720             :   }
     721             : 
     722             :   /** Match on a mutable non-const reference. */
     723             :   template<typename Matcher>
     724             :   auto
     725       90951 :   match(Matcher&& aMatcher)
     726             :     -> decltype(Impl::match(aMatcher, *this))
     727             :   {
     728       90951 :     return Impl::match(aMatcher, *this);
     729             :   }
     730             : };
     731             : 
     732             : /*
     733             :  * AsVariant() is used to construct a Variant<T,...> value containing the
     734             :  * provided T value using type inference. It can be used to construct Variant
     735             :  * values in expressions or return them from functions without specifying the
     736             :  * entire Variant type.
     737             :  *
     738             :  * Because AsVariant() must copy or move the value into a temporary and this
     739             :  * cannot necessarily be elided by the compiler, it's mostly appropriate only
     740             :  * for use with primitive or very small types.
     741             :  *
     742             :  * AsVariant() returns a AsVariantTemporary value which is implicitly
     743             :  * convertible to any Variant that can hold a value of type T.
     744             :  */
     745             : template<typename T>
     746             : detail::AsVariantTemporary<T>
     747       57295 : AsVariant(T&& aValue)
     748             : {
     749       57295 :   return detail::AsVariantTemporary<T>(Forward<T>(aValue));
     750             : }
     751             : 
     752             : } // namespace mozilla
     753             : 
     754             : #endif /* mozilla_Variant_h */

Generated by: LCOV version 1.13