Tuple.h 16 KB

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