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/. */
7 /* A template class for tagged unions. */
12 #include "mozilla/Assertions.h"
13 #include "mozilla/HashFunctions.h"
14 #include "mozilla/OperatorNewExtensions.h"
15 #include "mozilla/TemplateLib.h"
16 #include <type_traits>
19 #ifndef mozilla_Variant_h
20 # define mozilla_Variant_h
31 struct IPDLParamTraits
;
34 template <typename
... Ts
>
39 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
40 template <size_t N
, typename
... Ts
>
43 template <typename T
, typename
... Ts
>
44 struct Nth
<0, T
, Ts
...> {
48 template <size_t N
, typename T
, typename
... Ts
>
49 struct Nth
<N
, T
, Ts
...> {
50 using Type
= typename Nth
<N
- 1, Ts
...>::Type
;
53 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
54 template <typename T
, typename
... Variants
>
55 struct SelectVariantTypeHelper
;
58 struct SelectVariantTypeHelper
<T
> {
59 static constexpr size_t count
= 0;
62 template <typename T
, typename
... Variants
>
63 struct SelectVariantTypeHelper
<T
, T
, Variants
...> {
65 static constexpr size_t count
=
66 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
69 template <typename T
, typename
... Variants
>
70 struct SelectVariantTypeHelper
<T
, const T
, Variants
...> {
72 static constexpr size_t count
=
73 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
76 template <typename T
, typename
... Variants
>
77 struct SelectVariantTypeHelper
<T
, const T
&, Variants
...> {
78 typedef const T
& Type
;
79 static constexpr size_t count
=
80 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
83 template <typename T
, typename
... Variants
>
84 struct SelectVariantTypeHelper
<T
, T
&&, Variants
...> {
86 static constexpr size_t count
=
87 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
90 template <typename T
, typename Head
, typename
... Variants
>
91 struct SelectVariantTypeHelper
<T
, Head
, Variants
...>
92 : public SelectVariantTypeHelper
<T
, Variants
...> {};
95 * SelectVariantType takes a type T and a list of variant types Variants and
96 * yields a type Type, selected from Variants, that can store a value of type T
97 * or a reference to type T. If no such type was found, Type is not defined.
98 * SelectVariantType also has a `count` member that contains the total number of
99 * selectable types (which will be used to check that a requested type is not
100 * ambiguously present twice.)
102 template <typename T
, typename
... Variants
>
103 struct SelectVariantType
104 : public SelectVariantTypeHelper
<
105 std::remove_const_t
<std::remove_reference_t
<T
>>, Variants
...> {};
107 // Compute a fast, compact type that can be used to hold integral values that
108 // distinctly map to every type in Ts.
109 template <typename
... Ts
>
112 static const size_t TypeCount
= sizeof...(Ts
);
115 using Type
= std::conditional_t
< TypeCount
< 3, bool,
116 std::conditional_t
<TypeCount
<(1 << 8), uint_fast8_t,
117 size_t // stop caring past a certain
122 // TagHelper gets the given sentinel tag value for the given type T. This has to
123 // be split out from VariantImplementation because you can't nest a partial
124 // template specialization within a template class.
126 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
,
130 // In the case where T != U, we continue recursion.
131 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
132 struct TagHelper
<Tag
, N
, T
, U
, Next
, false> {
133 static Tag
tag() { return Next::template tag
<U
>(); }
136 // In the case where T == U, return the tag number.
137 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
138 struct TagHelper
<Tag
, N
, T
, U
, Next
, true> {
139 static Tag
tag() { return Tag(N
); }
142 // The VariantImplementation template provides the guts of mozilla::Variant. We
143 // create a VariantImplementation for each T in Ts... which handles
144 // construction, destruction, etc for when the Variant's type is T. If the
145 // Variant's type isn't T, it punts the request on to the next
146 // VariantImplementation.
148 template <typename Tag
, size_t N
, typename
... Ts
>
149 struct VariantImplementation
;
151 // The singly typed Variant / recursion base case.
152 template <typename Tag
, size_t N
, typename T
>
153 struct VariantImplementation
<Tag
, N
, T
> {
154 template <typename U
>
156 static_assert(std::is_same_v
<T
, U
>, "mozilla::Variant: tag: bad type!");
160 template <typename Variant
>
161 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
162 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
165 template <typename Variant
>
166 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
167 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
170 template <typename Variant
>
171 static void destroy(Variant
& aV
) {
172 aV
.template as
<N
>().~T();
175 template <typename Variant
>
176 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
177 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
180 template <typename Matcher
, typename ConcreteVariant
>
181 static decltype(auto) match(Matcher
&& aMatcher
, ConcreteVariant
&& aV
) {
182 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
183 decltype(std::forward
<ConcreteVariant
>(aV
)
184 .template as
<N
>())>) {
185 return std::forward
<Matcher
>(aMatcher
)(
186 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
188 return std::forward
<Matcher
>(aMatcher
)(
189 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
193 template <typename ConcreteVariant
, typename Matcher
>
194 static decltype(auto) matchN(ConcreteVariant
&& aV
, Matcher
&& aMatcher
) {
195 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
196 decltype(std::forward
<ConcreteVariant
>(aV
)
197 .template as
<N
>())>) {
198 return std::forward
<Matcher
>(aMatcher
)(
199 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
201 return std::forward
<Matcher
>(aMatcher
)(
202 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
207 // VariantImplementation for some variant type T.
208 template <typename Tag
, size_t N
, typename T
, typename
... Ts
>
209 struct VariantImplementation
<Tag
, N
, T
, Ts
...> {
210 // The next recursive VariantImplementation.
211 using Next
= VariantImplementation
<Tag
, N
+ 1, Ts
...>;
213 template <typename U
>
215 return TagHelper
<Tag
, N
, T
, U
, Next
, std::is_same_v
<T
, U
>>::tag();
218 template <typename Variant
>
219 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
220 if (aRhs
.template is
<N
>()) {
221 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
223 Next::copyConstruct(aLhs
, aRhs
);
227 template <typename Variant
>
228 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
229 if (aRhs
.template is
<N
>()) {
230 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
232 Next::moveConstruct(aLhs
, std::move(aRhs
));
236 template <typename Variant
>
237 static void destroy(Variant
& aV
) {
238 if (aV
.template is
<N
>()) {
239 aV
.template as
<N
>().~T();
245 template <typename Variant
>
246 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
247 if (aLhs
.template is
<N
>()) {
248 MOZ_ASSERT(aRhs
.template is
<N
>());
249 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
251 return Next::equal(aLhs
, aRhs
);
255 template <typename Matcher
, typename ConcreteVariant
>
256 static decltype(auto) match(Matcher
&& aMatcher
, ConcreteVariant
&& aV
) {
257 if (aV
.template is
<N
>()) {
258 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
260 std::forward
<ConcreteVariant
>(aV
)
261 .template as
<N
>())>) {
262 return std::forward
<Matcher
>(aMatcher
)(
263 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
265 return std::forward
<Matcher
>(aMatcher
)(
266 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
269 // If you're seeing compilation errors here like "no matching
270 // function for call to 'match'" then that means that the
271 // Matcher doesn't exhaust all variant types. There must exist a
272 // Matcher::operator()(T&) for every variant type T.
274 // If you're seeing compilation errors here like "cannot initialize
275 // return object of type <...> with an rvalue of type <...>" then that
276 // means that the Matcher::operator()(T&) overloads are returning
277 // different types. They must all return the same type.
278 return Next::match(std::forward
<Matcher
>(aMatcher
),
279 std::forward
<ConcreteVariant
>(aV
));
283 template <typename ConcreteVariant
, typename Mi
, typename
... Ms
>
284 static decltype(auto) matchN(ConcreteVariant
&& aV
, Mi
&& aMi
, Ms
&&... aMs
) {
285 if (aV
.template is
<N
>()) {
286 if constexpr (std::is_invocable_v
<Mi
, Tag
,
288 std::forward
<ConcreteVariant
>(aV
)
289 .template as
<N
>())>) {
292 decltype(std::forward
<Mi
>(aMi
)(
294 std::forward
<ConcreteVariant
>(aV
).template as
<N
>())),
295 decltype(Next::matchN(std::forward
<ConcreteVariant
>(aV
),
296 std::forward
<Ms
>(aMs
)...))>,
297 "all matchers must have the same return type");
298 return std::forward
<Mi
>(aMi
)(
299 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
303 decltype(std::forward
<Mi
>(aMi
)(
304 std::forward
<ConcreteVariant
>(aV
).template as
<N
>())),
305 decltype(Next::matchN(std::forward
<ConcreteVariant
>(aV
),
306 std::forward
<Ms
>(aMs
)...))>,
307 "all matchers must have the same return type");
308 return std::forward
<Mi
>(aMi
)(
309 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
312 // If you're seeing compilation errors here like "no matching
313 // function for call to 'match'" then that means that the
314 // Matchers don't exhaust all variant types. There must exist a
315 // Matcher (with its operator()(T&)) for every variant type T, in the
317 return Next::matchN(std::forward
<ConcreteVariant
>(aV
),
318 std::forward
<Ms
>(aMs
)...);
324 * AsVariantTemporary stores a value of type T to allow construction of a
325 * Variant value via type inference. Because T is copied and there's no
326 * guarantee that the copy can be elided, AsVariantTemporary is best used with
327 * primitive or very small types.
329 template <typename T
>
330 struct AsVariantTemporary
{
331 explicit AsVariantTemporary(const T
& aValue
) : mValue(aValue
) {}
333 template <typename U
>
334 explicit AsVariantTemporary(U
&& aValue
) : mValue(std::forward
<U
>(aValue
)) {}
336 AsVariantTemporary(const AsVariantTemporary
& aOther
)
337 : mValue(aOther
.mValue
) {}
339 AsVariantTemporary(AsVariantTemporary
&& aOther
)
340 : mValue(std::move(aOther
.mValue
)) {}
342 AsVariantTemporary() = delete;
343 void operator=(const AsVariantTemporary
&) = delete;
344 void operator=(AsVariantTemporary
&&) = delete;
346 std::remove_const_t
<std::remove_reference_t
<T
>> mValue
;
349 } // namespace detail
351 // Used to unambiguously specify one of the Variant's type.
352 template <typename T
>
357 // Used to specify one of the Variant's type by index.
359 struct VariantIndex
{
360 static constexpr size_t index
= N
;
366 * A variant / tagged union / heterogenous disjoint union / sum-type template
367 * class. Similar in concept to (but not derived from) `boost::variant`.
369 * Sometimes, you may wish to use a C union with non-POD types. However, this is
370 * forbidden in C++ because it is not clear which type in the union should have
371 * its constructor and destructor run on creation and deletion
372 * respectively. This is the problem that `mozilla::Variant` solves.
376 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
377 * its variant types (ignoring const and references). It does *not* support
378 * construction from subclasses of variant types or types that coerce to one of
381 * Variant<char, uint32_t> v1('a');
382 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
383 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
384 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
386 * Because specifying the full type of a Variant value is often verbose,
387 * there are two easier ways to construct values:
389 * A. AsVariant() can be used to construct a Variant value using type inference
390 * in contexts such as expressions or when returning values from functions.
391 * Because AsVariant() must copy or move the value into a temporary and this
392 * cannot necessarily be elided by the compiler, it's mostly appropriate only
393 * for use with primitive or very small types.
395 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
397 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
399 * B. Brace-construction with VariantType or VariantIndex; this also allows
400 * in-place construction with any number of arguments.
402 * struct AB { AB(int, int){...} };
403 * static Variant<AB, bool> foo()
405 * return {VariantIndex<0>{}, 1, 2};
408 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
410 * All access to the contained value goes through type-safe accessors.
411 * Either the stored type, or the type index may be provided.
414 * Foo(Variant<A, B, C> v)
417 * A& ref = v.as<A>();
419 * } else (v.is<1>()) { // Instead of v.is<B>.
426 * In some situation, a Variant may be constructed from templated types, in
427 * which case it is possible that the same type could be given multiple times by
428 * an external developer. Or seemingly-different types could be aliases.
429 * In this case, repeated types can only be accessed through their index, to
430 * prevent ambiguous access by type.
433 * template <typename T>
434 * struct ResultOrError
437 * ResultOrError() : m(int(0)) {} // Error '0' by default
438 * ResultOrError(const T& r) : m(r) {}
439 * bool IsResult() const { return m.is<T>(); }
440 * bool IsError() const { return m.is<int>(); }
442 * // Now instantiante with the result being an int too:
443 * ResultOrError<int> myResult(123); // Fail!
444 * // In Variant<int, int>, which 'int' are we refering to, from inside
445 * // ResultOrError functions?
448 * template <typename T>
449 * struct ResultOrError
452 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
453 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
454 * bool IsResult() const { return m.is<0>(); } // 0 -> T
455 * bool IsError() const { return m.is<1>(); } // 1 -> int
457 * // Now instantiante with the result being an int too:
458 * ResultOrError<int> myResult(123); // It now works!
460 * Attempting to use the contained value as type `T1` when the `Variant`
461 * instance contains a value of type `T2` causes an assertion failure.
464 * Variant<A, B, C> v(a);
465 * v.as<B>(); // <--- Assertion failure!
467 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
468 * member of the set of `Ts...` is a compiler error.
471 * Variant<A, B, C> v(a);
472 * v.as<SomeRandomType>(); // <--- Compiler error!
474 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
475 * out of the containing `Variant` instance with the `extract<T>` method:
477 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
478 * auto ptr = v.extract<UniquePtr<A>>();
480 * Finally, you can exhaustively match on the contained variant and branch into
481 * different code paths depending on which type is contained. This is preferred
482 * to manually checking every variant type T with is<T>() because it provides
483 * compile-time checking that you handled every type, rather than runtime
484 * assertion failures.
487 * char* foo(Variant<A, B, C, D>& v) {
490 * } else if (v.is<B>()) {
493 * return doSomething(v.as<C>()); // Forgot about case D!
497 * // Instead, a single function object (that can deal with all possible
498 * // options) may be provided:
501 * // The return type of all matchers must be identical.
502 * char* operator()(A& a) { ... }
503 * char* operator()(B& b) { ... }
504 * char* operator()(C& c) { ... }
505 * char* operator()(D& d) { ... } // Compile-time error to forget D!
507 * char* foo(Variant<A, B, C, D>& v) {
508 * return v.match(FooMatcher());
511 * // In some situations, a single generic lambda may also be appropriate:
512 * char* foo(Variant<A, B, C, D>& v) {
513 * return v.match([](auto&) {...});
516 * // Alternatively, multiple function objects may be provided, each one
517 * // corresponding to an option, in the same order:
518 * char* foo(Variant<A, B, C, D>& v) {
519 * return v.match([](A&) { ... },
525 * // In rare cases, the index of the currently-active alternative is
526 * // needed, it may be obtained by adding a first parameter in the matcner
527 * // callback, which will receive the index in its most compact type (just
528 * // use `size_t` if the exact type is not important), e.g.:
529 * char* foo(Variant<A, B, C, D>& v) {
530 * return v.match([](auto aIndex, auto& aAlternative) {...});
532 * return v.match([](size_t aIndex, auto& aAlternative) {...});
537 * A tree is either an empty leaf, or a node with a value and two children:
541 * template<typename T>
549 * template<typename T>
550 * using Tree = Variant<Leaf, Node<T>>;
552 * A copy-on-write string is either a non-owning reference to some existing
553 * string, or an owning reference to our copy:
555 * class CopyOnWriteString
557 * Variant<const char*, UniquePtr<char[]>> string;
562 * Because Variant must be aligned suitable to hold any value stored within it,
563 * and because |alignas| requirements don't affect platform ABI with respect to
564 * how parameters are laid out in memory, Variant can't be used as the type of a
565 * function parameter. Pass Variant to functions by pointer or reference
568 template <typename
... Ts
>
569 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
{
570 friend struct IPC::ParamTraits
<mozilla::Variant
<Ts
...>>;
571 friend struct mozilla::ipc::IPDLParamTraits
<mozilla::Variant
<Ts
...>>;
573 using Tag
= typename
detail::VariantTag
<Ts
...>::Type
;
574 using Impl
= detail::VariantImplementation
<Tag
, 0, Ts
...>;
576 static constexpr size_t RawDataAlignment
= tl::Max
<alignof(Ts
)...>::value
;
577 static constexpr size_t RawDataSize
= tl::Max
<sizeof(Ts
)...>::value
;
579 // Raw storage for the contained variant value.
580 alignas(RawDataAlignment
) unsigned char rawData
[RawDataSize
];
582 // Each type is given a unique tag value that lets us keep track of the
583 // contained variant value's type.
586 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
587 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
588 // through |void*|. Placing the latter cast in these separate functions
589 // breaks the chain such that affected GCC versions no longer warn/error.
590 void* ptr() { return rawData
; }
592 const void* ptr() const { return rawData
; }
595 /** Perfect forwarding construction for some variant type T. */
596 template <typename RefT
,
597 // RefT captures both const& as well as && (as intended, to support
598 // perfect forwarding), so we have to remove those qualifiers here
599 // when ensuring that T is a variant of this type, and getting T's
601 typename T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>
602 explicit Variant(RefT
&& aT
) : tag(Impl::template tag
<T
>()) {
604 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
605 "Variant can only be selected by type if that type is unique");
606 ::new (KnownNotNull
, ptr()) T(std::forward
<RefT
>(aT
));
610 * Perfect forwarding construction for some variant type T, by
611 * explicitly giving the type.
612 * This is necessary to construct from any number of arguments,
613 * or to convert from a type that is not in the Variant's type list.
615 template <typename T
, typename
... Args
>
616 MOZ_IMPLICIT
Variant(const VariantType
<T
>&, Args
&&... aTs
)
617 : tag(Impl::template tag
<T
>()) {
618 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
622 * Perfect forwarding construction for some variant type T, by
623 * explicitly giving the type index.
624 * This is necessary to construct from any number of arguments,
625 * or to convert from a type that is not in the Variant's type list,
626 * or to construct a type that is present more than once in the Variant.
628 template <size_t N
, typename
... Args
>
629 MOZ_IMPLICIT
Variant(const VariantIndex
<N
>&, Args
&&... aTs
) : tag(N
) {
630 using T
= typename
detail::Nth
<N
, Ts
...>::Type
;
631 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
635 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
636 * stored in one of the types allowable in this Variant. This is used in the
637 * implementation of AsVariant().
639 template <typename RefT
>
640 MOZ_IMPLICIT
Variant(detail::AsVariantTemporary
<RefT
>&& aValue
)
641 : tag(Impl::template tag
<
642 typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>()) {
643 using T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
;
645 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
646 "Variant can only be selected by type if that type is unique");
647 ::new (KnownNotNull
, ptr()) T(std::move(aValue
.mValue
));
650 /** Copy construction. */
651 Variant(const Variant
& aRhs
) : tag(aRhs
.tag
) {
652 Impl::copyConstruct(ptr(), aRhs
);
655 /** Move construction. */
656 Variant(Variant
&& aRhs
) : tag(aRhs
.tag
) {
657 Impl::moveConstruct(ptr(), std::move(aRhs
));
660 /** Copy assignment. */
661 Variant
& operator=(const Variant
& aRhs
) {
662 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
664 ::new (KnownNotNull
, this) Variant(aRhs
);
668 /** Move assignment. */
669 Variant
& operator=(Variant
&& aRhs
) {
670 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
672 ::new (KnownNotNull
, this) Variant(std::move(aRhs
));
676 /** Move assignment from AsVariant(). */
677 template <typename T
>
678 Variant
& operator=(detail::AsVariantTemporary
<T
>&& aValue
) {
680 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
681 "Variant can only be selected by type if that type is unique");
683 ::new (KnownNotNull
, this) Variant(std::move(aValue
));
687 ~Variant() { Impl::destroy(*this); }
689 template <typename T
, typename
... Args
>
690 T
& emplace(Args
&&... aTs
) {
691 Impl::destroy(*this);
692 tag
= Impl::template tag
<T
>();
693 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
697 template <size_t N
, typename
... Args
>
698 typename
detail::Nth
<N
, Ts
...>::Type
& emplace(Args
&&... aTs
) {
699 using T
= typename
detail::Nth
<N
, Ts
...>::Type
;
700 Impl::destroy(*this);
702 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
706 /** Check which variant type is currently contained. */
707 template <typename T
>
710 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
711 "provided a type not uniquely found in this Variant's type list");
712 return Impl::template tag
<T
>() == tag
;
717 static_assert(N
< sizeof...(Ts
),
718 "provided an index outside of this Variant's type list");
719 return N
== size_t(tag
);
723 * Operator == overload that defers to the variant type's operator==
724 * implementation if the rhs is tagged as the same type as this one.
726 bool operator==(const Variant
& aRhs
) const {
727 return tag
== aRhs
.tag
&& Impl::equal(*this, aRhs
);
731 * Operator != overload that defers to the negation of the variant type's
732 * operator== implementation if the rhs is tagged as the same type as this
735 bool operator!=(const Variant
& aRhs
) const { return !(*this == aRhs
); }
737 // Accessors for working with the contained variant value.
739 /** Mutable lvalue-reference. */
740 template <typename T
>
743 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
744 "provided a type not uniquely found in this Variant's type list");
745 MOZ_RELEASE_ASSERT(is
<T
>());
746 return *static_cast<T
*>(ptr());
750 typename
detail::Nth
<N
, Ts
...>::Type
& as() & {
751 static_assert(N
< sizeof...(Ts
),
752 "provided an index outside of this Variant's type list");
753 MOZ_RELEASE_ASSERT(is
<N
>());
754 return *static_cast<typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
757 /** Immutable const lvalue-reference. */
758 template <typename T
>
759 const T
& as() const& {
760 static_assert(detail::SelectVariantType
<T
, Ts
...>::count
== 1,
761 "provided a type not found in this Variant's type list");
762 MOZ_RELEASE_ASSERT(is
<T
>());
763 return *static_cast<const T
*>(ptr());
767 const typename
detail::Nth
<N
, Ts
...>::Type
& as() const& {
768 static_assert(N
< sizeof...(Ts
),
769 "provided an index outside of this Variant's type list");
770 MOZ_RELEASE_ASSERT(is
<N
>());
771 return *static_cast<const typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
774 /** Mutable rvalue-reference. */
775 template <typename T
>
778 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
779 "provided a type not uniquely found in this Variant's type list");
780 MOZ_RELEASE_ASSERT(is
<T
>());
781 return std::move(*static_cast<T
*>(ptr()));
785 typename
detail::Nth
<N
, Ts
...>::Type
&& as() && {
786 static_assert(N
< sizeof...(Ts
),
787 "provided an index outside of this Variant's type list");
788 MOZ_RELEASE_ASSERT(is
<N
>());
790 *static_cast<typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr()));
793 /** Immutable const rvalue-reference. */
794 template <typename T
>
795 const T
&& as() const&& {
796 static_assert(detail::SelectVariantType
<T
, Ts
...>::count
== 1,
797 "provided a type not found in this Variant's type list");
798 MOZ_RELEASE_ASSERT(is
<T
>());
799 return std::move(*static_cast<const T
*>(ptr()));
803 const typename
detail::Nth
<N
, Ts
...>::Type
&& as() const&& {
804 static_assert(N
< sizeof...(Ts
),
805 "provided an index outside of this Variant's type list");
806 MOZ_RELEASE_ASSERT(is
<N
>());
808 *static_cast<const typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr()));
812 * Extract the contained variant value from this container into a temporary
813 * value. On completion, the value in the variant will be in a
814 * safely-destructible state, as determined by the behavior of T's move
815 * constructor when provided the variant's internal value.
817 template <typename T
>
820 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
821 "provided a type not uniquely found in this Variant's type list");
823 return T(std::move(as
<T
>()));
827 typename
detail::Nth
<N
, Ts
...>::Type
extract() {
828 static_assert(N
< sizeof...(Ts
),
829 "provided an index outside of this Variant's type list");
830 MOZ_RELEASE_ASSERT(is
<N
>());
831 return typename
detail::Nth
<N
, Ts
...>::Type(std::move(as
<N
>()));
834 // Exhaustive matching of all variant types on the contained value.
836 /** Match on an immutable const lvalue-reference. */
837 template <typename Matcher
>
838 decltype(auto) match(Matcher
&& aMatcher
) const& {
839 return Impl::match(std::forward
<Matcher
>(aMatcher
), *this);
842 template <typename M0
, typename M1
, typename
... Ms
>
843 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) const& {
844 return matchN(*this, std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
845 std::forward
<Ms
>(aMs
)...);
848 /** Match on a mutable non-const lvalue-reference. */
849 template <typename Matcher
>
850 decltype(auto) match(Matcher
&& aMatcher
) & {
851 return Impl::match(std::forward
<Matcher
>(aMatcher
), *this);
854 template <typename M0
, typename M1
, typename
... Ms
>
855 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) & {
856 return matchN(*this, std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
857 std::forward
<Ms
>(aMs
)...);
860 /** Match on an immutable const rvalue-reference. */
861 template <typename Matcher
>
862 decltype(auto) match(Matcher
&& aMatcher
) const&& {
863 return Impl::match(std::forward
<Matcher
>(aMatcher
), std::move(*this));
866 template <typename M0
, typename M1
, typename
... Ms
>
867 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) const&& {
868 return matchN(std::move(*this), std::forward
<M0
>(aM0
),
869 std::forward
<M1
>(aM1
), std::forward
<Ms
>(aMs
)...);
872 /** Match on a mutable non-const rvalue-reference. */
873 template <typename Matcher
>
874 decltype(auto) match(Matcher
&& aMatcher
) && {
875 return Impl::match(std::forward
<Matcher
>(aMatcher
), std::move(*this));
878 template <typename M0
, typename M1
, typename
... Ms
>
879 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) && {
880 return matchN(std::move(*this), std::forward
<M0
>(aM0
),
881 std::forward
<M1
>(aM1
), std::forward
<Ms
>(aMs
)...);
885 * Incorporate the current variant's tag into hashValue.
886 * Note that this does not hash the actual contents; you must take
887 * care of that yourself, perhaps by using a match.
889 mozilla::HashNumber
addTagToHash(mozilla::HashNumber hashValue
) const {
890 return mozilla::AddToHash(hashValue
, tag
);
894 template <typename ConcreteVariant
, typename M0
, typename M1
, typename
... Ms
>
895 static decltype(auto) matchN(ConcreteVariant
&& aVariant
, M0
&& aM0
, M1
&& aM1
,
898 2 + sizeof...(Ms
) == sizeof...(Ts
),
899 "Variant<T...>::match() takes either one callable argument that "
900 "accepts every type T; or one for each type T, in order");
901 return Impl::matchN(std::forward
<ConcreteVariant
>(aVariant
),
902 std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
903 std::forward
<Ms
>(aMs
)...);
908 * AsVariant() is used to construct a Variant<T,...> value containing the
909 * provided T value using type inference. It can be used to construct Variant
910 * values in expressions or return them from functions without specifying the
911 * entire Variant type.
913 * Because AsVariant() must copy or move the value into a temporary and this
914 * cannot necessarily be elided by the compiler, it's mostly appropriate only
915 * for use with primitive or very small types.
917 * AsVariant() returns a AsVariantTemporary value which is implicitly
918 * convertible to any Variant that can hold a value of type T.
920 template <typename T
>
921 detail::AsVariantTemporary
<T
> AsVariant(T
&& aValue
) {
922 return detail::AsVariantTemporary
<T
>(std::forward
<T
>(aValue
));
925 } // namespace mozilla
927 #endif /* mozilla_Variant_h */