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