Variant.h (33851B)
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 <algorithm> 10 #include <new> 11 #include <stdint.h> 12 13 #include "mozilla/Assertions.h" 14 #include "mozilla/HashFunctions.h" 15 #include "mozilla/OperatorNewExtensions.h" 16 17 #include <type_traits> 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 std::remove_const_t<std::remove_reference_t<T>>, Variants...> {}; 102 103 // Compute a fast, compact type that can be used to hold integral values that 104 // distinctly map to every type in Ts. 105 template <typename... Ts> 106 struct VariantTag { 107 private: 108 static const size_t TypeCount = sizeof...(Ts); 109 110 public: 111 using Type = std::conditional_t< 112 (TypeCount <= 2), bool, 113 std::conditional_t<(TypeCount <= size_t(UINT_FAST8_MAX)), uint_fast8_t, 114 size_t // stop caring past a certain 115 // point :-) 116 >>; 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(std::is_same_v<T, U>, "mozilla::Variant: tag: bad type!"); 154 return Tag(N); 155 } 156 157 template <typename Variant> 158 static void copyConstruct(void* aLhs, const Variant& aRhs) { 159 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>()); 160 } 161 162 template <typename Variant> 163 static void moveConstruct(void* aLhs, Variant&& aRhs) { 164 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>()); 165 } 166 167 template <typename Variant> 168 static void destroy(Variant& aV) { 169 aV.template as<N>().~T(); 170 } 171 172 template <typename Variant> 173 static bool equal(const Variant& aLhs, const Variant& aRhs) { 174 return aLhs.template as<N>() == aRhs.template as<N>(); 175 } 176 177 template <typename Matcher, typename ConcreteVariant> 178 static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) { 179 if constexpr (std::is_invocable_v<Matcher, Tag, 180 decltype(std::forward<ConcreteVariant>(aV) 181 .template as<N>())>) { 182 return std::forward<Matcher>(aMatcher)( 183 Tag(N), std::forward<ConcreteVariant>(aV).template as<N>()); 184 } else { 185 return std::forward<Matcher>(aMatcher)( 186 std::forward<ConcreteVariant>(aV).template as<N>()); 187 } 188 } 189 190 template <typename ConcreteVariant, typename Matcher> 191 static decltype(auto) matchN(ConcreteVariant&& aV, Matcher&& aMatcher) { 192 if constexpr (std::is_invocable_v<Matcher, Tag, 193 decltype(std::forward<ConcreteVariant>(aV) 194 .template as<N>())>) { 195 return std::forward<Matcher>(aMatcher)( 196 Tag(N), std::forward<ConcreteVariant>(aV).template as<N>()); 197 } else { 198 return std::forward<Matcher>(aMatcher)( 199 std::forward<ConcreteVariant>(aV).template as<N>()); 200 } 201 } 202 }; 203 204 // VariantImplementation for some variant type T. 205 template <typename Tag, size_t N, typename T, typename... Ts> 206 struct VariantImplementation<Tag, N, T, Ts...> { 207 // The next recursive VariantImplementation. 208 using Next = VariantImplementation<Tag, N + 1, Ts...>; 209 210 template <typename U> 211 static Tag tag() { 212 return TagHelper<Tag, N, T, U, Next, std::is_same_v<T, U>>::tag(); 213 } 214 215 template <typename Variant> 216 static void copyConstruct(void* aLhs, const Variant& aRhs) { 217 if (aRhs.template is<N>()) { 218 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>()); 219 } else { 220 Next::copyConstruct(aLhs, aRhs); 221 } 222 } 223 224 template <typename Variant> 225 static void moveConstruct(void* aLhs, Variant&& aRhs) { 226 if (aRhs.template is<N>()) { 227 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>()); 228 } else { 229 Next::moveConstruct(aLhs, std::move(aRhs)); 230 } 231 } 232 233 template <typename Variant> 234 static void destroy(Variant& aV) { 235 if (aV.template is<N>()) { 236 aV.template as<N>().~T(); 237 } else { 238 Next::destroy(aV); 239 } 240 } 241 242 template <typename Variant> 243 static bool equal(const Variant& aLhs, const Variant& aRhs) { 244 if (aLhs.template is<N>()) { 245 MOZ_ASSERT(aRhs.template is<N>()); 246 return aLhs.template as<N>() == aRhs.template as<N>(); 247 } else { 248 return Next::equal(aLhs, aRhs); 249 } 250 } 251 252 template <typename Matcher, typename ConcreteVariant> 253 static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) { 254 if (aV.template is<N>()) { 255 if constexpr (std::is_invocable_v<Matcher, Tag, 256 decltype(std::forward<ConcreteVariant>( 257 aV) 258 .template as<N>())>) { 259 return std::forward<Matcher>(aMatcher)( 260 Tag(N), std::forward<ConcreteVariant>(aV).template as<N>()); 261 } else { 262 return std::forward<Matcher>(aMatcher)( 263 std::forward<ConcreteVariant>(aV).template as<N>()); 264 } 265 } else { 266 // If you're seeing compilation errors here like "no matching 267 // function for call to 'match'" then that means that the 268 // Matcher doesn't exhaust all variant types. There must exist a 269 // Matcher::operator()(T&) for every variant type T. 270 // 271 // If you're seeing compilation errors here like "cannot initialize 272 // return object of type <...> with an rvalue of type <...>" then that 273 // means that the Matcher::operator()(T&) overloads are returning 274 // different types. They must all return the same type. 275 return Next::match(std::forward<Matcher>(aMatcher), 276 std::forward<ConcreteVariant>(aV)); 277 } 278 } 279 280 template <typename ConcreteVariant, typename Mi, typename... Ms> 281 static decltype(auto) matchN(ConcreteVariant&& aV, Mi&& aMi, Ms&&... aMs) { 282 if (aV.template is<N>()) { 283 if constexpr (std::is_invocable_v<Mi, Tag, 284 decltype(std::forward<ConcreteVariant>( 285 aV) 286 .template as<N>())>) { 287 static_assert( 288 std::is_same_v< 289 decltype(std::forward<Mi>(aMi)( 290 Tag(N), 291 std::forward<ConcreteVariant>(aV).template as<N>())), 292 decltype(Next::matchN(std::forward<ConcreteVariant>(aV), 293 std::forward<Ms>(aMs)...))>, 294 "all matchers must have the same return type"); 295 return std::forward<Mi>(aMi)( 296 Tag(N), std::forward<ConcreteVariant>(aV).template as<N>()); 297 } else { 298 static_assert( 299 std::is_same_v< 300 decltype(std::forward<Mi>(aMi)( 301 std::forward<ConcreteVariant>(aV).template as<N>())), 302 decltype(Next::matchN(std::forward<ConcreteVariant>(aV), 303 std::forward<Ms>(aMs)...))>, 304 "all matchers must have the same return type"); 305 return std::forward<Mi>(aMi)( 306 std::forward<ConcreteVariant>(aV).template as<N>()); 307 } 308 } else { 309 // If you're seeing compilation errors here like "no matching 310 // function for call to 'match'" then that means that the 311 // Matchers don't exhaust all variant types. There must exist a 312 // Matcher (with its operator()(T&)) for every variant type T, in the 313 // exact same order. 314 return Next::matchN(std::forward<ConcreteVariant>(aV), 315 std::forward<Ms>(aMs)...); 316 } 317 } 318 }; 319 320 /** 321 * AsVariantTemporary stores a value of type T to allow construction of a 322 * Variant value via type inference. Because T is copied and there's no 323 * guarantee that the copy can be elided, AsVariantTemporary is best used with 324 * primitive or very small types. 325 */ 326 template <typename T> 327 struct AsVariantTemporary { 328 explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {} 329 330 template <typename U> 331 explicit AsVariantTemporary(U&& aValue) : mValue(std::forward<U>(aValue)) {} 332 333 AsVariantTemporary(const AsVariantTemporary& aOther) 334 : mValue(aOther.mValue) {} 335 336 AsVariantTemporary(AsVariantTemporary&& aOther) 337 : mValue(std::move(aOther.mValue)) {} 338 339 AsVariantTemporary() = delete; 340 void operator=(const AsVariantTemporary&) = delete; 341 void operator=(AsVariantTemporary&&) = delete; 342 343 std::remove_const_t<std::remove_reference_t<T>> mValue; 344 }; 345 346 } // namespace detail 347 348 // Used to unambiguously specify one of the Variant's type. 349 template <typename T> 350 struct VariantType { 351 using Type = T; 352 }; 353 354 // Used to specify one of the Variant's type by index. 355 template <size_t N> 356 struct VariantIndex { 357 static constexpr size_t index = N; 358 }; 359 360 /** 361 * # mozilla::Variant 362 * 363 * A variant / tagged union / heterogenous disjoint union / sum-type template 364 * class. Similar in concept to (but not derived from) `boost::variant`. 365 * 366 * Sometimes, you may wish to use a C union with non-POD types. However, this is 367 * forbidden in C++ because it is not clear which type in the union should have 368 * its constructor and destructor run on creation and deletion 369 * respectively. This is the problem that `mozilla::Variant` solves. 370 * 371 * Since C++17, std::variant exists. `mozilla::Variant` differs conceptually 372 * from it by (a.) having a richer `.match` API (compared to `std::visit`) and 373 * (b.) having a different assignment semantic. Assigning to an `std::variant` 374 * assigns to the underlying value, while assigning to a `mozilla::Variant` 375 * deletes the previous value then move-constructs a new value. This makes it 376 * possible to store *and* update const values. 377 * 378 * ## Usage 379 * 380 * A `mozilla::Variant` instance is constructed (via move or copy) from one of 381 * its variant types (ignoring const and references). It does *not* support 382 * construction from subclasses of variant types or types that coerce to one of 383 * the variant types. 384 * 385 * Variant<char, uint32_t> v1('a'); 386 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>()); 387 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed 388 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int 389 * 390 * Because specifying the full type of a Variant value is often verbose, 391 * there are two easier ways to construct values: 392 * 393 * A. AsVariant() can be used to construct a Variant value using type inference 394 * in contexts such as expressions or when returning values from functions. 395 * Because AsVariant() must copy or move the value into a temporary and this 396 * cannot necessarily be elided by the compiler, it's mostly appropriate only 397 * for use with primitive or very small types. 398 * 399 * Variant<char, uint32_t> Foo() { return AsVariant('x'); } 400 * // ... 401 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x'). 402 * 403 * B. Brace-construction with VariantType or VariantIndex; this also allows 404 * in-place construction with any number of arguments. 405 * 406 * struct AB { AB(int, int){...} }; 407 * static Variant<AB, bool> foo() 408 * { 409 * return {VariantIndex<0>{}, 1, 2}; 410 * } 411 * // ... 412 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2). 413 * 414 * All access to the contained value goes through type-safe accessors. 415 * Either the stored type, or the type index may be provided. 416 * 417 * void 418 * Foo(Variant<A, B, C> v) 419 * { 420 * if (v.is<A>()) { 421 * A& ref = v.as<A>(); 422 * ... 423 * } else (v.is<1>()) { // Instead of v.is<B>. 424 * ... 425 * } else { 426 * ... 427 * } 428 * } 429 * 430 * In some situation, a Variant may be constructed from templated types, in 431 * which case it is possible that the same type could be given multiple times by 432 * an external developer. Or seemingly-different types could be aliases. 433 * In this case, repeated types can only be accessed through their index, to 434 * prevent ambiguous access by type. 435 * 436 * // Bad! 437 * template <typename T> 438 * struct ResultOrError 439 * { 440 * Variant<T, int> m; 441 * ResultOrError() : m(int(0)) {} // Error '0' by default 442 * ResultOrError(const T& r) : m(r) {} 443 * bool IsResult() const { return m.is<T>(); } 444 * bool IsError() const { return m.is<int>(); } 445 * }; 446 * // Now instantiante with the result being an int too: 447 * ResultOrError<int> myResult(123); // Fail! 448 * // In Variant<int, int>, which 'int' are we refering to, from inside 449 * // ResultOrError functions? 450 * 451 * // Good! 452 * template <typename T> 453 * struct ResultOrError 454 * { 455 * Variant<T, int> m; 456 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default 457 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {} 458 * bool IsResult() const { return m.is<0>(); } // 0 -> T 459 * bool IsError() const { return m.is<1>(); } // 1 -> int 460 * }; 461 * // Now instantiante with the result being an int too: 462 * ResultOrError<int> myResult(123); // It now works! 463 * 464 * Attempting to use the contained value as type `T1` when the `Variant` 465 * instance contains a value of type `T2` causes an assertion failure. 466 * 467 * A a; 468 * Variant<A, B, C> v(a); 469 * v.as<B>(); // <--- Assertion failure! 470 * 471 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a 472 * member of the set of `Ts...` is a compiler error. 473 * 474 * A a; 475 * Variant<A, B, C> v(a); 476 * v.as<SomeRandomType>(); // <--- Compiler error! 477 * 478 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it 479 * out of the containing `Variant` instance with the `extract<T>` method: 480 * 481 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>()); 482 * auto ptr = v.extract<UniquePtr<A>>(); 483 * 484 * Finally, you can exhaustively match on the contained variant and branch into 485 * different code paths depending on which type is contained. This is preferred 486 * to manually checking every variant type T with is<T>() because it provides 487 * compile-time checking that you handled every type, rather than runtime 488 * assertion failures. 489 * 490 * // Bad! 491 * char* foo(Variant<A, B, C, D>& v) { 492 * if (v.is<A>()) { 493 * return ...; 494 * } else if (v.is<B>()) { 495 * return ...; 496 * } else { 497 * return doSomething(v.as<C>()); // Forgot about case D! 498 * } 499 * } 500 * 501 * // Instead, a single function object (that can deal with all possible 502 * // options) may be provided: 503 * struct FooMatcher 504 * { 505 * // The return type of all matchers must be identical. 506 * char* operator()(A& a) { ... } 507 * char* operator()(B& b) { ... } 508 * char* operator()(C& c) { ... } 509 * char* operator()(D& d) { ... } // Compile-time error to forget D! 510 * } 511 * char* foo(Variant<A, B, C, D>& v) { 512 * return v.match(FooMatcher()); 513 * } 514 * 515 * // In some situations, a single generic lambda may also be appropriate: 516 * char* foo(Variant<A, B, C, D>& v) { 517 * return v.match([](auto&) {...}); 518 * } 519 * 520 * // Alternatively, multiple function objects may be provided, each one 521 * // corresponding to an option, in the same order: 522 * char* foo(Variant<A, B, C, D>& v) { 523 * return v.match([](A&) { ... }, 524 * [](B&) { ... }, 525 * [](C&) { ... }, 526 * [](D&) { ... }); 527 * } 528 * 529 * // In rare cases, the index of the currently-active alternative is 530 * // needed, it may be obtained by adding a first parameter in the matcner 531 * // callback, which will receive the index in its most compact type (just 532 * // use `size_t` if the exact type is not important), e.g.: 533 * char* foo(Variant<A, B, C, D>& v) { 534 * return v.match([](auto aIndex, auto& aAlternative) {...}); 535 * // --OR-- 536 * return v.match([](size_t aIndex, auto& aAlternative) {...}); 537 * } 538 * 539 * ## Examples 540 * 541 * A tree is either an empty leaf, or a node with a value and two children: 542 * 543 * struct Leaf { }; 544 * 545 * template<typename T> 546 * struct Node 547 * { 548 * T value; 549 * Tree<T>* left; 550 * Tree<T>* right; 551 * }; 552 * 553 * template<typename T> 554 * using Tree = Variant<Leaf, Node<T>>; 555 * 556 * A copy-on-write string is either a non-owning reference to some existing 557 * string, or an owning reference to our copy: 558 * 559 * class CopyOnWriteString 560 * { 561 * Variant<const char*, UniquePtr<char[]>> string; 562 * 563 * ... 564 * }; 565 * 566 * Because Variant must be aligned suitable to hold any value stored within it, 567 * and because |alignas| requirements don't affect platform ABI with respect to 568 * how parameters are laid out in memory, Variant can't be used as the type of a 569 * function parameter. Pass Variant to functions by pointer or reference 570 * instead. 571 */ 572 template <typename... Ts> 573 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS 574 MOZ_NON_PARAM MOZ_GSL_OWNER Variant { 575 friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>; 576 577 using Tag = typename detail::VariantTag<Ts...>::Type; 578 using Impl = detail::VariantImplementation<Tag, 0, Ts...>; 579 580 static constexpr size_t RawDataAlignment = std::max({alignof(Ts)...}); 581 static constexpr size_t RawDataSize = std::max({sizeof(Ts)...}); 582 583 // Raw storage for the contained variant value. 584 alignas(RawDataAlignment) unsigned char rawData[RawDataSize]; 585 586 // Each type is given a unique tag value that lets us keep track of the 587 // contained variant value's type. 588 Tag tag; 589 590 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a 591 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even 592 // through |void*|. Placing the latter cast in these separate functions 593 // breaks the chain such that affected GCC versions no longer warn/error. 594 void* ptr() { return rawData; } 595 596 const void* ptr() const { return rawData; } 597 598 public: 599 /** Perfect forwarding construction for some variant type T. */ 600 template <typename RefT, 601 // RefT captures both const& as well as && (as intended, to support 602 // perfect forwarding), so we have to remove those qualifiers here 603 // when ensuring that T is a variant of this type, and getting T's 604 // tag, etc. 605 typename T = typename detail::SelectVariantType<RefT, Ts...>::Type> 606 explicit Variant(RefT&& aT) : tag(Impl::template tag<T>()) { 607 static_assert( 608 detail::SelectVariantType<RefT, Ts...>::count == 1, 609 "Variant can only be selected by type if that type is unique"); 610 ::new (KnownNotNull, ptr()) T(std::forward<RefT>(aT)); 611 } 612 613 /** 614 * Perfect forwarding construction for some variant type T, by 615 * explicitly giving the type. 616 * This is necessary to construct from any number of arguments, 617 * or to convert from a type that is not in the Variant's type list. 618 */ 619 template <typename T, typename... Args> 620 MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs) 621 : tag(Impl::template tag<T>()) { 622 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...); 623 } 624 625 /** 626 * Perfect forwarding construction for some variant type T, by 627 * explicitly giving the type index. 628 * This is necessary to construct from any number of arguments, 629 * or to convert from a type that is not in the Variant's type list, 630 * or to construct a type that is present more than once in the Variant. 631 */ 632 template <size_t N, typename... Args> 633 MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs) : tag(N) { 634 using T = typename detail::Nth<N, Ts...>::Type; 635 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...); 636 } 637 638 /** 639 * Constructs this Variant from an AsVariantTemporary<T> such that T can be 640 * stored in one of the types allowable in this Variant. This is used in the 641 * implementation of AsVariant(). 642 */ 643 template <typename RefT> 644 MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue) 645 : tag(Impl::template tag< 646 typename detail::SelectVariantType<RefT, Ts...>::Type>()) { 647 using T = typename detail::SelectVariantType<RefT, Ts...>::Type; 648 static_assert( 649 detail::SelectVariantType<RefT, Ts...>::count == 1, 650 "Variant can only be selected by type if that type is unique"); 651 ::new (KnownNotNull, ptr()) T(std::move(aValue.mValue)); 652 } 653 654 /** Copy construction. */ 655 Variant(const Variant& aRhs) : tag(aRhs.tag) { 656 Impl::copyConstruct(ptr(), aRhs); 657 } 658 659 /** Move construction. */ 660 Variant(Variant&& aRhs) : tag(aRhs.tag) { 661 Impl::moveConstruct(ptr(), std::move(aRhs)); 662 } 663 664 /** Copy assignment. */ 665 Variant& operator=(const Variant& aRhs) { 666 MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); 667 this->~Variant(); 668 ::new (KnownNotNull, this) Variant(aRhs); 669 return *this; 670 } 671 672 /** Move assignment. */ 673 Variant& operator=(Variant&& aRhs) { 674 MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); 675 this->~Variant(); 676 ::new (KnownNotNull, this) Variant(std::move(aRhs)); 677 return *this; 678 } 679 680 /** Move assignment from AsVariant(). */ 681 template <typename T> 682 Variant& operator=(detail::AsVariantTemporary<T>&& aValue) { 683 static_assert( 684 detail::SelectVariantType<T, Ts...>::count == 1, 685 "Variant can only be selected by type if that type is unique"); 686 this->~Variant(); 687 ::new (KnownNotNull, this) Variant(std::move(aValue)); 688 return *this; 689 } 690 691 ~Variant() { Impl::destroy(*this); } 692 693 template <typename T, typename... Args> 694 T& emplace(Args&&... aTs) { 695 Impl::destroy(*this); 696 tag = Impl::template tag<T>(); 697 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...); 698 return as<T>(); 699 } 700 701 template <size_t N, typename... Args> 702 typename detail::Nth<N, Ts...>::Type& emplace(Args&&... aTs) { 703 using T = typename detail::Nth<N, Ts...>::Type; 704 Impl::destroy(*this); 705 tag = N; 706 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...); 707 return as<N>(); 708 } 709 710 /** Check which variant type is currently contained. */ 711 template <typename T> 712 bool is() const { 713 static_assert( 714 detail::SelectVariantType<T, Ts...>::count == 1, 715 "provided a type not uniquely found in this Variant's type list"); 716 return Impl::template tag<T>() == tag; 717 } 718 719 template <size_t N> 720 bool is() const { 721 static_assert(N < sizeof...(Ts), 722 "provided an index outside of this Variant's type list"); 723 return N == size_t(tag); 724 } 725 726 /** 727 * Operator == overload that defers to the variant type's operator== 728 * implementation if the rhs is tagged as the same type as this one. 729 */ 730 bool operator==(const Variant& aRhs) const { 731 return tag == aRhs.tag && Impl::equal(*this, aRhs); 732 } 733 734 /** 735 * Operator != overload that defers to the negation of the variant type's 736 * operator== implementation if the rhs is tagged as the same type as this 737 * one. 738 */ 739 bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); } 740 741 // Accessors for working with the contained variant value. 742 743 /** Mutable lvalue-reference. */ 744 template <typename T> 745 T& as() & MOZ_LIFETIME_BOUND { 746 static_assert( 747 detail::SelectVariantType<T, Ts...>::count == 1, 748 "provided a type not uniquely found in this Variant's type list"); 749 MOZ_RELEASE_ASSERT(is<T>()); 750 return *static_cast<T*>(ptr()); 751 } 752 753 template <size_t N> 754 typename detail::Nth<N, Ts...>::Type& as() & MOZ_LIFETIME_BOUND { 755 static_assert(N < sizeof...(Ts), 756 "provided an index outside of this Variant's type list"); 757 MOZ_RELEASE_ASSERT(is<N>()); 758 return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr()); 759 } 760 761 /** Immutable const lvalue-reference. */ 762 template <typename T> 763 const T& as() const& MOZ_LIFETIME_BOUND { 764 static_assert(detail::SelectVariantType<T, Ts...>::count == 1, 765 "provided a type not found in this Variant's type list"); 766 MOZ_RELEASE_ASSERT(is<T>()); 767 return *static_cast<const T*>(ptr()); 768 } 769 770 template <size_t N> 771 const typename detail::Nth<N, Ts...>::Type& as() const& MOZ_LIFETIME_BOUND { 772 static_assert(N < sizeof...(Ts), 773 "provided an index outside of this Variant's type list"); 774 MOZ_RELEASE_ASSERT(is<N>()); 775 return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr()); 776 } 777 778 /** Mutable rvalue-reference. */ 779 template <typename T> 780 T&& as() && MOZ_LIFETIME_BOUND { 781 static_assert( 782 detail::SelectVariantType<T, Ts...>::count == 1, 783 "provided a type not uniquely found in this Variant's type list"); 784 MOZ_RELEASE_ASSERT(is<T>()); 785 return std::move(*static_cast<T*>(ptr())); 786 } 787 788 template <size_t N> 789 typename detail::Nth<N, Ts...>::Type&& as() && MOZ_LIFETIME_BOUND { 790 static_assert(N < sizeof...(Ts), 791 "provided an index outside of this Variant's type list"); 792 MOZ_RELEASE_ASSERT(is<N>()); 793 return std::move( 794 *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr())); 795 } 796 797 /** Immutable const rvalue-reference. */ 798 template <typename T> 799 const T&& as() const&& MOZ_LIFETIME_BOUND { 800 static_assert(detail::SelectVariantType<T, Ts...>::count == 1, 801 "provided a type not found in this Variant's type list"); 802 MOZ_RELEASE_ASSERT(is<T>()); 803 return std::move(*static_cast<const T*>(ptr())); 804 } 805 806 template <size_t N> 807 const typename detail::Nth<N, Ts...>::Type&& as() const&& MOZ_LIFETIME_BOUND { 808 static_assert(N < sizeof...(Ts), 809 "provided an index outside of this Variant's type list"); 810 MOZ_RELEASE_ASSERT(is<N>()); 811 return std::move( 812 *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr())); 813 } 814 815 /** 816 * Extract the contained variant value from this container into a temporary 817 * value. On completion, the value in the variant will be in a 818 * safely-destructible state, as determined by the behavior of T's move 819 * constructor when provided the variant's internal value. 820 */ 821 template <typename T> 822 T extract() { 823 static_assert( 824 detail::SelectVariantType<T, Ts...>::count == 1, 825 "provided a type not uniquely found in this Variant's type list"); 826 MOZ_ASSERT(is<T>()); 827 return T(std::move(as<T>())); 828 } 829 830 template <size_t N> 831 typename detail::Nth<N, Ts...>::Type extract() { 832 static_assert(N < sizeof...(Ts), 833 "provided an index outside of this Variant's type list"); 834 MOZ_RELEASE_ASSERT(is<N>()); 835 return typename detail::Nth<N, Ts...>::Type(std::move(as<N>())); 836 } 837 838 // Exhaustive matching of all variant types on the contained value. 839 840 /** Match on an immutable const lvalue-reference. */ 841 template <typename Matcher> 842 decltype(auto) match(Matcher&& aMatcher) const& { 843 return Impl::match(std::forward<Matcher>(aMatcher), *this); 844 } 845 846 template <typename M0, typename M1, typename... Ms> 847 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const& { 848 return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1), 849 std::forward<Ms>(aMs)...); 850 } 851 852 /** Match on a mutable non-const lvalue-reference. */ 853 template <typename Matcher> 854 decltype(auto) match(Matcher&& aMatcher) & { 855 return Impl::match(std::forward<Matcher>(aMatcher), *this); 856 } 857 858 template <typename M0, typename M1, typename... Ms> 859 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) & { 860 return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1), 861 std::forward<Ms>(aMs)...); 862 } 863 864 /** Match on an immutable const rvalue-reference. */ 865 template <typename Matcher> 866 decltype(auto) match(Matcher&& aMatcher) const&& { 867 return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this)); 868 } 869 870 template <typename M0, typename M1, typename... Ms> 871 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const&& { 872 return matchN(std::move(*this), std::forward<M0>(aM0), 873 std::forward<M1>(aM1), std::forward<Ms>(aMs)...); 874 } 875 876 /** Match on a mutable non-const rvalue-reference. */ 877 template <typename Matcher> 878 decltype(auto) match(Matcher&& aMatcher) && { 879 return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this)); 880 } 881 882 template <typename M0, typename M1, typename... Ms> 883 decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) && { 884 return matchN(std::move(*this), std::forward<M0>(aM0), 885 std::forward<M1>(aM1), std::forward<Ms>(aMs)...); 886 } 887 888 /** 889 * Incorporate the current variant's tag into hashValue. 890 * Note that this does not hash the actual contents; you must take 891 * care of that yourself, perhaps by using a match. 892 */ 893 mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const { 894 return mozilla::AddToHash(hashValue, tag); 895 } 896 897 private: 898 template <typename ConcreteVariant, typename M0, typename M1, typename... Ms> 899 static decltype(auto) matchN(ConcreteVariant&& aVariant, M0&& aM0, M1&& aM1, 900 Ms&&... aMs) { 901 static_assert( 902 2 + sizeof...(Ms) == sizeof...(Ts), 903 "Variant<T...>::match() takes either one callable argument that " 904 "accepts every type T; or one for each type T, in order"); 905 return Impl::matchN(std::forward<ConcreteVariant>(aVariant), 906 std::forward<M0>(aM0), std::forward<M1>(aM1), 907 std::forward<Ms>(aMs)...); 908 } 909 }; 910 911 /* 912 * AsVariant() is used to construct a Variant<T,...> value containing the 913 * provided T value using type inference. It can be used to construct Variant 914 * values in expressions or return them from functions without specifying the 915 * entire Variant type. 916 * 917 * Because AsVariant() must copy or move the value into a temporary and this 918 * cannot necessarily be elided by the compiler, it's mostly appropriate only 919 * for use with primitive or very small types. 920 * 921 * AsVariant() returns a AsVariantTemporary value which is implicitly 922 * convertible to any Variant that can hold a value of type T. 923 */ 924 template <typename T> 925 detail::AsVariantTemporary<T> AsVariant(T&& aValue) { 926 return detail::AsVariantTemporary<T>(std::forward<T>(aValue)); 927 } 928 929 } // namespace mozilla 930 931 #endif /* mozilla_Variant_h */