Tuple.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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 variadic tuple class. */
  6. #ifndef mozilla_Tuple_h
  7. #define mozilla_Tuple_h
  8. #include "mozilla/Move.h"
  9. #include "mozilla/Pair.h"
  10. #include "mozilla/TemplateLib.h"
  11. #include "mozilla/TypeTraits.h"
  12. #include <stddef.h>
  13. #include <utility>
  14. namespace mozilla {
  15. namespace detail {
  16. /*
  17. * A helper class that allows passing around multiple variadic argument lists
  18. * by grouping them.
  19. */
  20. template<typename... Ts>
  21. struct Group;
  22. /*
  23. * CheckConvertibility checks whether each type in a source pack of types
  24. * is convertible to the corresponding type in a target pack of types.
  25. *
  26. * It is intended to be invoked like this:
  27. * CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
  28. * 'Group' is used to separate types in the two packs (otherwise if we just
  29. * wrote 'CheckConvertibility<SourceTypes..., TargetTypes...', it couldn't
  30. * know where the first pack ends and the second begins).
  31. *
  32. * Note that we need to check explicitly that the two packs are of the same
  33. * size, because attempting to simultaneously expand two parameter packs
  34. * is an error (and it would be a hard error, because it wouldn't be in the
  35. * immediate context of the caller).
  36. */
  37. template<typename Source, typename Target, bool SameSize>
  38. struct CheckConvertibilityImpl;
  39. template<typename Source, typename Target>
  40. struct CheckConvertibilityImpl<Source, Target, false>
  41. : FalseType {};
  42. template<typename... SourceTypes, typename... TargetTypes>
  43. struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, true>
  44. : IntegralConstant<bool, tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> { };
  45. template<typename Source, typename Target>
  46. struct CheckConvertibility;
  47. template<typename... SourceTypes, typename... TargetTypes>
  48. struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
  49. : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
  50. sizeof...(SourceTypes) == sizeof...(TargetTypes)> { };
  51. /*
  52. * TupleImpl is a helper class used to implement mozilla::Tuple.
  53. * It represents one node in a recursive inheritance hierarchy.
  54. * 'Index' is the 0-based index of the tuple element stored in this node;
  55. * 'Elements...' are the types of the elements stored in this node and its
  56. * base classes.
  57. *
  58. * Example:
  59. * Tuple<int, float, char> inherits from
  60. * TupleImpl<0, int, float, char>, which stores the 'int' and inherits from
  61. * TupleImpl<1, float, char>, which stores the 'float' and inherits from
  62. * TupleImpl<2, char>, which stores the 'char' and inherits from
  63. * TupleImpl<3>, which stores nothing and terminates the recursion.
  64. *
  65. * The purpose of the 'Index' parameter is to allow efficient index-based
  66. * access to a tuple element: given a tuple, and an index 'I' that we wish to
  67. * access, we can cast the tuple to the base which stores the I'th element
  68. * by performing template argument deduction against 'TupleImpl<I, E...>',
  69. * where 'I' is specified explicitly and 'E...' is deduced (this is what the
  70. * non-member 'Get<N>(t)' function does).
  71. *
  72. * This implementation strategy is borrowed from libstdc++'s std::tuple
  73. * implementation.
  74. */
  75. template<std::size_t Index, typename... Elements>
  76. struct TupleImpl;
  77. /*
  78. * The base case of the inheritance recursion (and also the implementation
  79. * of an empty tuple).
  80. */
  81. template<std::size_t Index>
  82. struct TupleImpl<Index> {
  83. bool operator==(const TupleImpl<Index>& aOther) const
  84. {
  85. return true;
  86. }
  87. };
  88. /*
  89. * One node of the recursive inheritance hierarchy. It stores the element at
  90. * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
  91. * that store the remaining elements, of types 'TailT...'.
  92. */
  93. template<std::size_t Index, typename HeadT, typename... TailT>
  94. struct TupleImpl<Index, HeadT, TailT...>
  95. : public TupleImpl<Index + 1, TailT...>
  96. {
  97. typedef TupleImpl<Index + 1, TailT...> Base;
  98. // Accessors for the head and the tail.
  99. // These are static, because the intended usage is for the caller to,
  100. // given a tuple, obtain the type B of the base class which stores the
  101. // element of interest, and then call B::Head(tuple) to access it.
  102. // (Tail() is mostly for internal use, but is exposed for consistency.)
  103. static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
  104. static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
  105. static Base& Tail(TupleImpl& aTuple) { return aTuple; }
  106. static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
  107. TupleImpl() : Base(), mHead() { }
  108. // Construct from const references to the elements.
  109. explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
  110. : Base(aTail...), mHead(aHead) { }
  111. // Construct from objects that are convertible to the elements.
  112. // This constructor is enabled only when the argument types are actually
  113. // convertible to the element types, otherwise it could become a better
  114. // match for certain invocations than the copy constructor.
  115. template <typename OtherHeadT, typename... OtherTailT,
  116. typename = typename EnableIf<
  117. CheckConvertibility<
  118. Group<OtherHeadT, OtherTailT...>,
  119. Group<HeadT, TailT...>>::value>::Type>
  120. explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
  121. : Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { }
  122. // Copy and move constructors.
  123. // We'd like to use '= default' to implement these, but MSVC 2013's support
  124. // for '= default' is incomplete and this doesn't work.
  125. TupleImpl(const TupleImpl& aOther)
  126. : Base(Tail(aOther))
  127. , mHead(Head(aOther)) {}
  128. TupleImpl(TupleImpl&& aOther)
  129. : Base(Move(Tail(aOther)))
  130. , mHead(Forward<HeadT>(Head(aOther))) {}
  131. // Assign from a tuple whose elements are convertible to the elements
  132. // of this tuple.
  133. template <typename... OtherElements,
  134. typename = typename EnableIf<
  135. sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
  136. TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther)
  137. {
  138. typedef TupleImpl<Index, OtherElements...> OtherT;
  139. Head(*this) = OtherT::Head(aOther);
  140. Tail(*this) = OtherT::Tail(aOther);
  141. return *this;
  142. }
  143. template <typename... OtherElements,
  144. typename = typename EnableIf<
  145. sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
  146. TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther)
  147. {
  148. typedef TupleImpl<Index, OtherElements...> OtherT;
  149. Head(*this) = Move(OtherT::Head(aOther));
  150. Tail(*this) = Move(OtherT::Tail(aOther));
  151. return *this;
  152. }
  153. // Copy and move assignment operators.
  154. TupleImpl& operator=(const TupleImpl& aOther)
  155. {
  156. Head(*this) = Head(aOther);
  157. Tail(*this) = Tail(aOther);
  158. return *this;
  159. }
  160. TupleImpl& operator=(TupleImpl&& aOther)
  161. {
  162. Head(*this) = Move(Head(aOther));
  163. Tail(*this) = Move(Tail(aOther));
  164. return *this;
  165. }
  166. bool operator==(const TupleImpl& aOther) const
  167. {
  168. return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
  169. }
  170. private:
  171. HeadT mHead; // The element stored at this index in the tuple.
  172. };
  173. } // namespace detail
  174. /**
  175. * Tuple is a class that stores zero or more objects, whose types are specified
  176. * as template parameters. It can be thought of as a generalization of Pair,
  177. * (which can be thought of as a 2-tuple).
  178. *
  179. * Tuple allows index-based access to its elements (with the index having to be
  180. * known at compile time) via the non-member function 'Get<N>(tuple)'.
  181. */
  182. template<typename... Elements>
  183. class Tuple : public detail::TupleImpl<0, Elements...>
  184. {
  185. typedef detail::TupleImpl<0, Elements...> Impl;
  186. public:
  187. // The constructors and assignment operators here are simple wrappers
  188. // around those in TupleImpl.
  189. Tuple() : Impl() { }
  190. explicit Tuple(const Elements&... aElements) : Impl(aElements...) { }
  191. // Here, we can't just use 'typename... OtherElements' because MSVC will give
  192. // a warning "C4520: multiple default constructors specified" (even if no one
  193. // actually instantiates the constructor with an empty parameter pack -
  194. // that's probably a bug) and we compile with warnings-as-errors.
  195. template <typename OtherHead, typename... OtherTail,
  196. typename = typename EnableIf<
  197. detail::CheckConvertibility<
  198. detail::Group<OtherHead, OtherTail...>,
  199. detail::Group<Elements...>>::value>::Type>
  200. explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
  201. : Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { }
  202. Tuple(const Tuple& aOther) : Impl(aOther) { }
  203. Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
  204. template <typename... OtherElements,
  205. typename = typename EnableIf<
  206. sizeof...(OtherElements) == sizeof...(Elements)>::Type>
  207. Tuple& operator=(const Tuple<OtherElements...>& aOther)
  208. {
  209. static_cast<Impl&>(*this) = aOther;
  210. return *this;
  211. }
  212. template <typename... OtherElements,
  213. typename = typename EnableIf<
  214. sizeof...(OtherElements) == sizeof...(Elements)>::Type>
  215. Tuple& operator=(Tuple<OtherElements...>&& aOther)
  216. {
  217. static_cast<Impl&>(*this) = Move(aOther);
  218. return *this;
  219. }
  220. Tuple& operator=(const Tuple& aOther)
  221. {
  222. static_cast<Impl&>(*this) = aOther;
  223. return *this;
  224. }
  225. Tuple& operator=(Tuple&& aOther)
  226. {
  227. static_cast<Impl&>(*this) = Move(aOther);
  228. return *this;
  229. }
  230. bool operator==(const Tuple& aOther) const
  231. {
  232. return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
  233. }
  234. };
  235. /**
  236. * Specialization of Tuple for two elements.
  237. * This is created to support construction and assignment from a Pair or std::pair.
  238. */
  239. template <typename A, typename B>
  240. class Tuple<A, B> : public detail::TupleImpl<0, A, B>
  241. {
  242. typedef detail::TupleImpl<0, A, B> Impl;
  243. public:
  244. // The constructors and assignment operators here are simple wrappers
  245. // around those in TupleImpl.
  246. Tuple() : Impl() { }
  247. explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { }
  248. template <typename AArg, typename BArg,
  249. typename = typename EnableIf<
  250. detail::CheckConvertibility<
  251. detail::Group<AArg, BArg>,
  252. detail::Group<A, B>>::value>::Type>
  253. explicit Tuple(AArg&& aA, BArg&& aB)
  254. : Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { }
  255. Tuple(const Tuple& aOther) : Impl(aOther) { }
  256. Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
  257. explicit Tuple(const Pair<A, B>& aOther)
  258. : Impl(aOther.first(), aOther.second()) { }
  259. explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()),
  260. Forward<B>(aOther.second())) { }
  261. explicit Tuple(const std::pair<A, B>& aOther)
  262. : Impl(aOther.first, aOther.second) { }
  263. explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first),
  264. Forward<B>(aOther.second)) { }
  265. template <typename AArg, typename BArg>
  266. Tuple& operator=(const Tuple<AArg, BArg>& aOther)
  267. {
  268. static_cast<Impl&>(*this) = aOther;
  269. return *this;
  270. }
  271. template <typename AArg, typename BArg>
  272. Tuple& operator=(Tuple<AArg, BArg>&& aOther)
  273. {
  274. static_cast<Impl&>(*this) = Move(aOther);
  275. return *this;
  276. }
  277. Tuple& operator=(const Tuple& aOther)
  278. {
  279. static_cast<Impl&>(*this) = aOther;
  280. return *this;
  281. }
  282. Tuple& operator=(Tuple&& aOther)
  283. {
  284. static_cast<Impl&>(*this) = Move(aOther);
  285. return *this;
  286. }
  287. template <typename AArg, typename BArg>
  288. Tuple& operator=(const Pair<AArg, BArg>& aOther)
  289. {
  290. Impl::Head(*this) = aOther.first();
  291. Impl::Tail(*this).Head(*this) = aOther.second();
  292. return *this;
  293. }
  294. template <typename AArg, typename BArg>
  295. Tuple& operator=(Pair<AArg, BArg>&& aOther)
  296. {
  297. Impl::Head(*this) = Forward<AArg>(aOther.first());
  298. Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second());
  299. return *this;
  300. }
  301. template <typename AArg, typename BArg>
  302. Tuple& operator=(const std::pair<AArg, BArg>& aOther)
  303. {
  304. Impl::Head(*this) = aOther.first;
  305. Impl::Tail(*this).Head(*this) = aOther.second;
  306. return *this;
  307. }
  308. template <typename AArg, typename BArg>
  309. Tuple& operator=(std::pair<AArg, BArg>&& aOther)
  310. {
  311. Impl::Head(*this) = Forward<AArg>(aOther.first);
  312. Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second);
  313. return *this;
  314. }
  315. };
  316. /**
  317. * Specialization of Tuple for zero arguments.
  318. * This is necessary because if the primary template were instantiated with
  319. * an empty parameter pack, the 'Tuple(Elements...)' constructors would
  320. * become illegal overloads of the default constructor.
  321. */
  322. template <>
  323. class Tuple<> {};
  324. namespace detail {
  325. /*
  326. * Helper functions for implementing Get<N>(tuple).
  327. * These functions take a TupleImpl<Index, Elements...>, with Index being
  328. * explicitly specified, and Elements being deduced. By passing a Tuple
  329. * object as argument, template argument deduction will do its magic and
  330. * cast the tuple to the base class which stores the element at Index.
  331. */
  332. // Const reference version.
  333. template<std::size_t Index, typename... Elements>
  334. auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
  335. -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
  336. {
  337. return TupleImpl<Index, Elements...>::Head(aTuple);
  338. }
  339. // Non-const reference version.
  340. template<std::size_t Index, typename... Elements>
  341. auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
  342. -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
  343. {
  344. return TupleImpl<Index, Elements...>::Head(aTuple);
  345. }
  346. } // namespace detail
  347. /**
  348. * Index-based access to an element of a tuple.
  349. * The syntax is Get<Index>(tuple). The index is zero-based.
  350. *
  351. * Example:
  352. *
  353. * Tuple<int, float, char> t;
  354. * ...
  355. * float f = Get<1>(t);
  356. */
  357. // Non-const reference version.
  358. template<std::size_t Index, typename... Elements>
  359. auto Get(Tuple<Elements...>& aTuple)
  360. -> decltype(detail::TupleGetHelper<Index>(aTuple))
  361. {
  362. return detail::TupleGetHelper<Index>(aTuple);
  363. }
  364. // Const reference version.
  365. template<std::size_t Index, typename... Elements>
  366. auto Get(const Tuple<Elements...>& aTuple)
  367. -> decltype(detail::TupleGetHelper<Index>(aTuple))
  368. {
  369. return detail::TupleGetHelper<Index>(aTuple);
  370. }
  371. // Rvalue reference version.
  372. template<std::size_t Index, typename... Elements>
  373. auto Get(Tuple<Elements...>&& aTuple)
  374. -> decltype(Move(mozilla::Get<Index>(aTuple)))
  375. {
  376. // We need a 'mozilla::' qualification here to avoid
  377. // name lookup only finding the current function.
  378. return Move(mozilla::Get<Index>(aTuple));
  379. }
  380. /**
  381. * A convenience function for constructing a tuple out of a sequence of
  382. * values without specifying the type of the tuple.
  383. * The type of the tuple is deduced from the types of its elements.
  384. *
  385. * Example:
  386. *
  387. * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
  388. */
  389. template<typename... Elements>
  390. inline Tuple<typename Decay<Elements>::Type...>
  391. MakeTuple(Elements&&... aElements)
  392. {
  393. return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...);
  394. }
  395. /**
  396. * A convenience function for constructing a tuple of references to a
  397. * sequence of variables. Since assignments to the elements of the tuple
  398. * "go through" to the referenced variables, this can be used to "unpack"
  399. * a tuple into individual variables.
  400. *
  401. * Example:
  402. *
  403. * int i;
  404. * float f;
  405. * char c;
  406. * Tie(i, f, c) = FunctionThatReturnsATuple();
  407. */
  408. template<typename... Elements>
  409. inline Tuple<Elements&...>
  410. Tie(Elements&... aVariables)
  411. {
  412. return Tuple<Elements&...>(aVariables...);
  413. }
  414. } // namespace mozilla
  415. #endif /* mozilla_Tuple_h */