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