Source code

Revision control

Other Tools

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/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>
19
20
#ifndef mozilla_Variant_h
21
# define mozilla_Variant_h
22
23
namespace IPC {
24
template <typename T>
25
struct ParamTraits;
26
} // namespace IPC
27
28
namespace mozilla {
29
30
template <typename... Ts>
31
class Variant;
32
33
namespace detail {
34
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;
38
39
template <typename T, typename... Ts>
40
struct Nth<0, T, Ts...> {
41
using Type = T;
42
};
43
44
template <size_t N, typename T, typename... Ts>
45
struct Nth<N, T, Ts...> {
46
using Type = typename Nth<N - 1, Ts...>::Type;
47
};
48
49
/// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
50
template <typename T, typename... Variants>
51
struct SelectVariantTypeHelper;
52
53
template <typename T>
54
struct SelectVariantTypeHelper<T> {
55
static constexpr size_t count = 0;
56
};
57
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;
63
};
64
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;
70
};
71
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;
77
};
78
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;
84
};
85
86
template <typename T, typename Head, typename... Variants>
87
struct SelectVariantTypeHelper<T, Head, Variants...>
88
: public SelectVariantTypeHelper<T, Variants...> {};
89
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.)
97
*/
98
template <typename T, typename... Variants>
99
struct SelectVariantType
100
: public SelectVariantTypeHelper<
101
typename RemoveConst<typename RemoveReference<T>::Type>::Type,
102
Variants...> {};
103
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);
110
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;
117
};
118
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.
122
123
template <typename Tag, size_t N, typename T, typename U, typename Next,
124
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
static Tag tag() { return Next::template tag<U>(); }
131
};
132
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); }
137
};
138
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.
144
145
template <typename Tag, size_t N, typename... Ts>
146
struct VariantImplementation;
147
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);
156
}
157
158
template <typename Variant>
159
static void copyConstruct(void* aLhs, const Variant& aRhs) {
160
::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
161
}
162
163
template <typename Variant>
164
static void moveConstruct(void* aLhs, Variant&& aRhs) {
165
::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
166
}
167
168
template <typename Variant>
169
static void destroy(Variant& aV) {
170
aV.template as<N>().~T();
171
}
172
173
template <typename Variant>
174
static bool equal(const Variant& aLhs, const Variant& aRhs) {
175
return aLhs.template as<N>() == aRhs.template as<N>();
176
}
177
178
template <typename Matcher, typename ConcreteVariant>
179
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
180
return aMatcher(aV.template as<N>());
181
}
182
183
template <typename ConcreteVariant, typename Matcher>
184
static decltype(auto) matchN(ConcreteVariant& aV, Matcher&& aMatcher) {
185
return aMatcher(aV.template as<N>());
186
}
187
};
188
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...>;
194
195
template <typename U>
196
static Tag tag() {
197
return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
198
}
199
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);
206
}
207
}
208
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));
215
}
216
}
217
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);
224
}
225
}
226
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);
234
}
235
}
236
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.
246
//
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);
252
}
253
}
254
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)...);
266
}
267
}
268
};
269
270
/**
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.
275
*/
276
template <typename T>
277
struct AsVariantTemporary {
278
explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {}
279
280
template <typename U>
281
explicit AsVariantTemporary(U&& aValue) : mValue(std::forward<U>(aValue)) {}
282
283
AsVariantTemporary(const AsVariantTemporary& aOther)
284
: mValue(aOther.mValue) {}
285
286
AsVariantTemporary(AsVariantTemporary&& aOther)
287
: mValue(std::move(aOther.mValue)) {}
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>
300
struct VariantType {
301
using Type = T;
302
};
303
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;
308
};
309
310
/**
311
* # mozilla::Variant
312
*
313
* A variant / tagged union / heterogenous disjoint union / sum-type template
314
* class. Similar in concept to (but not derived from) `boost::variant`.
315
*
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.
320
*
321
* ## Usage
322
*
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.
327
*
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
332
*
333
* Because specifying the full type of a Variant value is often verbose,
334
* there are two easier ways to construct values:
335
*
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.
341
*
342
* Variant<char, uint32_t> Foo() { return AsVariant('x'); }
343
* // ...
344
* Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
345
*
346
* B. Brace-construction with VariantType or VariantIndex; this also allows
347
* in-place construction with any number of arguments.
348
*
349
* struct AB { AB(int, int){...} };
350
* static Variant<AB, bool> foo()
351
* {
352
* return {VariantIndex<0>{}, 1, 2};
353
* }
354
* // ...
355
* Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
356
*
357
* All access to the contained value goes through type-safe accessors.
358
* Either the stored type, or the type index may be provided.
359
*
360
* void
361
* Foo(Variant<A, B, C> v)
362
* {
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
* ...
370
* }
371
* }
372
*
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.
378
*
379
* // Bad!
380
* template <typename T>
381
* struct ResultOrError
382
* {
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?
393
*
394
* // Good!
395
* template <typename T>
396
* struct ResultOrError
397
* {
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!
406
*
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.
409
*
410
* A a;
411
* Variant<A, B, C> v(a);
412
* v.as<B>(); // <--- Assertion failure!
413
*
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.
416
*
417
* A a;
418
* Variant<A, B, C> v(a);
419
* v.as<SomeRandomType>(); // <--- Compiler error!
420
*
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:
423
*
424
* Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
425
* auto ptr = v.extract<UniquePtr<A>>();
426
*
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.
432
*
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!
441
* }
442
* }
443
*
444
* // Instead, a single function object (that can deal with all possible
445
* // options) may be provided:
446
* struct FooMatcher
447
* {
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!
453
* }
454
* char* foo(Variant<A, B, C, D>& v) {
455
* return v.match(FooMatcher());
456
* }
457
*
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&){...});
461
* }
462
*
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&) { ... });
470
* }
471
*
472
* ## Examples
473
*
474
* A tree is either an empty leaf, or a node with a value and two children:
475
*
476
* struct Leaf { };
477
*
478
* template<typename T>
479
* struct Node
480
* {
481
* T value;
482
* Tree<T>* left;
483
* Tree<T>* right;
484
* };
485
*
486
* template<typename T>
487
* using Tree = Variant<Leaf, Node<T>>;
488
*
489
* A copy-on-write string is either a non-owning reference to some existing
490
* string, or an owning reference to our copy:
491
*
492
* class CopyOnWriteString
493
* {
494
* Variant<const char*, UniquePtr<char[]>> string;
495
*
496
* ...
497
* };
498
*
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.
504
*/
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...>>;
508
509
using Tag = typename detail::VariantTag<Ts...>::Type;
510
using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
511
512
static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
513
static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
514
515
// Raw storage for the contained variant value.
516
alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
517
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;
521
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; }
527
528
const void* ptr() const { return rawData; }
529
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));
543
}
544
545
/**
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.
550
*/
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)...);
555
}
556
557
/**
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.
563
*/
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)...);
568
}
569
570
/**
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().
574
*/
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));
584
}
585
586
/** Copy construction. */
587
Variant(const Variant& aRhs) : tag(aRhs.tag) {
588
Impl::copyConstruct(ptr(), aRhs);
589
}
590
591
/** Move construction. */
592
Variant(Variant&& aRhs) : tag(aRhs.tag) {
593
Impl::moveConstruct(ptr(), std::move(aRhs));
594
}
595
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;
602
}
603
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;
610
}
611
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;
621
}
622
623
~Variant() { Impl::destroy(*this); }
624
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;
632
}
633
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);
639
}
640
641
/**
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.
644
*/
645
bool operator==(const Variant& aRhs) const {
646
return tag == aRhs.tag && Impl::equal(*this, aRhs);
647
}
648
649
/**
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.
653
*/
654
bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); }
655
656
// Accessors for working with the contained variant value.
657
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());
666
}
667
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());
674
}
675
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());
683
}
684
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());
691
}
692
693
/**
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.
698
*/
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>()));
706
}
707
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>()));
714
}
715
716
// Exhaustive matching of all variant types on the contained value.
717
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);
722
}
723
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)...);
739
}
740
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);
745
}
746
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)...);
762
}
763
764
/**
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.
768
*/
769
mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const {
770
return mozilla::AddToHash(hashValue, tag);
771
}
772
};
773
774
/*
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.
779
*
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.
783
*
784
* AsVariant() returns a AsVariantTemporary value which is implicitly
785
* convertible to any Variant that can hold a value of type T.
786
*/
787
template <typename T>
788
detail::AsVariantTemporary<T> AsVariant(T&& aValue) {
789
return detail::AsVariantTemporary<T>(std::forward<T>(aValue));
790
}
791
792
} // namespace mozilla
793
794
#endif /* mozilla_Variant_h */