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
<
116 (TypeCount
<= 2), bool,
117 std::conditional_t
<(TypeCount
<= size_t(UINT_FAST8_MAX
)), uint_fast8_t,
118 size_t // stop caring past a certain
123 // TagHelper gets the given sentinel tag value for the given type T. This has to
124 // be split out from VariantImplementation because you can't nest a partial
125 // template specialization within a template class.
127 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
,
131 // In the case where T != U, we continue recursion.
132 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
133 struct TagHelper
<Tag
, N
, T
, U
, Next
, false> {
134 static Tag
tag() { return Next::template tag
<U
>(); }
137 // In the case where T == U, return the tag number.
138 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
139 struct TagHelper
<Tag
, N
, T
, U
, Next
, true> {
140 static Tag
tag() { return Tag(N
); }
143 // The VariantImplementation template provides the guts of mozilla::Variant. We
144 // create a VariantImplementation for each T in Ts... which handles
145 // construction, destruction, etc for when the Variant's type is T. If the
146 // Variant's type isn't T, it punts the request on to the next
147 // VariantImplementation.
149 template <typename Tag
, size_t N
, typename
... Ts
>
150 struct VariantImplementation
;
152 // The singly typed Variant / recursion base case.
153 template <typename Tag
, size_t N
, typename T
>
154 struct VariantImplementation
<Tag
, N
, T
> {
155 template <typename U
>
157 static_assert(std::is_same_v
<T
, U
>, "mozilla::Variant: tag: bad type!");
161 template <typename Variant
>
162 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
163 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
166 template <typename Variant
>
167 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
168 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
171 template <typename Variant
>
172 static void destroy(Variant
& aV
) {
173 aV
.template as
<N
>().~T();
176 template <typename Variant
>
177 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
178 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
181 template <typename Matcher
, typename ConcreteVariant
>
182 static decltype(auto) match(Matcher
&& aMatcher
, ConcreteVariant
&& aV
) {
183 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
184 decltype(std::forward
<ConcreteVariant
>(aV
)
185 .template as
<N
>())>) {
186 return std::forward
<Matcher
>(aMatcher
)(
187 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
189 return std::forward
<Matcher
>(aMatcher
)(
190 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
194 template <typename ConcreteVariant
, typename Matcher
>
195 static decltype(auto) matchN(ConcreteVariant
&& aV
, Matcher
&& aMatcher
) {
196 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
197 decltype(std::forward
<ConcreteVariant
>(aV
)
198 .template as
<N
>())>) {
199 return std::forward
<Matcher
>(aMatcher
)(
200 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
202 return std::forward
<Matcher
>(aMatcher
)(
203 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
208 // VariantImplementation for some variant type T.
209 template <typename Tag
, size_t N
, typename T
, typename
... Ts
>
210 struct VariantImplementation
<Tag
, N
, T
, Ts
...> {
211 // The next recursive VariantImplementation.
212 using Next
= VariantImplementation
<Tag
, N
+ 1, Ts
...>;
214 template <typename U
>
216 return TagHelper
<Tag
, N
, T
, U
, Next
, std::is_same_v
<T
, U
>>::tag();
219 template <typename Variant
>
220 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
221 if (aRhs
.template is
<N
>()) {
222 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
224 Next::copyConstruct(aLhs
, aRhs
);
228 template <typename Variant
>
229 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
230 if (aRhs
.template is
<N
>()) {
231 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
233 Next::moveConstruct(aLhs
, std::move(aRhs
));
237 template <typename Variant
>
238 static void destroy(Variant
& aV
) {
239 if (aV
.template is
<N
>()) {
240 aV
.template as
<N
>().~T();
246 template <typename Variant
>
247 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
248 if (aLhs
.template is
<N
>()) {
249 MOZ_ASSERT(aRhs
.template is
<N
>());
250 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
252 return Next::equal(aLhs
, aRhs
);
256 template <typename Matcher
, typename ConcreteVariant
>
257 static decltype(auto) match(Matcher
&& aMatcher
, ConcreteVariant
&& aV
) {
258 if (aV
.template is
<N
>()) {
259 if constexpr (std::is_invocable_v
<Matcher
, Tag
,
260 decltype(std::forward
<ConcreteVariant
>(
262 .template as
<N
>())>) {
263 return std::forward
<Matcher
>(aMatcher
)(
264 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
266 return std::forward
<Matcher
>(aMatcher
)(
267 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
270 // If you're seeing compilation errors here like "no matching
271 // function for call to 'match'" then that means that the
272 // Matcher doesn't exhaust all variant types. There must exist a
273 // Matcher::operator()(T&) for every variant type T.
275 // If you're seeing compilation errors here like "cannot initialize
276 // return object of type <...> with an rvalue of type <...>" then that
277 // means that the Matcher::operator()(T&) overloads are returning
278 // different types. They must all return the same type.
279 return Next::match(std::forward
<Matcher
>(aMatcher
),
280 std::forward
<ConcreteVariant
>(aV
));
284 template <typename ConcreteVariant
, typename Mi
, typename
... Ms
>
285 static decltype(auto) matchN(ConcreteVariant
&& aV
, Mi
&& aMi
, Ms
&&... aMs
) {
286 if (aV
.template is
<N
>()) {
287 if constexpr (std::is_invocable_v
<Mi
, Tag
,
288 decltype(std::forward
<ConcreteVariant
>(
290 .template as
<N
>())>) {
293 decltype(std::forward
<Mi
>(aMi
)(
295 std::forward
<ConcreteVariant
>(aV
).template as
<N
>())),
296 decltype(Next::matchN(std::forward
<ConcreteVariant
>(aV
),
297 std::forward
<Ms
>(aMs
)...))>,
298 "all matchers must have the same return type");
299 return std::forward
<Mi
>(aMi
)(
300 Tag(N
), std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
304 decltype(std::forward
<Mi
>(aMi
)(
305 std::forward
<ConcreteVariant
>(aV
).template as
<N
>())),
306 decltype(Next::matchN(std::forward
<ConcreteVariant
>(aV
),
307 std::forward
<Ms
>(aMs
)...))>,
308 "all matchers must have the same return type");
309 return std::forward
<Mi
>(aMi
)(
310 std::forward
<ConcreteVariant
>(aV
).template as
<N
>());
313 // If you're seeing compilation errors here like "no matching
314 // function for call to 'match'" then that means that the
315 // Matchers don't exhaust all variant types. There must exist a
316 // Matcher (with its operator()(T&)) for every variant type T, in the
318 return Next::matchN(std::forward
<ConcreteVariant
>(aV
),
319 std::forward
<Ms
>(aMs
)...);
325 * AsVariantTemporary stores a value of type T to allow construction of a
326 * Variant value via type inference. Because T is copied and there's no
327 * guarantee that the copy can be elided, AsVariantTemporary is best used with
328 * primitive or very small types.
330 template <typename T
>
331 struct AsVariantTemporary
{
332 explicit AsVariantTemporary(const T
& aValue
) : mValue(aValue
) {}
334 template <typename U
>
335 explicit AsVariantTemporary(U
&& aValue
) : mValue(std::forward
<U
>(aValue
)) {}
337 AsVariantTemporary(const AsVariantTemporary
& aOther
)
338 : mValue(aOther
.mValue
) {}
340 AsVariantTemporary(AsVariantTemporary
&& aOther
)
341 : mValue(std::move(aOther
.mValue
)) {}
343 AsVariantTemporary() = delete;
344 void operator=(const AsVariantTemporary
&) = delete;
345 void operator=(AsVariantTemporary
&&) = delete;
347 std::remove_const_t
<std::remove_reference_t
<T
>> mValue
;
350 } // namespace detail
352 // Used to unambiguously specify one of the Variant's type.
353 template <typename T
>
358 // Used to specify one of the Variant's type by index.
360 struct VariantIndex
{
361 static constexpr size_t index
= N
;
367 * A variant / tagged union / heterogenous disjoint union / sum-type template
368 * class. Similar in concept to (but not derived from) `boost::variant`.
370 * Sometimes, you may wish to use a C union with non-POD types. However, this is
371 * forbidden in C++ because it is not clear which type in the union should have
372 * its constructor and destructor run on creation and deletion
373 * respectively. This is the problem that `mozilla::Variant` solves.
377 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
378 * its variant types (ignoring const and references). It does *not* support
379 * construction from subclasses of variant types or types that coerce to one of
382 * Variant<char, uint32_t> v1('a');
383 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
384 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
385 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
387 * Because specifying the full type of a Variant value is often verbose,
388 * there are two easier ways to construct values:
390 * A. AsVariant() can be used to construct a Variant value using type inference
391 * in contexts such as expressions or when returning values from functions.
392 * Because AsVariant() must copy or move the value into a temporary and this
393 * cannot necessarily be elided by the compiler, it's mostly appropriate only
394 * for use with primitive or very small types.
396 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
398 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
400 * B. Brace-construction with VariantType or VariantIndex; this also allows
401 * in-place construction with any number of arguments.
403 * struct AB { AB(int, int){...} };
404 * static Variant<AB, bool> foo()
406 * return {VariantIndex<0>{}, 1, 2};
409 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
411 * All access to the contained value goes through type-safe accessors.
412 * Either the stored type, or the type index may be provided.
415 * Foo(Variant<A, B, C> v)
418 * A& ref = v.as<A>();
420 * } else (v.is<1>()) { // Instead of v.is<B>.
427 * In some situation, a Variant may be constructed from templated types, in
428 * which case it is possible that the same type could be given multiple times by
429 * an external developer. Or seemingly-different types could be aliases.
430 * In this case, repeated types can only be accessed through their index, to
431 * prevent ambiguous access by type.
434 * template <typename T>
435 * struct ResultOrError
438 * ResultOrError() : m(int(0)) {} // Error '0' by default
439 * ResultOrError(const T& r) : m(r) {}
440 * bool IsResult() const { return m.is<T>(); }
441 * bool IsError() const { return m.is<int>(); }
443 * // Now instantiante with the result being an int too:
444 * ResultOrError<int> myResult(123); // Fail!
445 * // In Variant<int, int>, which 'int' are we refering to, from inside
446 * // ResultOrError functions?
449 * template <typename T>
450 * struct ResultOrError
453 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
454 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
455 * bool IsResult() const { return m.is<0>(); } // 0 -> T
456 * bool IsError() const { return m.is<1>(); } // 1 -> int
458 * // Now instantiante with the result being an int too:
459 * ResultOrError<int> myResult(123); // It now works!
461 * Attempting to use the contained value as type `T1` when the `Variant`
462 * instance contains a value of type `T2` causes an assertion failure.
465 * Variant<A, B, C> v(a);
466 * v.as<B>(); // <--- Assertion failure!
468 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
469 * member of the set of `Ts...` is a compiler error.
472 * Variant<A, B, C> v(a);
473 * v.as<SomeRandomType>(); // <--- Compiler error!
475 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
476 * out of the containing `Variant` instance with the `extract<T>` method:
478 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
479 * auto ptr = v.extract<UniquePtr<A>>();
481 * Finally, you can exhaustively match on the contained variant and branch into
482 * different code paths depending on which type is contained. This is preferred
483 * to manually checking every variant type T with is<T>() because it provides
484 * compile-time checking that you handled every type, rather than runtime
485 * assertion failures.
488 * char* foo(Variant<A, B, C, D>& v) {
491 * } else if (v.is<B>()) {
494 * return doSomething(v.as<C>()); // Forgot about case D!
498 * // Instead, a single function object (that can deal with all possible
499 * // options) may be provided:
502 * // The return type of all matchers must be identical.
503 * char* operator()(A& a) { ... }
504 * char* operator()(B& b) { ... }
505 * char* operator()(C& c) { ... }
506 * char* operator()(D& d) { ... } // Compile-time error to forget D!
508 * char* foo(Variant<A, B, C, D>& v) {
509 * return v.match(FooMatcher());
512 * // In some situations, a single generic lambda may also be appropriate:
513 * char* foo(Variant<A, B, C, D>& v) {
514 * return v.match([](auto&) {...});
517 * // Alternatively, multiple function objects may be provided, each one
518 * // corresponding to an option, in the same order:
519 * char* foo(Variant<A, B, C, D>& v) {
520 * return v.match([](A&) { ... },
526 * // In rare cases, the index of the currently-active alternative is
527 * // needed, it may be obtained by adding a first parameter in the matcner
528 * // callback, which will receive the index in its most compact type (just
529 * // use `size_t` if the exact type is not important), e.g.:
530 * char* foo(Variant<A, B, C, D>& v) {
531 * return v.match([](auto aIndex, auto& aAlternative) {...});
533 * return v.match([](size_t aIndex, auto& aAlternative) {...});
538 * A tree is either an empty leaf, or a node with a value and two children:
542 * template<typename T>
550 * template<typename T>
551 * using Tree = Variant<Leaf, Node<T>>;
553 * A copy-on-write string is either a non-owning reference to some existing
554 * string, or an owning reference to our copy:
556 * class CopyOnWriteString
558 * Variant<const char*, UniquePtr<char[]>> string;
563 * Because Variant must be aligned suitable to hold any value stored within it,
564 * and because |alignas| requirements don't affect platform ABI with respect to
565 * how parameters are laid out in memory, Variant can't be used as the type of a
566 * function parameter. Pass Variant to functions by pointer or reference
569 template <typename
... Ts
>
570 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
{
571 friend struct IPC::ParamTraits
<mozilla::Variant
<Ts
...>>;
572 friend struct mozilla::ipc::IPDLParamTraits
<mozilla::Variant
<Ts
...>>;
574 using Tag
= typename
detail::VariantTag
<Ts
...>::Type
;
575 using Impl
= detail::VariantImplementation
<Tag
, 0, Ts
...>;
577 static constexpr size_t RawDataAlignment
= tl::Max
<alignof(Ts
)...>::value
;
578 static constexpr size_t RawDataSize
= tl::Max
<sizeof(Ts
)...>::value
;
580 // Raw storage for the contained variant value.
581 alignas(RawDataAlignment
) unsigned char rawData
[RawDataSize
];
583 // Each type is given a unique tag value that lets us keep track of the
584 // contained variant value's type.
587 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
588 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
589 // through |void*|. Placing the latter cast in these separate functions
590 // breaks the chain such that affected GCC versions no longer warn/error.
591 void* ptr() { return rawData
; }
593 const void* ptr() const { return rawData
; }
596 /** Perfect forwarding construction for some variant type T. */
597 template <typename RefT
,
598 // RefT captures both const& as well as && (as intended, to support
599 // perfect forwarding), so we have to remove those qualifiers here
600 // when ensuring that T is a variant of this type, and getting T's
602 typename T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>
603 explicit Variant(RefT
&& aT
) : tag(Impl::template tag
<T
>()) {
605 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
606 "Variant can only be selected by type if that type is unique");
607 ::new (KnownNotNull
, ptr()) T(std::forward
<RefT
>(aT
));
611 * Perfect forwarding construction for some variant type T, by
612 * explicitly giving the type.
613 * This is necessary to construct from any number of arguments,
614 * or to convert from a type that is not in the Variant's type list.
616 template <typename T
, typename
... Args
>
617 MOZ_IMPLICIT
Variant(const VariantType
<T
>&, Args
&&... aTs
)
618 : tag(Impl::template tag
<T
>()) {
619 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
623 * Perfect forwarding construction for some variant type T, by
624 * explicitly giving the type index.
625 * This is necessary to construct from any number of arguments,
626 * or to convert from a type that is not in the Variant's type list,
627 * or to construct a type that is present more than once in the Variant.
629 template <size_t N
, typename
... Args
>
630 MOZ_IMPLICIT
Variant(const VariantIndex
<N
>&, Args
&&... aTs
) : tag(N
) {
631 using T
= typename
detail::Nth
<N
, Ts
...>::Type
;
632 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
636 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
637 * stored in one of the types allowable in this Variant. This is used in the
638 * implementation of AsVariant().
640 template <typename RefT
>
641 MOZ_IMPLICIT
Variant(detail::AsVariantTemporary
<RefT
>&& aValue
)
642 : tag(Impl::template tag
<
643 typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>()) {
644 using T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
;
646 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
647 "Variant can only be selected by type if that type is unique");
648 ::new (KnownNotNull
, ptr()) T(std::move(aValue
.mValue
));
651 /** Copy construction. */
652 Variant(const Variant
& aRhs
) : tag(aRhs
.tag
) {
653 Impl::copyConstruct(ptr(), aRhs
);
656 /** Move construction. */
657 Variant(Variant
&& aRhs
) : tag(aRhs
.tag
) {
658 Impl::moveConstruct(ptr(), std::move(aRhs
));
661 /** Copy assignment. */
662 Variant
& operator=(const Variant
& aRhs
) {
663 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
665 ::new (KnownNotNull
, this) Variant(aRhs
);
669 /** Move assignment. */
670 Variant
& operator=(Variant
&& aRhs
) {
671 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
673 ::new (KnownNotNull
, this) Variant(std::move(aRhs
));
677 /** Move assignment from AsVariant(). */
678 template <typename T
>
679 Variant
& operator=(detail::AsVariantTemporary
<T
>&& aValue
) {
681 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
682 "Variant can only be selected by type if that type is unique");
684 ::new (KnownNotNull
, this) Variant(std::move(aValue
));
688 ~Variant() { Impl::destroy(*this); }
690 template <typename T
, typename
... Args
>
691 T
& emplace(Args
&&... aTs
) {
692 Impl::destroy(*this);
693 tag
= Impl::template tag
<T
>();
694 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
698 template <size_t N
, typename
... Args
>
699 typename
detail::Nth
<N
, Ts
...>::Type
& emplace(Args
&&... aTs
) {
700 using T
= typename
detail::Nth
<N
, Ts
...>::Type
;
701 Impl::destroy(*this);
703 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
707 /** Check which variant type is currently contained. */
708 template <typename T
>
711 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
712 "provided a type not uniquely found in this Variant's type list");
713 return Impl::template tag
<T
>() == tag
;
718 static_assert(N
< sizeof...(Ts
),
719 "provided an index outside of this Variant's type list");
720 return N
== size_t(tag
);
724 * Operator == overload that defers to the variant type's operator==
725 * implementation if the rhs is tagged as the same type as this one.
727 bool operator==(const Variant
& aRhs
) const {
728 return tag
== aRhs
.tag
&& Impl::equal(*this, aRhs
);
732 * Operator != overload that defers to the negation of the variant type's
733 * operator== implementation if the rhs is tagged as the same type as this
736 bool operator!=(const Variant
& aRhs
) const { return !(*this == aRhs
); }
738 // Accessors for working with the contained variant value.
740 /** Mutable lvalue-reference. */
741 template <typename T
>
744 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
745 "provided a type not uniquely found in this Variant's type list");
746 MOZ_RELEASE_ASSERT(is
<T
>());
747 return *static_cast<T
*>(ptr());
751 typename
detail::Nth
<N
, Ts
...>::Type
& as() & {
752 static_assert(N
< sizeof...(Ts
),
753 "provided an index outside of this Variant's type list");
754 MOZ_RELEASE_ASSERT(is
<N
>());
755 return *static_cast<typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
758 /** Immutable const lvalue-reference. */
759 template <typename T
>
760 const T
& as() const& {
761 static_assert(detail::SelectVariantType
<T
, Ts
...>::count
== 1,
762 "provided a type not found in this Variant's type list");
763 MOZ_RELEASE_ASSERT(is
<T
>());
764 return *static_cast<const T
*>(ptr());
768 const typename
detail::Nth
<N
, Ts
...>::Type
& as() const& {
769 static_assert(N
< sizeof...(Ts
),
770 "provided an index outside of this Variant's type list");
771 MOZ_RELEASE_ASSERT(is
<N
>());
772 return *static_cast<const typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
775 /** Mutable rvalue-reference. */
776 template <typename T
>
779 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
780 "provided a type not uniquely found in this Variant's type list");
781 MOZ_RELEASE_ASSERT(is
<T
>());
782 return std::move(*static_cast<T
*>(ptr()));
786 typename
detail::Nth
<N
, Ts
...>::Type
&& as() && {
787 static_assert(N
< sizeof...(Ts
),
788 "provided an index outside of this Variant's type list");
789 MOZ_RELEASE_ASSERT(is
<N
>());
791 *static_cast<typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr()));
794 /** Immutable const rvalue-reference. */
795 template <typename T
>
796 const T
&& as() const&& {
797 static_assert(detail::SelectVariantType
<T
, Ts
...>::count
== 1,
798 "provided a type not found in this Variant's type list");
799 MOZ_RELEASE_ASSERT(is
<T
>());
800 return std::move(*static_cast<const T
*>(ptr()));
804 const typename
detail::Nth
<N
, Ts
...>::Type
&& as() const&& {
805 static_assert(N
< sizeof...(Ts
),
806 "provided an index outside of this Variant's type list");
807 MOZ_RELEASE_ASSERT(is
<N
>());
809 *static_cast<const typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr()));
813 * Extract the contained variant value from this container into a temporary
814 * value. On completion, the value in the variant will be in a
815 * safely-destructible state, as determined by the behavior of T's move
816 * constructor when provided the variant's internal value.
818 template <typename T
>
821 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
822 "provided a type not uniquely found in this Variant's type list");
824 return T(std::move(as
<T
>()));
828 typename
detail::Nth
<N
, Ts
...>::Type
extract() {
829 static_assert(N
< sizeof...(Ts
),
830 "provided an index outside of this Variant's type list");
831 MOZ_RELEASE_ASSERT(is
<N
>());
832 return typename
detail::Nth
<N
, Ts
...>::Type(std::move(as
<N
>()));
835 // Exhaustive matching of all variant types on the contained value.
837 /** Match on an immutable const lvalue-reference. */
838 template <typename Matcher
>
839 decltype(auto) match(Matcher
&& aMatcher
) const& {
840 return Impl::match(std::forward
<Matcher
>(aMatcher
), *this);
843 template <typename M0
, typename M1
, typename
... Ms
>
844 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) const& {
845 return matchN(*this, std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
846 std::forward
<Ms
>(aMs
)...);
849 /** Match on a mutable non-const lvalue-reference. */
850 template <typename Matcher
>
851 decltype(auto) match(Matcher
&& aMatcher
) & {
852 return Impl::match(std::forward
<Matcher
>(aMatcher
), *this);
855 template <typename M0
, typename M1
, typename
... Ms
>
856 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) & {
857 return matchN(*this, std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
858 std::forward
<Ms
>(aMs
)...);
861 /** Match on an immutable const rvalue-reference. */
862 template <typename Matcher
>
863 decltype(auto) match(Matcher
&& aMatcher
) const&& {
864 return Impl::match(std::forward
<Matcher
>(aMatcher
), std::move(*this));
867 template <typename M0
, typename M1
, typename
... Ms
>
868 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) const&& {
869 return matchN(std::move(*this), std::forward
<M0
>(aM0
),
870 std::forward
<M1
>(aM1
), std::forward
<Ms
>(aMs
)...);
873 /** Match on a mutable non-const rvalue-reference. */
874 template <typename Matcher
>
875 decltype(auto) match(Matcher
&& aMatcher
) && {
876 return Impl::match(std::forward
<Matcher
>(aMatcher
), std::move(*this));
879 template <typename M0
, typename M1
, typename
... Ms
>
880 decltype(auto) match(M0
&& aM0
, M1
&& aM1
, Ms
&&... aMs
) && {
881 return matchN(std::move(*this), std::forward
<M0
>(aM0
),
882 std::forward
<M1
>(aM1
), std::forward
<Ms
>(aMs
)...);
886 * Incorporate the current variant's tag into hashValue.
887 * Note that this does not hash the actual contents; you must take
888 * care of that yourself, perhaps by using a match.
890 mozilla::HashNumber
addTagToHash(mozilla::HashNumber hashValue
) const {
891 return mozilla::AddToHash(hashValue
, tag
);
895 template <typename ConcreteVariant
, typename M0
, typename M1
, typename
... Ms
>
896 static decltype(auto) matchN(ConcreteVariant
&& aVariant
, M0
&& aM0
, M1
&& aM1
,
899 2 + sizeof...(Ms
) == sizeof...(Ts
),
900 "Variant<T...>::match() takes either one callable argument that "
901 "accepts every type T; or one for each type T, in order");
902 return Impl::matchN(std::forward
<ConcreteVariant
>(aVariant
),
903 std::forward
<M0
>(aM0
), std::forward
<M1
>(aM1
),
904 std::forward
<Ms
>(aMs
)...);
909 * AsVariant() is used to construct a Variant<T,...> value containing the
910 * provided T value using type inference. It can be used to construct Variant
911 * values in expressions or return them from functions without specifying the
912 * entire Variant type.
914 * Because AsVariant() must copy or move the value into a temporary and this
915 * cannot necessarily be elided by the compiler, it's mostly appropriate only
916 * for use with primitive or very small types.
918 * AsVariant() returns a AsVariantTemporary value which is implicitly
919 * convertible to any Variant that can hold a value of type T.
921 template <typename T
>
922 detail::AsVariantTemporary
<T
> AsVariant(T
&& aValue
) {
923 return detail::AsVariantTemporary
<T
>(std::forward
<T
>(aValue
));
926 } // namespace mozilla
928 #endif /* mozilla_Variant_h */