Variant.h 18 KB

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