Bug 1551001 [wpt PR 16740] - Don't mark disconnected tree-scopes for style update...
[gecko.git] / mfbt / Variant.h
blob9fe280cacf3c076d3f1c01b40ae7356ffdf31018
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. */
9 #include <new>
10 #include <stdint.h>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/FunctionTypeTraits.h"
14 #include "mozilla/HashFunctions.h"
15 #include "mozilla/OperatorNewExtensions.h"
16 #include "mozilla/TemplateLib.h"
17 #include "mozilla/TypeTraits.h"
18 #include <utility>
20 #ifndef mozilla_Variant_h
21 # define mozilla_Variant_h
23 namespace IPC {
24 template <typename T>
25 struct ParamTraits;
26 } // namespace IPC
28 namespace mozilla {
30 template <typename... Ts>
31 class Variant;
33 namespace detail {
35 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
36 template <size_t N, typename... Ts>
37 struct Nth;
39 template <typename T, typename... Ts>
40 struct Nth<0, T, Ts...> {
41 using Type = T;
44 template <size_t N, typename T, typename... Ts>
45 struct Nth<N, T, Ts...> {
46 using Type = typename Nth<N - 1, Ts...>::Type;
49 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
50 template <typename T, typename... Variants>
51 struct SelectVariantTypeHelper;
53 template <typename T>
54 struct SelectVariantTypeHelper<T> {
55 static constexpr size_t count = 0;
58 template <typename T, typename... Variants>
59 struct SelectVariantTypeHelper<T, T, Variants...> {
60 typedef T Type;
61 static constexpr size_t count =
62 1 + SelectVariantTypeHelper<T, Variants...>::count;
65 template <typename T, typename... Variants>
66 struct SelectVariantTypeHelper<T, const T, Variants...> {
67 typedef const T Type;
68 static constexpr size_t count =
69 1 + SelectVariantTypeHelper<T, Variants...>::count;
72 template <typename T, typename... Variants>
73 struct SelectVariantTypeHelper<T, const T&, Variants...> {
74 typedef const T& Type;
75 static constexpr size_t count =
76 1 + SelectVariantTypeHelper<T, Variants...>::count;
79 template <typename T, typename... Variants>
80 struct SelectVariantTypeHelper<T, T&&, Variants...> {
81 typedef T&& Type;
82 static constexpr size_t count =
83 1 + SelectVariantTypeHelper<T, Variants...>::count;
86 template <typename T, typename Head, typename... Variants>
87 struct SelectVariantTypeHelper<T, Head, Variants...>
88 : public SelectVariantTypeHelper<T, Variants...> {};
90 /**
91 * SelectVariantType takes a type T and a list of variant types Variants and
92 * yields a type Type, selected from Variants, that can store a value of type T
93 * or a reference to type T. If no such type was found, Type is not defined.
94 * SelectVariantType also has a `count` member that contains the total number of
95 * selectable types (which will be used to check that a requested type is not
96 * ambiguously present twice.)
98 template <typename T, typename... Variants>
99 struct SelectVariantType
100 : public SelectVariantTypeHelper<
101 typename RemoveConst<typename RemoveReference<T>::Type>::Type,
102 Variants...> {};
104 // Compute a fast, compact type that can be used to hold integral values that
105 // distinctly map to every type in Ts.
106 template <typename... Ts>
107 struct VariantTag {
108 private:
109 static const size_t TypeCount = sizeof...(Ts);
111 public:
112 using Type = typename Conditional < TypeCount < 3, bool,
113 typename Conditional<TypeCount<(1 << 8), uint_fast8_t,
114 size_t // stop caring past a certain
115 // point :-)
116 >::Type>::Type;
119 // TagHelper gets the given sentinel tag value for the given type T. This has to
120 // be split out from VariantImplementation because you can't nest a partial
121 // template specialization within a template class.
123 template <typename Tag, size_t N, typename T, typename U, typename Next,
124 bool isMatch>
125 struct TagHelper;
127 // In the case where T != U, we continue recursion.
128 template <typename Tag, size_t N, typename T, typename U, typename Next>
129 struct TagHelper<Tag, N, T, U, Next, false> {
130 static Tag tag() { return Next::template tag<U>(); }
133 // In the case where T == U, return the tag number.
134 template <typename Tag, size_t N, typename T, typename U, typename Next>
135 struct TagHelper<Tag, N, T, U, Next, true> {
136 static Tag tag() { return Tag(N); }
139 // The VariantImplementation template provides the guts of mozilla::Variant. We
140 // create a VariantImplementation for each T in Ts... which handles
141 // construction, destruction, etc for when the Variant's type is T. If the
142 // Variant's type isn't T, it punts the request on to the next
143 // VariantImplementation.
145 template <typename Tag, size_t N, typename... Ts>
146 struct VariantImplementation;
148 // The singly typed Variant / recursion base case.
149 template <typename Tag, size_t N, typename T>
150 struct VariantImplementation<Tag, N, T> {
151 template <typename U>
152 static Tag tag() {
153 static_assert(mozilla::IsSame<T, U>::value,
154 "mozilla::Variant: tag: bad type!");
155 return Tag(N);
158 template <typename Variant>
159 static void copyConstruct(void* aLhs, const Variant& aRhs) {
160 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
163 template <typename Variant>
164 static void moveConstruct(void* aLhs, Variant&& aRhs) {
165 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
168 template <typename Variant>
169 static void destroy(Variant& aV) {
170 aV.template as<N>().~T();
173 template <typename Variant>
174 static bool equal(const Variant& aLhs, const Variant& aRhs) {
175 return aLhs.template as<N>() == aRhs.template as<N>();
178 template <typename Matcher, typename ConcreteVariant>
179 static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
180 return aMatcher(aV.template as<N>());
183 template <typename ConcreteVariant, typename Matcher>
184 static decltype(auto) matchN(ConcreteVariant& aV, Matcher&& aMatcher) {
185 return aMatcher(aV.template as<N>());
189 // VariantImplementation for some variant type T.
190 template <typename Tag, size_t N, typename T, typename... Ts>
191 struct VariantImplementation<Tag, N, T, Ts...> {
192 // The next recursive VariantImplementation.
193 using Next = VariantImplementation<Tag, N + 1, Ts...>;
195 template <typename U>
196 static Tag tag() {
197 return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
200 template <typename Variant>
201 static void copyConstruct(void* aLhs, const Variant& aRhs) {
202 if (aRhs.template is<N>()) {
203 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
204 } else {
205 Next::copyConstruct(aLhs, aRhs);
209 template <typename Variant>
210 static void moveConstruct(void* aLhs, Variant&& aRhs) {
211 if (aRhs.template is<N>()) {
212 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
213 } else {
214 Next::moveConstruct(aLhs, std::move(aRhs));
218 template <typename Variant>
219 static void destroy(Variant& aV) {
220 if (aV.template is<N>()) {
221 aV.template as<N>().~T();
222 } else {
223 Next::destroy(aV);
227 template <typename Variant>
228 static bool equal(const Variant& aLhs, const Variant& aRhs) {
229 if (aLhs.template is<N>()) {
230 MOZ_ASSERT(aRhs.template is<N>());
231 return aLhs.template as<N>() == aRhs.template as<N>();
232 } else {
233 return Next::equal(aLhs, aRhs);
237 template <typename Matcher, typename ConcreteVariant>
238 static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
239 if (aV.template is<N>()) {
240 return aMatcher(aV.template as<N>());
241 } else {
242 // If you're seeing compilation errors here like "no matching
243 // function for call to 'match'" then that means that the
244 // Matcher doesn't exhaust all variant types. There must exist a
245 // Matcher::operator()(T&) for every variant type T.
247 // If you're seeing compilation errors here like "cannot initialize
248 // return object of type <...> with an rvalue of type <...>" then that
249 // means that the Matcher::operator()(T&) overloads are returning
250 // different types. They must all return the same type.
251 return Next::match(std::forward<Matcher>(aMatcher), aV);
255 template <typename ConcreteVariant, typename Mi, typename... Ms>
256 static decltype(auto) matchN(ConcreteVariant& aV, Mi&& aMi, Ms&&... aMs) {
257 if (aV.template is<N>()) {
258 return aMi(aV.template as<N>());
259 } else {
260 // If you're seeing compilation errors here like "no matching
261 // function for call to 'match'" then that means that the
262 // Matchers don't exhaust all variant types. There must exist a
263 // Matcher (with its operator()(T&)) for every variant type T, in the
264 // exact same order.
265 return Next::matchN(aV, std::forward<Ms>(aMs)...);
271 * AsVariantTemporary stores a value of type T to allow construction of a
272 * Variant value via type inference. Because T is copied and there's no
273 * guarantee that the copy can be elided, AsVariantTemporary is best used with
274 * primitive or very small types.
276 template <typename T>
277 struct AsVariantTemporary {
278 explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {}
280 template <typename U>
281 explicit AsVariantTemporary(U&& aValue) : mValue(std::forward<U>(aValue)) {}
283 AsVariantTemporary(const AsVariantTemporary& aOther)
284 : mValue(aOther.mValue) {}
286 AsVariantTemporary(AsVariantTemporary&& aOther)
287 : mValue(std::move(aOther.mValue)) {}
289 AsVariantTemporary() = delete;
290 void operator=(const AsVariantTemporary&) = delete;
291 void operator=(AsVariantTemporary&&) = delete;
293 typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
296 } // namespace detail
298 // Used to unambiguously specify one of the Variant's type.
299 template <typename T>
300 struct VariantType {
301 using Type = T;
304 // Used to specify one of the Variant's type by index.
305 template <size_t N>
306 struct VariantIndex {
307 static constexpr size_t index = N;
311 * # mozilla::Variant
313 * A variant / tagged union / heterogenous disjoint union / sum-type template
314 * class. Similar in concept to (but not derived from) `boost::variant`.
316 * Sometimes, you may wish to use a C union with non-POD types. However, this is
317 * forbidden in C++ because it is not clear which type in the union should have
318 * its constructor and destructor run on creation and deletion
319 * respectively. This is the problem that `mozilla::Variant` solves.
321 * ## Usage
323 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
324 * its variant types (ignoring const and references). It does *not* support
325 * construction from subclasses of variant types or types that coerce to one of
326 * the variant types.
328 * Variant<char, uint32_t> v1('a');
329 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
330 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
331 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
333 * Because specifying the full type of a Variant value is often verbose,
334 * there are two easier ways to construct values:
336 * A. AsVariant() can be used to construct a Variant value using type inference
337 * in contexts such as expressions or when returning values from functions.
338 * Because AsVariant() must copy or move the value into a temporary and this
339 * cannot necessarily be elided by the compiler, it's mostly appropriate only
340 * for use with primitive or very small types.
342 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
343 * // ...
344 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
346 * B. Brace-construction with VariantType or VariantIndex; this also allows
347 * in-place construction with any number of arguments.
349 * struct AB { AB(int, int){...} };
350 * static Variant<AB, bool> foo()
352 * return {VariantIndex<0>{}, 1, 2};
354 * // ...
355 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
357 * All access to the contained value goes through type-safe accessors.
358 * Either the stored type, or the type index may be provided.
360 * void
361 * Foo(Variant<A, B, C> v)
363 * if (v.is<A>()) {
364 * A& ref = v.as<A>();
365 * ...
366 * } else (v.is<1>()) { // Instead of v.is<B>.
367 * ...
368 * } else {
369 * ...
373 * In some situation, a Variant may be constructed from templated types, in
374 * which case it is possible that the same type could be given multiple times by
375 * an external developer. Or seemingly-different types could be aliases.
376 * In this case, repeated types can only be accessed through their index, to
377 * prevent ambiguous access by type.
379 * // Bad!
380 * template <typename T>
381 * struct ResultOrError
383 * Variant<T, int> m;
384 * ResultOrError() : m(int(0)) {} // Error '0' by default
385 * ResultOrError(const T& r) : m(r) {}
386 * bool IsResult() const { return m.is<T>(); }
387 * bool IsError() const { return m.is<int>(); }
388 * };
389 * // Now instantiante with the result being an int too:
390 * ResultOrError<int> myResult(123); // Fail!
391 * // In Variant<int, int>, which 'int' are we refering to, from inside
392 * // ResultOrError functions?
394 * // Good!
395 * template <typename T>
396 * struct ResultOrError
398 * Variant<T, int> m;
399 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
400 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
401 * bool IsResult() const { return m.is<0>(); } // 0 -> T
402 * bool IsError() const { return m.is<1>(); } // 1 -> int
403 * };
404 * // Now instantiante with the result being an int too:
405 * ResultOrError<int> myResult(123); // It now works!
407 * Attempting to use the contained value as type `T1` when the `Variant`
408 * instance contains a value of type `T2` causes an assertion failure.
410 * A a;
411 * Variant<A, B, C> v(a);
412 * v.as<B>(); // <--- Assertion failure!
414 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
415 * member of the set of `Ts...` is a compiler error.
417 * A a;
418 * Variant<A, B, C> v(a);
419 * v.as<SomeRandomType>(); // <--- Compiler error!
421 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
422 * out of the containing `Variant` instance with the `extract<T>` method:
424 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
425 * auto ptr = v.extract<UniquePtr<A>>();
427 * Finally, you can exhaustively match on the contained variant and branch into
428 * different code paths depending on which type is contained. This is preferred
429 * to manually checking every variant type T with is<T>() because it provides
430 * compile-time checking that you handled every type, rather than runtime
431 * assertion failures.
433 * // Bad!
434 * char* foo(Variant<A, B, C, D>& v) {
435 * if (v.is<A>()) {
436 * return ...;
437 * } else if (v.is<B>()) {
438 * return ...;
439 * } else {
440 * return doSomething(v.as<C>()); // Forgot about case D!
444 * // Instead, a single function object (that can deal with all possible
445 * // options) may be provided:
446 * struct FooMatcher
448 * // The return type of all matchers must be identical.
449 * char* operator()(A& a) { ... }
450 * char* operator()(B& b) { ... }
451 * char* operator()(C& c) { ... }
452 * char* operator()(D& d) { ... } // Compile-time error to forget D!
454 * char* foo(Variant<A, B, C, D>& v) {
455 * return v.match(FooMatcher());
458 * // In some situations, a single generic lambda may also be appropriate:
459 * char* foo(Variant<A, B, C, D>& v) {
460 * return v.match([](auto&){...});
463 * // Alternatively, multiple function objects may be provided, each one
464 * // corresponding to an option, in the same order:
465 * char* foo(Variant<A, B, C, D>& v) {
466 * return v.match([](A&) { ... },
467 * [](B&) { ... },
468 * [](C&) { ... },
469 * [](D&) { ... });
472 * ## Examples
474 * A tree is either an empty leaf, or a node with a value and two children:
476 * struct Leaf { };
478 * template<typename T>
479 * struct Node
481 * T value;
482 * Tree<T>* left;
483 * Tree<T>* right;
484 * };
486 * template<typename T>
487 * using Tree = Variant<Leaf, Node<T>>;
489 * A copy-on-write string is either a non-owning reference to some existing
490 * string, or an owning reference to our copy:
492 * class CopyOnWriteString
494 * Variant<const char*, UniquePtr<char[]>> string;
496 * ...
497 * };
499 * Because Variant must be aligned suitable to hold any value stored within it,
500 * and because |alignas| requirements don't affect platform ABI with respect to
501 * how parameters are laid out in memory, Variant can't be used as the type of a
502 * function parameter. Pass Variant to functions by pointer or reference
503 * instead.
505 template <typename... Ts>
506 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
507 friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
509 using Tag = typename detail::VariantTag<Ts...>::Type;
510 using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
512 static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
513 static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
515 // Raw storage for the contained variant value.
516 alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
518 // Each type is given a unique tag value that lets us keep track of the
519 // contained variant value's type.
520 Tag tag;
522 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
523 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
524 // through |void*|. Placing the latter cast in these separate functions
525 // breaks the chain such that affected GCC versions no longer warn/error.
526 void* ptr() { return rawData; }
528 const void* ptr() const { return rawData; }
530 public:
531 /** Perfect forwarding construction for some variant type T. */
532 template <typename RefT,
533 // RefT captures both const& as well as && (as intended, to support
534 // perfect forwarding), so we have to remove those qualifiers here
535 // when ensuring that T is a variant of this type, and getting T's
536 // tag, etc.
537 typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
538 explicit Variant(RefT&& aT) : tag(Impl::template tag<T>()) {
539 static_assert(
540 detail::SelectVariantType<RefT, Ts...>::count == 1,
541 "Variant can only be selected by type if that type is unique");
542 ::new (KnownNotNull, ptr()) T(std::forward<RefT>(aT));
546 * Perfect forwarding construction for some variant type T, by
547 * explicitly giving the type.
548 * This is necessary to construct from any number of arguments,
549 * or to convert from a type that is not in the Variant's type list.
551 template <typename T, typename... Args>
552 MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs)
553 : tag(Impl::template tag<T>()) {
554 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
558 * Perfect forwarding construction for some variant type T, by
559 * explicitly giving the type index.
560 * This is necessary to construct from any number of arguments,
561 * or to convert from a type that is not in the Variant's type list,
562 * or to construct a type that is present more than once in the Variant.
564 template <size_t N, typename... Args>
565 MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs) : tag(N) {
566 using T = typename detail::Nth<N, Ts...>::Type;
567 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
571 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
572 * stored in one of the types allowable in this Variant. This is used in the
573 * implementation of AsVariant().
575 template <typename RefT>
576 MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
577 : tag(Impl::template tag<
578 typename detail::SelectVariantType<RefT, Ts...>::Type>()) {
579 using T = typename detail::SelectVariantType<RefT, Ts...>::Type;
580 static_assert(
581 detail::SelectVariantType<RefT, Ts...>::count == 1,
582 "Variant can only be selected by type if that type is unique");
583 ::new (KnownNotNull, ptr()) T(std::move(aValue.mValue));
586 /** Copy construction. */
587 Variant(const Variant& aRhs) : tag(aRhs.tag) {
588 Impl::copyConstruct(ptr(), aRhs);
591 /** Move construction. */
592 Variant(Variant&& aRhs) : tag(aRhs.tag) {
593 Impl::moveConstruct(ptr(), std::move(aRhs));
596 /** Copy assignment. */
597 Variant& operator=(const Variant& aRhs) {
598 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
599 this->~Variant();
600 ::new (KnownNotNull, this) Variant(aRhs);
601 return *this;
604 /** Move assignment. */
605 Variant& operator=(Variant&& aRhs) {
606 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
607 this->~Variant();
608 ::new (KnownNotNull, this) Variant(std::move(aRhs));
609 return *this;
612 /** Move assignment from AsVariant(). */
613 template <typename T>
614 Variant& operator=(detail::AsVariantTemporary<T>&& aValue) {
615 static_assert(
616 detail::SelectVariantType<T, Ts...>::count == 1,
617 "Variant can only be selected by type if that type is unique");
618 this->~Variant();
619 ::new (KnownNotNull, this) Variant(std::move(aValue));
620 return *this;
623 ~Variant() { Impl::destroy(*this); }
625 /** Check which variant type is currently contained. */
626 template <typename T>
627 bool is() const {
628 static_assert(
629 detail::SelectVariantType<T, Ts...>::count == 1,
630 "provided a type not uniquely found in this Variant's type list");
631 return Impl::template tag<T>() == tag;
634 template <size_t N>
635 bool is() const {
636 static_assert(N < sizeof...(Ts),
637 "provided an index outside of this Variant's type list");
638 return N == size_t(tag);
642 * Operator == overload that defers to the variant type's operator==
643 * implementation if the rhs is tagged as the same type as this one.
645 bool operator==(const Variant& aRhs) const {
646 return tag == aRhs.tag && Impl::equal(*this, aRhs);
650 * Operator != overload that defers to the negation of the variant type's
651 * operator== implementation if the rhs is tagged as the same type as this
652 * one.
654 bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); }
656 // Accessors for working with the contained variant value.
658 /** Mutable reference. */
659 template <typename T>
660 T& as() {
661 static_assert(
662 detail::SelectVariantType<T, Ts...>::count == 1,
663 "provided a type not uniquely found in this Variant's type list");
664 MOZ_RELEASE_ASSERT(is<T>());
665 return *static_cast<T*>(ptr());
668 template <size_t N>
669 typename detail::Nth<N, Ts...>::Type& as() {
670 static_assert(N < sizeof...(Ts),
671 "provided an index outside of this Variant's type list");
672 MOZ_RELEASE_ASSERT(is<N>());
673 return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
676 /** Immutable const reference. */
677 template <typename T>
678 const T& as() const {
679 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
680 "provided a type not found in this Variant's type list");
681 MOZ_RELEASE_ASSERT(is<T>());
682 return *static_cast<const T*>(ptr());
685 template <size_t N>
686 const typename detail::Nth<N, Ts...>::Type& as() const {
687 static_assert(N < sizeof...(Ts),
688 "provided an index outside of this Variant's type list");
689 MOZ_RELEASE_ASSERT(is<N>());
690 return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
694 * Extract the contained variant value from this container into a temporary
695 * value. On completion, the value in the variant will be in a
696 * safely-destructible state, as determined by the behavior of T's move
697 * constructor when provided the variant's internal value.
699 template <typename T>
700 T extract() {
701 static_assert(
702 detail::SelectVariantType<T, Ts...>::count == 1,
703 "provided a type not uniquely found in this Variant's type list");
704 MOZ_ASSERT(is<T>());
705 return T(std::move(as<T>()));
708 template <size_t N>
709 typename detail::Nth<N, Ts...>::Type extract() {
710 static_assert(N < sizeof...(Ts),
711 "provided an index outside of this Variant's type list");
712 MOZ_RELEASE_ASSERT(is<N>());
713 return typename detail::Nth<N, Ts...>::Type(std::move(as<N>()));
716 // Exhaustive matching of all variant types on the contained value.
718 /** Match on an immutable const reference. */
719 template <typename Matcher>
720 decltype(auto) match(Matcher&& aMatcher) const {
721 return Impl::match(std::forward<Matcher>(aMatcher), *this);
724 template <typename M0, typename M1, typename... Ms>
725 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const {
726 static_assert(
727 2 + sizeof...(Ms) == sizeof...(Ts),
728 "Variant<T...>::match() takes either one callable argument that "
729 "accepts every type T; or one for each type T, in order");
730 static_assert(
731 tl::And<IsSame<typename FunctionTypeTraits<M0>::ReturnType,
732 typename FunctionTypeTraits<M1>::ReturnType>::value,
733 IsSame<typename FunctionTypeTraits<M1>::ReturnType,
734 typename FunctionTypeTraits<Ms>::ReturnType>::value...>::
735 value,
736 "all matchers must have the same return type");
737 return Impl::matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
738 std::forward<Ms>(aMs)...);
741 /** Match on a mutable non-const reference. */
742 template <typename Matcher>
743 decltype(auto) match(Matcher&& aMatcher) {
744 return Impl::match(std::forward<Matcher>(aMatcher), *this);
747 template <typename M0, typename M1, typename... Ms>
748 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) {
749 static_assert(
750 2 + sizeof...(Ms) == sizeof...(Ts),
751 "Variant<T...>::match() takes either one callable argument that "
752 "accepts every type T; or one for each type T, in order");
753 static_assert(
754 tl::And<IsSame<typename FunctionTypeTraits<M0>::ReturnType,
755 typename FunctionTypeTraits<M1>::ReturnType>::value,
756 IsSame<typename FunctionTypeTraits<M0>::ReturnType,
757 typename FunctionTypeTraits<Ms>::ReturnType>::value...>::
758 value,
759 "all matchers must have the same return type");
760 return Impl::matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
761 std::forward<Ms>(aMs)...);
765 * Incorporate the current variant's tag into hashValue.
766 * Note that this does not hash the actual contents; you must take
767 * care of that yourself, perhaps by using a match.
769 mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const {
770 return mozilla::AddToHash(hashValue, tag);
775 * AsVariant() is used to construct a Variant<T,...> value containing the
776 * provided T value using type inference. It can be used to construct Variant
777 * values in expressions or return them from functions without specifying the
778 * entire Variant type.
780 * Because AsVariant() must copy or move the value into a temporary and this
781 * cannot necessarily be elided by the compiler, it's mostly appropriate only
782 * for use with primitive or very small types.
784 * AsVariant() returns a AsVariantTemporary value which is implicitly
785 * convertible to any Variant that can hold a value of type T.
787 template <typename T>
788 detail::AsVariantTemporary<T> AsVariant(T&& aValue) {
789 return detail::AsVariantTemporary<T>(std::forward<T>(aValue));
792 } // namespace mozilla
794 #endif /* mozilla_Variant_h */