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/Move.h"
14 #include "mozilla/OperatorNewExtensions.h"
15 #include "mozilla/TemplateLib.h"
16 #include "mozilla/TypeTraits.h"
18 #ifndef mozilla_Variant_h
19 # define mozilla_Variant_h
28 template <typename
... Ts
>
33 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
34 template <size_t N
, typename
... Ts
>
37 template <typename T
, typename
... Ts
>
38 struct Nth
<0, T
, Ts
...> {
42 template <size_t N
, typename T
, typename
... Ts
>
43 struct Nth
<N
, T
, Ts
...> {
44 using Type
= typename Nth
<N
- 1, Ts
...>::Type
;
47 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
48 template <typename T
, typename
... Variants
>
49 struct SelectVariantTypeHelper
;
52 struct SelectVariantTypeHelper
<T
> {
53 static constexpr size_t count
= 0;
56 template <typename T
, typename
... Variants
>
57 struct SelectVariantTypeHelper
<T
, T
, Variants
...> {
59 static constexpr size_t count
=
60 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
63 template <typename T
, typename
... Variants
>
64 struct SelectVariantTypeHelper
<T
, const T
, Variants
...> {
66 static constexpr size_t count
=
67 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
70 template <typename T
, typename
... Variants
>
71 struct SelectVariantTypeHelper
<T
, const T
&, Variants
...> {
72 typedef const T
& Type
;
73 static constexpr size_t count
=
74 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
77 template <typename T
, typename
... Variants
>
78 struct SelectVariantTypeHelper
<T
, T
&&, Variants
...> {
80 static constexpr size_t count
=
81 1 + SelectVariantTypeHelper
<T
, Variants
...>::count
;
84 template <typename T
, typename Head
, typename
... Variants
>
85 struct SelectVariantTypeHelper
<T
, Head
, Variants
...>
86 : public SelectVariantTypeHelper
<T
, Variants
...> {};
89 * SelectVariantType takes a type T and a list of variant types Variants and
90 * yields a type Type, selected from Variants, that can store a value of type T
91 * or a reference to type T. If no such type was found, Type is not defined.
92 * SelectVariantType also has a `count` member that contains the total number of
93 * selectable types (which will be used to check that a requested type is not
94 * ambiguously present twice.)
96 template <typename T
, typename
... Variants
>
97 struct SelectVariantType
98 : public SelectVariantTypeHelper
<
99 typename RemoveConst
<typename RemoveReference
<T
>::Type
>::Type
,
102 // Compute a fast, compact type that can be used to hold integral values that
103 // distinctly map to every type in Ts.
104 template <typename
... Ts
>
107 static const size_t TypeCount
= sizeof...(Ts
);
110 using Type
= typename Conditional
< TypeCount
< 3, bool,
111 typename Conditional
<TypeCount
<(1 << 8), uint_fast8_t,
112 size_t // stop caring past a certain
117 // TagHelper gets the given sentinel tag value for the given type T. This has to
118 // be split out from VariantImplementation because you can't nest a partial
119 // template specialization within a template class.
121 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
,
125 // In the case where T != U, we continue recursion.
126 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
127 struct TagHelper
<Tag
, N
, T
, U
, Next
, false> {
128 static Tag
tag() { return Next::template tag
<U
>(); }
131 // In the case where T == U, return the tag number.
132 template <typename Tag
, size_t N
, typename T
, typename U
, typename Next
>
133 struct TagHelper
<Tag
, N
, T
, U
, Next
, true> {
134 static Tag
tag() { return Tag(N
); }
137 // The VariantImplementation template provides the guts of mozilla::Variant. We
138 // create a VariantImplementation for each T in Ts... which handles
139 // construction, destruction, etc for when the Variant's type is T. If the
140 // Variant's type isn't T, it punts the request on to the next
141 // VariantImplementation.
143 template <typename Tag
, size_t N
, typename
... Ts
>
144 struct VariantImplementation
;
146 // The singly typed Variant / recursion base case.
147 template <typename Tag
, size_t N
, typename T
>
148 struct VariantImplementation
<Tag
, N
, T
> {
149 template <typename U
>
151 static_assert(mozilla::IsSame
<T
, U
>::value
,
152 "mozilla::Variant: tag: bad type!");
156 template <typename Variant
>
157 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
158 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
161 template <typename Variant
>
162 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
163 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
166 template <typename Variant
>
167 static void destroy(Variant
& aV
) {
168 aV
.template as
<N
>().~T();
171 template <typename Variant
>
172 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
173 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
176 template <typename Matcher
, typename ConcreteVariant
>
177 static auto match(Matcher
&& aMatcher
, ConcreteVariant
& aV
)
178 -> decltype(aMatcher
.match(aV
.template as
<N
>())) {
179 return aMatcher
.match(aV
.template as
<N
>());
183 // VariantImplementation for some variant type T.
184 template <typename Tag
, size_t N
, typename T
, typename
... Ts
>
185 struct VariantImplementation
<Tag
, N
, T
, Ts
...> {
186 // The next recursive VariantImplementation.
187 using Next
= VariantImplementation
<Tag
, N
+ 1, Ts
...>;
189 template <typename U
>
191 return TagHelper
<Tag
, N
, T
, U
, Next
, IsSame
<T
, U
>::value
>::tag();
194 template <typename Variant
>
195 static void copyConstruct(void* aLhs
, const Variant
& aRhs
) {
196 if (aRhs
.template is
<N
>()) {
197 ::new (KnownNotNull
, aLhs
) T(aRhs
.template as
<N
>());
199 Next::copyConstruct(aLhs
, aRhs
);
203 template <typename Variant
>
204 static void moveConstruct(void* aLhs
, Variant
&& aRhs
) {
205 if (aRhs
.template is
<N
>()) {
206 ::new (KnownNotNull
, aLhs
) T(aRhs
.template extract
<N
>());
208 Next::moveConstruct(aLhs
, std::move(aRhs
));
212 template <typename Variant
>
213 static void destroy(Variant
& aV
) {
214 if (aV
.template is
<N
>()) {
215 aV
.template as
<N
>().~T();
221 template <typename Variant
>
222 static bool equal(const Variant
& aLhs
, const Variant
& aRhs
) {
223 if (aLhs
.template is
<N
>()) {
224 MOZ_ASSERT(aRhs
.template is
<N
>());
225 return aLhs
.template as
<N
>() == aRhs
.template as
<N
>();
227 return Next::equal(aLhs
, aRhs
);
231 template <typename Matcher
, typename ConcreteVariant
>
232 static auto match(Matcher
&& aMatcher
, ConcreteVariant
& aV
)
233 -> decltype(aMatcher
.match(aV
.template as
<N
>())) {
234 if (aV
.template is
<N
>()) {
235 return aMatcher
.match(aV
.template as
<N
>());
237 // If you're seeing compilation errors here like "no matching
238 // function for call to 'match'" then that means that the
239 // Matcher doesn't exhaust all variant types. There must exist a
240 // Matcher::match(T&) for every variant type T.
242 // If you're seeing compilation errors here like "cannot
243 // initialize return object of type <...> with an rvalue of type
244 // <...>" then that means that the Matcher::match(T&) overloads
245 // are returning different types. They must all return the same
246 // Matcher::ReturnType type.
247 return Next::match(aMatcher
, aV
);
253 * AsVariantTemporary stores a value of type T to allow construction of a
254 * Variant value via type inference. Because T is copied and there's no
255 * guarantee that the copy can be elided, AsVariantTemporary is best used with
256 * primitive or very small types.
258 template <typename T
>
259 struct AsVariantTemporary
{
260 explicit AsVariantTemporary(const T
& aValue
) : mValue(aValue
) {}
262 template <typename U
>
263 explicit AsVariantTemporary(U
&& aValue
) : mValue(std::forward
<U
>(aValue
)) {}
265 AsVariantTemporary(const AsVariantTemporary
& aOther
)
266 : mValue(aOther
.mValue
) {}
268 AsVariantTemporary(AsVariantTemporary
&& aOther
)
269 : mValue(std::move(aOther
.mValue
)) {}
271 AsVariantTemporary() = delete;
272 void operator=(const AsVariantTemporary
&) = delete;
273 void operator=(AsVariantTemporary
&&) = delete;
275 typename RemoveConst
<typename RemoveReference
<T
>::Type
>::Type mValue
;
278 } // namespace detail
280 // Used to unambiguously specify one of the Variant's type.
281 template <typename T
>
286 // Used to specify one of the Variant's type by index.
288 struct VariantIndex
{
289 static constexpr size_t index
= N
;
295 * A variant / tagged union / heterogenous disjoint union / sum-type template
296 * class. Similar in concept to (but not derived from) `boost::variant`.
298 * Sometimes, you may wish to use a C union with non-POD types. However, this is
299 * forbidden in C++ because it is not clear which type in the union should have
300 * its constructor and destructor run on creation and deletion
301 * respectively. This is the problem that `mozilla::Variant` solves.
305 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
306 * its variant types (ignoring const and references). It does *not* support
307 * construction from subclasses of variant types or types that coerce to one of
310 * Variant<char, uint32_t> v1('a');
311 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
312 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
313 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
315 * Because specifying the full type of a Variant value is often verbose,
316 * there are two easier ways to construct values:
318 * A. AsVariant() can be used to construct a Variant value using type inference
319 * in contexts such as expressions or when returning values from functions.
320 * Because AsVariant() must copy or move the value into a temporary and this
321 * cannot necessarily be elided by the compiler, it's mostly appropriate only
322 * for use with primitive or very small types.
324 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
326 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
328 * B. Brace-construction with VariantType or VariantIndex; this also allows
329 * in-place construction with any number of arguments.
331 * struct AB { AB(int, int){...} };
332 * static Variant<AB, bool> foo()
334 * return {VariantIndex<0>{}, 1, 2};
337 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
339 * All access to the contained value goes through type-safe accessors.
340 * Either the stored type, or the type index may be provided.
343 * Foo(Variant<A, B, C> v)
346 * A& ref = v.as<A>();
348 * } else (v.is<1>()) { // Instead of v.is<B>.
355 * In some situation, a Variant may be constructed from templated types, in
356 * which case it is possible that the same type could be given multiple times by
357 * an external developer. Or seemingly-different types could be aliases.
358 * In this case, repeated types can only be accessed through their index, to
359 * prevent ambiguous access by type.
362 * template <typename T>
363 * struct ResultOrError
366 * ResultOrError() : m(int(0)) {} // Error '0' by default
367 * ResultOrError(const T& r) : m(r) {}
368 * bool IsResult() const { return m.is<T>(); }
369 * bool IsError() const { return m.is<int>(); }
371 * // Now instantiante with the result being an int too:
372 * ResultOrError<int> myResult(123); // Fail!
373 * // In Variant<int, int>, which 'int' are we refering to, from inside
374 * // ResultOrError functions?
377 * template <typename T>
378 * struct ResultOrError
381 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
382 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
383 * bool IsResult() const { return m.is<0>(); } // 0 -> T
384 * bool IsError() const { return m.is<1>(); } // 1 -> int
386 * // Now instantiante with the result being an int too:
387 * ResultOrError<int> myResult(123); // It now works!
389 * Attempting to use the contained value as type `T1` when the `Variant`
390 * instance contains a value of type `T2` causes an assertion failure.
393 * Variant<A, B, C> v(a);
394 * v.as<B>(); // <--- Assertion failure!
396 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
397 * member of the set of `Ts...` is a compiler error.
400 * Variant<A, B, C> v(a);
401 * v.as<SomeRandomType>(); // <--- Compiler error!
403 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
404 * out of the containing `Variant` instance with the `extract<T>` method:
406 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
407 * auto ptr = v.extract<UniquePtr<A>>();
409 * Finally, you can exhaustively match on the contained variant and branch into
410 * different code paths depending on which type is contained. This is preferred
411 * to manually checking every variant type T with is<T>() because it provides
412 * compile-time checking that you handled every type, rather than runtime
413 * assertion failures.
416 * char* foo(Variant<A, B, C, D>& v) {
419 * } else if (v.is<B>()) {
422 * return doSomething(v.as<C>()); // Forgot about case D!
429 * // The return type of all matchers must be identical.
430 * char* match(A& a) { ... }
431 * char* match(B& b) { ... }
432 * char* match(C& c) { ... }
433 * char* match(D& d) { ... } // Compile-time error to forget D!
435 * char* foo(Variant<A, B, C, D>& v) {
436 * return v.match(FooMatcher());
441 * A tree is either an empty leaf, or a node with a value and two children:
445 * template<typename T>
453 * template<typename T>
454 * using Tree = Variant<Leaf, Node<T>>;
456 * A copy-on-write string is either a non-owning reference to some existing
457 * string, or an owning reference to our copy:
459 * class CopyOnWriteString
461 * Variant<const char*, UniquePtr<char[]>> string;
466 * Because Variant must be aligned suitable to hold any value stored within it,
467 * and because |alignas| requirements don't affect platform ABI with respect to
468 * how parameters are laid out in memory, Variant can't be used as the type of a
469 * function parameter. Pass Variant to functions by pointer or reference
472 template <typename
... Ts
>
473 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
{
474 friend struct IPC::ParamTraits
<mozilla::Variant
<Ts
...>>;
476 using Tag
= typename
detail::VariantTag
<Ts
...>::Type
;
477 using Impl
= detail::VariantImplementation
<Tag
, 0, Ts
...>;
479 static constexpr size_t RawDataAlignment
= tl::Max
<alignof(Ts
)...>::value
;
480 static constexpr size_t RawDataSize
= tl::Max
<sizeof(Ts
)...>::value
;
482 // Raw storage for the contained variant value.
483 alignas(RawDataAlignment
) unsigned char rawData
[RawDataSize
];
485 // Each type is given a unique tag value that lets us keep track of the
486 // contained variant value's type.
489 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
490 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
491 // through |void*|. Placing the latter cast in these separate functions
492 // breaks the chain such that affected GCC versions no longer warn/error.
493 void* ptr() { return rawData
; }
495 const void* ptr() const { return rawData
; }
498 /** Perfect forwarding construction for some variant type T. */
499 template <typename RefT
,
500 // RefT captures both const& as well as && (as intended, to support
501 // perfect forwarding), so we have to remove those qualifiers here
502 // when ensuring that T is a variant of this type, and getting T's
504 typename T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>
505 explicit Variant(RefT
&& aT
) : tag(Impl::template tag
<T
>()) {
507 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
508 "Variant can only be selected by type if that type is unique");
509 ::new (KnownNotNull
, ptr()) T(std::forward
<RefT
>(aT
));
513 * Perfect forwarding construction for some variant type T, by
514 * explicitly giving the type.
515 * This is necessary to construct from any number of arguments,
516 * or to convert from a type that is not in the Variant's type list.
518 template <typename T
, typename
... Args
>
519 MOZ_IMPLICIT
Variant(const VariantType
<T
>&, Args
&&... aTs
)
520 : tag(Impl::template tag
<T
>()) {
521 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
525 * Perfect forwarding construction for some variant type T, by
526 * explicitly giving the type index.
527 * This is necessary to construct from any number of arguments,
528 * or to convert from a type that is not in the Variant's type list,
529 * or to construct a type that is present more than once in the Variant.
531 template <size_t N
, typename
... Args
>
532 MOZ_IMPLICIT
Variant(const VariantIndex
<N
>&, Args
&&... aTs
) : tag(N
) {
533 using T
= typename
detail::Nth
<N
, Ts
...>::Type
;
534 ::new (KnownNotNull
, ptr()) T(std::forward
<Args
>(aTs
)...);
538 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
539 * stored in one of the types allowable in this Variant. This is used in the
540 * implementation of AsVariant().
542 template <typename RefT
>
543 MOZ_IMPLICIT
Variant(detail::AsVariantTemporary
<RefT
>&& aValue
)
544 : tag(Impl::template tag
<
545 typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
>()) {
546 using T
= typename
detail::SelectVariantType
<RefT
, Ts
...>::Type
;
548 detail::SelectVariantType
<RefT
, Ts
...>::count
== 1,
549 "Variant can only be selected by type if that type is unique");
550 ::new (KnownNotNull
, ptr()) T(std::move(aValue
.mValue
));
553 /** Copy construction. */
554 Variant(const Variant
& aRhs
) : tag(aRhs
.tag
) {
555 Impl::copyConstruct(ptr(), aRhs
);
558 /** Move construction. */
559 Variant(Variant
&& aRhs
) : tag(aRhs
.tag
) {
560 Impl::moveConstruct(ptr(), std::move(aRhs
));
563 /** Copy assignment. */
564 Variant
& operator=(const Variant
& aRhs
) {
565 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
567 ::new (KnownNotNull
, this) Variant(aRhs
);
571 /** Move assignment. */
572 Variant
& operator=(Variant
&& aRhs
) {
573 MOZ_ASSERT(&aRhs
!= this, "self-assign disallowed");
575 ::new (KnownNotNull
, this) Variant(std::move(aRhs
));
579 /** Move assignment from AsVariant(). */
580 template <typename T
>
581 Variant
& operator=(detail::AsVariantTemporary
<T
>&& aValue
) {
583 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
584 "Variant can only be selected by type if that type is unique");
586 ::new (KnownNotNull
, this) Variant(std::move(aValue
));
590 ~Variant() { Impl::destroy(*this); }
592 /** Check which variant type is currently contained. */
593 template <typename T
>
596 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
597 "provided a type not uniquely found in this Variant's type list");
598 return Impl::template tag
<T
>() == tag
;
603 static_assert(N
< sizeof...(Ts
),
604 "provided an index outside of this Variant's type list");
605 return N
== size_t(tag
);
609 * Operator == overload that defers to the variant type's operator==
610 * implementation if the rhs is tagged as the same type as this one.
612 bool operator==(const Variant
& aRhs
) const {
613 return tag
== aRhs
.tag
&& Impl::equal(*this, aRhs
);
617 * Operator != overload that defers to the negation of the variant type's
618 * operator== implementation if the rhs is tagged as the same type as this
621 bool operator!=(const Variant
& aRhs
) const { return !(*this == aRhs
); }
623 // Accessors for working with the contained variant value.
625 /** Mutable reference. */
626 template <typename T
>
629 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
630 "provided a type not uniquely found in this Variant's type list");
631 MOZ_RELEASE_ASSERT(is
<T
>());
632 return *static_cast<T
*>(ptr());
636 typename
detail::Nth
<N
, Ts
...>::Type
& as() {
637 static_assert(N
< sizeof...(Ts
),
638 "provided an index outside of this Variant's type list");
639 MOZ_RELEASE_ASSERT(is
<N
>());
640 return *static_cast<typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
643 /** Immutable const reference. */
644 template <typename T
>
645 const T
& as() const {
646 static_assert(detail::SelectVariantType
<T
, Ts
...>::count
== 1,
647 "provided a type not found in this Variant's type list");
648 MOZ_RELEASE_ASSERT(is
<T
>());
649 return *static_cast<const T
*>(ptr());
653 const typename
detail::Nth
<N
, Ts
...>::Type
& as() const {
654 static_assert(N
< sizeof...(Ts
),
655 "provided an index outside of this Variant's type list");
656 MOZ_RELEASE_ASSERT(is
<N
>());
657 return *static_cast<const typename
detail::Nth
<N
, Ts
...>::Type
*>(ptr());
661 * Extract the contained variant value from this container into a temporary
662 * value. On completion, the value in the variant will be in a
663 * safely-destructible state, as determined by the behavior of T's move
664 * constructor when provided the variant's internal value.
666 template <typename T
>
669 detail::SelectVariantType
<T
, Ts
...>::count
== 1,
670 "provided a type not uniquely found in this Variant's type list");
672 return T(std::move(as
<T
>()));
676 typename
detail::Nth
<N
, Ts
...>::Type
extract() {
677 static_assert(N
< sizeof...(Ts
),
678 "provided an index outside of this Variant's type list");
679 MOZ_RELEASE_ASSERT(is
<N
>());
680 return typename
detail::Nth
<N
, Ts
...>::Type(std::move(as
<N
>()));
683 // Exhaustive matching of all variant types on the contained value.
685 /** Match on an immutable const reference. */
686 template <typename Matcher
>
687 auto match(Matcher
&& aMatcher
) const
688 -> decltype(Impl::match(aMatcher
, *this)) {
689 return Impl::match(aMatcher
, *this);
692 /** Match on a mutable non-const reference. */
693 template <typename Matcher
>
694 auto match(Matcher
&& aMatcher
) -> decltype(Impl::match(aMatcher
, *this)) {
695 return Impl::match(aMatcher
, *this);
700 * AsVariant() is used to construct a Variant<T,...> value containing the
701 * provided T value using type inference. It can be used to construct Variant
702 * values in expressions or return them from functions without specifying the
703 * entire Variant type.
705 * Because AsVariant() must copy or move the value into a temporary and this
706 * cannot necessarily be elided by the compiler, it's mostly appropriate only
707 * for use with primitive or very small types.
709 * AsVariant() returns a AsVariantTemporary value which is implicitly
710 * convertible to any Variant that can hold a value of type T.
712 template <typename T
>
713 detail::AsVariantTemporary
<T
> AsVariant(T
&& aValue
) {
714 return detail::AsVariantTemporary
<T
>(std::forward
<T
>(aValue
));
717 } // namespace mozilla
719 #endif /* mozilla_Variant_h */