Variant.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* A template class for tagged unions. */
  6. #include <new>
  7. #include <stdint.h>
  8. #include "mozilla/Alignment.h"
  9. #include "mozilla/Assertions.h"
  10. #include "mozilla/Move.h"
  11. #include "mozilla/TypeTraits.h"
  12. #ifndef mozilla_Variant_h
  13. #define mozilla_Variant_h
  14. namespace mozilla {
  15. template<typename... Ts>
  16. class Variant;
  17. namespace detail {
  18. // MaxSizeOf computes the maximum sizeof(T) for each T in Ts.
  19. template<typename T, typename... Ts>
  20. struct MaxSizeOf
  21. {
  22. static const size_t size = sizeof(T) > MaxSizeOf<Ts...>::size
  23. ? sizeof(T)
  24. : MaxSizeOf<Ts...>::size;
  25. };
  26. template<typename T>
  27. struct MaxSizeOf<T>
  28. {
  29. static const size_t size = sizeof(T);
  30. };
  31. // The `IsVariant` helper is used in conjunction with static_assert and
  32. // `mozilla::EnableIf` to catch passing non-variant types to `Variant::is<T>()`
  33. // and friends at compile time, rather than at runtime. It ensures that the
  34. // given type `Needle` is one of the types in the set of types `Haystack`.
  35. template<typename Needle, typename... Haystack>
  36. struct IsVariant;
  37. template<typename Needle>
  38. struct IsVariant<Needle>
  39. {
  40. static const bool value = false;
  41. };
  42. template<typename Needle, typename... Haystack>
  43. struct IsVariant<Needle, Needle, Haystack...>
  44. {
  45. static const bool value = true;
  46. };
  47. template<typename Needle, typename T, typename... Haystack>
  48. struct IsVariant<Needle, T, Haystack...> : public IsVariant<Needle, Haystack...> { };
  49. /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
  50. template<typename T, typename... Variants>
  51. struct SelectVariantTypeHelper;
  52. template<typename T>
  53. struct SelectVariantTypeHelper<T>
  54. { };
  55. template<typename T, typename... Variants>
  56. struct SelectVariantTypeHelper<T, T, Variants...>
  57. {
  58. typedef T Type;
  59. };
  60. template<typename T, typename... Variants>
  61. struct SelectVariantTypeHelper<T, const T, Variants...>
  62. {
  63. typedef const T Type;
  64. };
  65. template<typename T, typename... Variants>
  66. struct SelectVariantTypeHelper<T, const T&, Variants...>
  67. {
  68. typedef const T& Type;
  69. };
  70. template<typename T, typename... Variants>
  71. struct SelectVariantTypeHelper<T, T&&, Variants...>
  72. {
  73. typedef T&& Type;
  74. };
  75. template<typename T, typename Head, typename... Variants>
  76. struct SelectVariantTypeHelper<T, Head, Variants...>
  77. : public SelectVariantTypeHelper<T, Variants...>
  78. { };
  79. /**
  80. * SelectVariantType takes a type T and a list of variant types Variants and
  81. * yields a type Type, selected from Variants, that can store a value of type T
  82. * or a reference to type T. If no such type was found, Type is not defined.
  83. */
  84. template <typename T, typename... Variants>
  85. struct SelectVariantType
  86. : public SelectVariantTypeHelper<typename RemoveConst<typename RemoveReference<T>::Type>::Type,
  87. Variants...>
  88. { };
  89. // Compute a fast, compact type that can be used to hold integral values that
  90. // distinctly map to every type in Ts.
  91. template<typename... Ts>
  92. struct VariantTag
  93. {
  94. private:
  95. static const size_t TypeCount = sizeof...(Ts);
  96. public:
  97. using Type =
  98. typename Conditional<TypeCount < 3,
  99. bool,
  100. typename Conditional<TypeCount < (1 << 8),
  101. uint_fast8_t,
  102. size_t // stop caring past a certain point :-)
  103. >::Type
  104. >::Type;
  105. };
  106. // TagHelper gets the given sentinel tag value for the given type T. This has to
  107. // be split out from VariantImplementation because you can't nest a partial
  108. // template specialization within a template class.
  109. template<typename Tag, size_t N, typename T, typename U, typename Next, bool isMatch>
  110. struct TagHelper;
  111. // In the case where T != U, we continue recursion.
  112. template<typename Tag, size_t N, typename T, typename U, typename Next>
  113. struct TagHelper<Tag, N, T, U, Next, false>
  114. {
  115. static Tag tag() { return Next::template tag<U>(); }
  116. };
  117. // In the case where T == U, return the tag number.
  118. template<typename Tag, size_t N, typename T, typename U, typename Next>
  119. struct TagHelper<Tag, N, T, U, Next, true>
  120. {
  121. static Tag tag() { return Tag(N); }
  122. };
  123. // The VariantImplementation template provides the guts of mozilla::Variant. We
  124. // create a VariantImplementation for each T in Ts... which handles
  125. // construction, destruction, etc for when the Variant's type is T. If the
  126. // Variant's type isn't T, it punts the request on to the next
  127. // VariantImplementation.
  128. template<typename Tag, size_t N, typename... Ts>
  129. struct VariantImplementation;
  130. // The singly typed Variant / recursion base case.
  131. template<typename Tag, size_t N, typename T>
  132. struct VariantImplementation<Tag, N, T>
  133. {
  134. template<typename U>
  135. static Tag tag() {
  136. static_assert(mozilla::IsSame<T, U>::value,
  137. "mozilla::Variant: tag: bad type!");
  138. return Tag(N);
  139. }
  140. template<typename Variant>
  141. static void copyConstruct(void* aLhs, const Variant& aRhs) {
  142. new (aLhs) T(aRhs.template as<T>());
  143. }
  144. template<typename Variant>
  145. static void moveConstruct(void* aLhs, Variant&& aRhs) {
  146. new (aLhs) T(aRhs.template extract<T>());
  147. }
  148. template<typename Variant>
  149. static void destroy(Variant& aV) {
  150. aV.template as<T>().~T();
  151. }
  152. template<typename Variant>
  153. static bool
  154. equal(const Variant& aLhs, const Variant& aRhs) {
  155. return aLhs.template as<T>() == aRhs.template as<T>();
  156. }
  157. template<typename Matcher, typename ConcreteVariant>
  158. static auto
  159. match(Matcher&& aMatcher, ConcreteVariant& aV)
  160. -> decltype(aMatcher.match(aV.template as<T>()))
  161. {
  162. return aMatcher.match(aV.template as<T>());
  163. }
  164. };
  165. // VariantImplementation for some variant type T.
  166. template<typename Tag, size_t N, typename T, typename... Ts>
  167. struct VariantImplementation<Tag, N, T, Ts...>
  168. {
  169. // The next recursive VariantImplementation.
  170. using Next = VariantImplementation<Tag, N + 1, Ts...>;
  171. template<typename U>
  172. static Tag tag() {
  173. return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
  174. }
  175. template<typename Variant>
  176. static void copyConstruct(void* aLhs, const Variant& aRhs) {
  177. if (aRhs.template is<T>()) {
  178. new (aLhs) T(aRhs.template as<T>());
  179. } else {
  180. Next::copyConstruct(aLhs, aRhs);
  181. }
  182. }
  183. template<typename Variant>
  184. static void moveConstruct(void* aLhs, Variant&& aRhs) {
  185. if (aRhs.template is<T>()) {
  186. new (aLhs) T(aRhs.template extract<T>());
  187. } else {
  188. Next::moveConstruct(aLhs, aRhs);
  189. }
  190. }
  191. template<typename Variant>
  192. static void destroy(Variant& aV) {
  193. if (aV.template is<T>()) {
  194. aV.template as<T>().~T();
  195. } else {
  196. Next::destroy(aV);
  197. }
  198. }
  199. template<typename Variant>
  200. static bool equal(const Variant& aLhs, const Variant& aRhs) {
  201. if (aLhs.template is<T>()) {
  202. MOZ_ASSERT(aRhs.template is<T>());
  203. return aLhs.template as<T>() == aRhs.template as<T>();
  204. } else {
  205. return Next::equal(aLhs, aRhs);
  206. }
  207. }
  208. template<typename Matcher, typename ConcreteVariant>
  209. static auto
  210. match(Matcher&& aMatcher, ConcreteVariant& aV)
  211. -> decltype(aMatcher.match(aV.template as<T>()))
  212. {
  213. if (aV.template is<T>()) {
  214. return aMatcher.match(aV.template as<T>());
  215. } else {
  216. // If you're seeing compilation errors here like "no matching
  217. // function for call to 'match'" then that means that the
  218. // Matcher doesn't exhaust all variant types. There must exist a
  219. // Matcher::match(T&) for every variant type T.
  220. //
  221. // If you're seeing compilation errors here like "cannot
  222. // initialize return object of type <...> with an rvalue of type
  223. // <...>" then that means that the Matcher::match(T&) overloads
  224. // are returning different types. They must all return the same
  225. // Matcher::ReturnType type.
  226. return Next::match(aMatcher, aV);
  227. }
  228. }
  229. };
  230. /**
  231. * AsVariantTemporary stores a value of type T to allow construction of a
  232. * Variant value via type inference. Because T is copied and there's no
  233. * guarantee that the copy can be elided, AsVariantTemporary is best used with
  234. * primitive or very small types.
  235. */
  236. template <typename T>
  237. struct AsVariantTemporary
  238. {
  239. explicit AsVariantTemporary(const T& aValue)
  240. : mValue(aValue)
  241. {}
  242. template<typename U>
  243. explicit AsVariantTemporary(U&& aValue)
  244. : mValue(Forward<U>(aValue))
  245. {}
  246. AsVariantTemporary(const AsVariantTemporary& aOther)
  247. : mValue(aOther.mValue)
  248. {}
  249. AsVariantTemporary(AsVariantTemporary&& aOther)
  250. : mValue(Move(aOther.mValue))
  251. {}
  252. AsVariantTemporary() = delete;
  253. void operator=(const AsVariantTemporary&) = delete;
  254. void operator=(AsVariantTemporary&&) = delete;
  255. typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
  256. };
  257. } // namespace detail
  258. /**
  259. * # mozilla::Variant
  260. *
  261. * A variant / tagged union / heterogenous disjoint union / sum-type template
  262. * class. Similar in concept to (but not derived from) `boost::variant`.
  263. *
  264. * Sometimes, you may wish to use a C union with non-POD types. However, this is
  265. * forbidden in C++ because it is not clear which type in the union should have
  266. * its constructor and destructor run on creation and deletion
  267. * respectively. This is the problem that `mozilla::Variant` solves.
  268. *
  269. * ## Usage
  270. *
  271. * A `mozilla::Variant` instance is constructed (via move or copy) from one of
  272. * its variant types (ignoring const and references). It does *not* support
  273. * construction from subclasses of variant types or types that coerce to one of
  274. * the variant types.
  275. *
  276. * Variant<char, uint32_t> v1('a');
  277. * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
  278. *
  279. * Because specifying the full type of a Variant value is often verbose,
  280. * AsVariant() can be used to construct a Variant value using type inference in
  281. * contexts such as expressions or when returning values from functions. Because
  282. * AsVariant() must copy or move the value into a temporary and this cannot
  283. * necessarily be elided by the compiler, it's mostly appropriate only for use
  284. * with primitive or very small types.
  285. *
  286. *
  287. * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
  288. * // ...
  289. * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
  290. *
  291. * All access to the contained value goes through type-safe accessors.
  292. *
  293. * void
  294. * Foo(Variant<A, B, C> v)
  295. * {
  296. * if (v.is<A>()) {
  297. * A& ref = v.as<A>();
  298. * ...
  299. * } else {
  300. * ...
  301. * }
  302. * }
  303. *
  304. * Attempting to use the contained value as type `T1` when the `Variant`
  305. * instance contains a value of type `T2` causes an assertion failure.
  306. *
  307. * A a;
  308. * Variant<A, B, C> v(a);
  309. * v.as<B>(); // <--- Assertion failure!
  310. *
  311. * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
  312. * member of the set of `Ts...` is a compiler error.
  313. *
  314. * A a;
  315. * Variant<A, B, C> v(a);
  316. * v.as<SomeRandomType>(); // <--- Compiler error!
  317. *
  318. * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
  319. * out of the containing `Variant` instance with the `extract<T>` method:
  320. *
  321. * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
  322. * auto ptr = v.extract<UniquePtr<A>>();
  323. *
  324. * Finally, you can exhaustively match on the contained variant and branch into
  325. * different code paths depending which type is contained. This is preferred to
  326. * manually checking every variant type T with is<T>() because it provides
  327. * compile-time checking that you handled every type, rather than runtime
  328. * assertion failures.
  329. *
  330. * // Bad!
  331. * char* foo(Variant<A, B, C, D>& v) {
  332. * if (v.is<A>()) {
  333. * return ...;
  334. * } else if (v.is<B>()) {
  335. * return ...;
  336. * } else {
  337. * return doSomething(v.as<C>()); // Forgot about case D!
  338. * }
  339. * }
  340. *
  341. * // Good!
  342. * struct FooMatcher
  343. * {
  344. * // The return type of all matchers must be identical.
  345. * char* match(A& a) { ... }
  346. * char* match(B& b) { ... }
  347. * char* match(C& c) { ... }
  348. * char* match(D& d) { ... } // Compile-time error to forget D!
  349. * }
  350. * char* foo(Variant<A, B, C, D>& v) {
  351. * return v.match(FooMatcher());
  352. * }
  353. *
  354. * ## Examples
  355. *
  356. * A tree is either an empty leaf, or a node with a value and two children:
  357. *
  358. * struct Leaf { };
  359. *
  360. * template<typename T>
  361. * struct Node
  362. * {
  363. * T value;
  364. * Tree<T>* left;
  365. * Tree<T>* right;
  366. * };
  367. *
  368. * template<typename T>
  369. * using Tree = Variant<Leaf, Node<T>>;
  370. *
  371. * A copy-on-write string is either a non-owning reference to some existing
  372. * string, or an owning reference to our copy:
  373. *
  374. * class CopyOnWriteString
  375. * {
  376. * Variant<const char*, UniquePtr<char[]>> string;
  377. *
  378. * ...
  379. * };
  380. */
  381. template<typename... Ts>
  382. class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant
  383. {
  384. using Tag = typename detail::VariantTag<Ts...>::Type;
  385. using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
  386. using RawData = AlignedStorage<detail::MaxSizeOf<Ts...>::size>;
  387. // Raw storage for the contained variant value.
  388. RawData raw;
  389. // Each type is given a unique tag value that lets us keep track of the
  390. // contained variant value's type.
  391. Tag tag;
  392. void* ptr() {
  393. return reinterpret_cast<void*>(&raw);
  394. }
  395. public:
  396. /** Perfect forwarding construction for some variant type T. */
  397. template<typename RefT,
  398. // RefT captures both const& as well as && (as intended, to support
  399. // perfect forwarding), so we have to remove those qualifiers here
  400. // when ensuring that T is a variant of this type, and getting T's
  401. // tag, etc.
  402. typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
  403. explicit Variant(RefT&& aT)
  404. : tag(Impl::template tag<T>())
  405. {
  406. new (ptr()) T(Forward<RefT>(aT));
  407. }
  408. /**
  409. * Constructs this Variant from an AsVariantTemporary<T> such that T can be
  410. * stored in one of the types allowable in this Variant. This is used in the
  411. * implementation of AsVariant().
  412. */
  413. template<typename RefT,
  414. typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
  415. MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
  416. : tag(Impl::template tag<T>())
  417. {
  418. new (ptr()) T(Move(aValue.mValue));
  419. }
  420. /** Copy construction. */
  421. Variant(const Variant& aRhs)
  422. : tag(aRhs.tag)
  423. {
  424. Impl::copyConstruct(ptr(), aRhs);
  425. }
  426. /** Move construction. */
  427. Variant(Variant&& aRhs)
  428. : tag(aRhs.tag)
  429. {
  430. Impl::moveConstruct(ptr(), Move(aRhs));
  431. }
  432. /** Copy assignment. */
  433. Variant& operator=(const Variant& aRhs) {
  434. MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
  435. this->~Variant();
  436. new (this) Variant(aRhs);
  437. return *this;
  438. }
  439. /** Move assignment. */
  440. Variant& operator=(Variant&& aRhs) {
  441. MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
  442. this->~Variant();
  443. new (this) Variant(Move(aRhs));
  444. return *this;
  445. }
  446. /** Move assignment from AsVariant(). */
  447. template <typename T>
  448. Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
  449. {
  450. this->~Variant();
  451. new (this) Variant(Move(aValue));
  452. return *this;
  453. }
  454. ~Variant()
  455. {
  456. Impl::destroy(*this);
  457. }
  458. /** Check which variant type is currently contained. */
  459. template<typename T>
  460. bool is() const {
  461. static_assert(detail::IsVariant<T, Ts...>::value,
  462. "provided a type not found in this Variant's type list");
  463. return Impl::template tag<T>() == tag;
  464. }
  465. /**
  466. * Operator == overload that defers to the variant type's operator==
  467. * implementation if the rhs is tagged as the same type as this one.
  468. */
  469. bool operator==(const Variant& aRhs) const {
  470. return tag == aRhs.tag && Impl::equal(*this, aRhs);
  471. }
  472. /**
  473. * Operator != overload that defers to the negation of the variant type's
  474. * operator== implementation if the rhs is tagged as the same type as this
  475. * one.
  476. */
  477. bool operator!=(const Variant& aRhs) const {
  478. return !(*this == aRhs);
  479. }
  480. // Accessors for working with the contained variant value.
  481. /** Mutable reference. */
  482. template<typename T>
  483. T& as() {
  484. static_assert(detail::IsVariant<T, Ts...>::value,
  485. "provided a type not found in this Variant's type list");
  486. MOZ_ASSERT(is<T>());
  487. return *reinterpret_cast<T*>(&raw);
  488. }
  489. /** Immutable const reference. */
  490. template<typename T>
  491. const T& as() const {
  492. static_assert(detail::IsVariant<T, Ts...>::value,
  493. "provided a type not found in this Variant's type list");
  494. MOZ_ASSERT(is<T>());
  495. return *reinterpret_cast<const T*>(&raw);
  496. }
  497. /**
  498. * Extract the contained variant value from this container into a temporary
  499. * value. On completion, the value in the variant will be in a
  500. * safely-destructible state, as determined by the behavior of T's move
  501. * constructor when provided the variant's internal value.
  502. */
  503. template<typename T>
  504. T extract() {
  505. static_assert(detail::IsVariant<T, Ts...>::value,
  506. "provided a type not found in this Variant's type list");
  507. MOZ_ASSERT(is<T>());
  508. return T(Move(as<T>()));
  509. }
  510. // Exhaustive matching of all variant types on the contained value.
  511. /** Match on an immutable const reference. */
  512. template<typename Matcher>
  513. auto
  514. match(Matcher&& aMatcher) const
  515. -> decltype(Impl::match(aMatcher, *this))
  516. {
  517. return Impl::match(aMatcher, *this);
  518. }
  519. /** Match on a mutable non-const reference. */
  520. template<typename Matcher>
  521. auto
  522. match(Matcher&& aMatcher)
  523. -> decltype(Impl::match(aMatcher, *this))
  524. {
  525. return Impl::match(aMatcher, *this);
  526. }
  527. };
  528. /*
  529. * AsVariant() is used to construct a Variant<T,...> value containing the
  530. * provided T value using type inference. It can be used to construct Variant
  531. * values in expressions or return them from functions without specifying the
  532. * entire Variant type.
  533. *
  534. * Because AsVariant() must copy or move the value into a temporary and this
  535. * cannot necessarily be elided by the compiler, it's mostly appropriate only
  536. * for use with primitive or very small types.
  537. *
  538. * AsVariant() returns a AsVariantTemporary value which is implicitly
  539. * convertible to any Variant that can hold a value of type T.
  540. */
  541. template<typename T>
  542. detail::AsVariantTemporary<T>
  543. AsVariant(T&& aValue)
  544. {
  545. return detail::AsVariantTemporary<T>(Forward<T>(aValue));
  546. }
  547. } // namespace mozilla
  548. #endif /* mozilla_Variant_h */