Line data Source code
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 0 : bool operator==(const TupleImpl<Index>& aOther) const
100 : {
101 0 : return true;
102 : }
103 : };
104 :
105 : /*
106 : * One node of the recursive inheritance hierarchy. It stores the element at
107 : * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
108 : * that store the remaining elements, of types 'TailT...'.
109 : */
110 : template<std::size_t Index, typename HeadT, typename... TailT>
111 74 : struct TupleImpl<Index, HeadT, TailT...>
112 : : public TupleImpl<Index + 1, TailT...>
113 : {
114 : typedef TupleImpl<Index + 1, TailT...> Base;
115 :
116 : // Accessors for the head and the tail.
117 : // These are static, because the intended usage is for the caller to,
118 : // given a tuple, obtain the type B of the base class which stores the
119 : // element of interest, and then call B::Head(tuple) to access it.
120 : // (Tail() is mostly for internal use, but is exposed for consistency.)
121 3174 : static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
122 0 : static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
123 1905 : static Base& Tail(TupleImpl& aTuple) { return aTuple; }
124 0 : static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
125 :
126 : TupleImpl() : Base(), mHead() { }
127 :
128 : // Construct from const references to the elements.
129 985 : explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
130 985 : : Base(aTail...), mHead(aHead) { }
131 :
132 : // Construct from objects that are convertible to the elements.
133 : // This constructor is enabled only when the argument types are actually
134 : // convertible to the element types, otherwise it could become a better
135 : // match for certain invocations than the copy constructor.
136 : template <typename OtherHeadT, typename... OtherTailT,
137 : typename = typename EnableIf<
138 : CheckConvertibility<
139 : Group<OtherHeadT, OtherTailT...>,
140 : Group<HeadT, TailT...>>::value>::Type>
141 2186 : explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
142 2186 : : Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { }
143 :
144 : // Copy and move constructors.
145 : // We'd like to use '= default' to implement these, but MSVC 2013's support
146 : // for '= default' is incomplete and this doesn't work.
147 0 : TupleImpl(const TupleImpl& aOther)
148 0 : : Base(Tail(aOther))
149 0 : , mHead(Head(aOther)) {}
150 7 : TupleImpl(TupleImpl&& aOther)
151 7 : : Base(Move(Tail(aOther)))
152 7 : , mHead(Forward<HeadT>(Head(aOther))) {}
153 :
154 : // Assign from a tuple whose elements are convertible to the elements
155 : // of this tuple.
156 : template <typename... OtherElements,
157 : typename = typename EnableIf<
158 : sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
159 : TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther)
160 : {
161 : typedef TupleImpl<Index, OtherElements...> OtherT;
162 : Head(*this) = OtherT::Head(aOther);
163 : Tail(*this) = OtherT::Tail(aOther);
164 : return *this;
165 : }
166 : template <typename... OtherElements,
167 : typename = typename EnableIf<
168 : sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
169 937 : TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther)
170 : {
171 : typedef TupleImpl<Index, OtherElements...> OtherT;
172 937 : Head(*this) = Move(OtherT::Head(aOther));
173 937 : Tail(*this) = Move(OtherT::Tail(aOther));
174 937 : return *this;
175 : }
176 :
177 : // Copy and move assignment operators.
178 0 : TupleImpl& operator=(const TupleImpl& aOther)
179 : {
180 0 : Head(*this) = Head(aOther);
181 0 : Tail(*this) = Tail(aOther);
182 0 : return *this;
183 : }
184 : TupleImpl& operator=(TupleImpl&& aOther)
185 : {
186 : Head(*this) = Move(Head(aOther));
187 : Tail(*this) = Move(Tail(aOther));
188 : return *this;
189 : }
190 0 : bool operator==(const TupleImpl& aOther) const
191 : {
192 0 : return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
193 : }
194 : private:
195 : HeadT mHead; // The element stored at this index in the tuple.
196 : };
197 :
198 : } // namespace detail
199 :
200 : /**
201 : * Tuple is a class that stores zero or more objects, whose types are specified
202 : * as template parameters. It can be thought of as a generalization of Pair,
203 : * (which can be thought of as a 2-tuple).
204 : *
205 : * Tuple allows index-based access to its elements (with the index having to be
206 : * known at compile time) via the non-member function 'Get<N>(tuple)'.
207 : */
208 : template<typename... Elements>
209 34 : class Tuple : public detail::TupleImpl<0, Elements...>
210 : {
211 : typedef detail::TupleImpl<0, Elements...> Impl;
212 : public:
213 : // The constructors and assignment operators here are simple wrappers
214 : // around those in TupleImpl.
215 :
216 : Tuple() : Impl() { }
217 182 : explicit Tuple(const Elements&... aElements) : Impl(aElements...) { }
218 : // Here, we can't just use 'typename... OtherElements' because MSVC will give
219 : // a warning "C4520: multiple default constructors specified" (even if no one
220 : // actually instantiates the constructor with an empty parameter pack -
221 : // that's probably a bug) and we compile with warnings-as-errors.
222 : template <typename OtherHead, typename... OtherTail,
223 : typename = typename EnableIf<
224 : detail::CheckConvertibility<
225 : detail::Group<OtherHead, OtherTail...>,
226 : detail::Group<Elements...>>::value>::Type>
227 1371 : explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
228 1371 : : Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { }
229 0 : Tuple(const Tuple& aOther) : Impl(aOther) { }
230 3 : Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
231 :
232 : template <typename... OtherElements,
233 : typename = typename EnableIf<
234 : sizeof...(OtherElements) == sizeof...(Elements)>::Type>
235 : Tuple& operator=(const Tuple<OtherElements...>& aOther)
236 : {
237 : static_cast<Impl&>(*this) = aOther;
238 : return *this;
239 : }
240 : template <typename... OtherElements,
241 : typename = typename EnableIf<
242 : sizeof...(OtherElements) == sizeof...(Elements)>::Type>
243 182 : Tuple& operator=(Tuple<OtherElements...>&& aOther)
244 : {
245 182 : static_cast<Impl&>(*this) = Move(aOther);
246 182 : return *this;
247 : }
248 0 : Tuple& operator=(const Tuple& aOther)
249 : {
250 0 : static_cast<Impl&>(*this) = aOther;
251 0 : return *this;
252 : }
253 : Tuple& operator=(Tuple&& aOther)
254 : {
255 : static_cast<Impl&>(*this) = Move(aOther);
256 : return *this;
257 : }
258 0 : bool operator==(const Tuple& aOther) const
259 : {
260 0 : return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
261 : }
262 : };
263 :
264 : /**
265 : * Specialization of Tuple for two elements.
266 : * This is created to support construction and assignment from a Pair or std::pair.
267 : */
268 : template <typename A, typename B>
269 8 : class Tuple<A, B> : public detail::TupleImpl<0, A, B>
270 : {
271 : typedef detail::TupleImpl<0, A, B> Impl;
272 :
273 : public:
274 : // The constructors and assignment operators here are simple wrappers
275 : // around those in TupleImpl.
276 :
277 : Tuple() : Impl() { }
278 141 : explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { }
279 : template <typename AArg, typename BArg,
280 : typename = typename EnableIf<
281 : detail::CheckConvertibility<
282 : detail::Group<AArg, BArg>,
283 : detail::Group<A, B>>::value>::Type>
284 134 : explicit Tuple(AArg&& aA, BArg&& aB)
285 134 : : Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { }
286 0 : Tuple(const Tuple& aOther) : Impl(aOther) { }
287 2 : Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
288 : explicit Tuple(const Pair<A, B>& aOther)
289 : : Impl(aOther.first(), aOther.second()) { }
290 : explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()),
291 : Forward<B>(aOther.second())) { }
292 : explicit Tuple(const std::pair<A, B>& aOther)
293 : : Impl(aOther.first, aOther.second) { }
294 : explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first),
295 : Forward<B>(aOther.second)) { }
296 :
297 : template <typename AArg, typename BArg>
298 : Tuple& operator=(const Tuple<AArg, BArg>& aOther)
299 : {
300 : static_cast<Impl&>(*this) = aOther;
301 : return *this;
302 : }
303 : template <typename AArg, typename BArg>
304 117 : Tuple& operator=(Tuple<AArg, BArg>&& aOther)
305 : {
306 117 : static_cast<Impl&>(*this) = Move(aOther);
307 117 : return *this;
308 : }
309 : Tuple& operator=(const Tuple& aOther)
310 : {
311 : static_cast<Impl&>(*this) = aOther;
312 : return *this;
313 : }
314 : Tuple& operator=(Tuple&& aOther)
315 : {
316 : static_cast<Impl&>(*this) = Move(aOther);
317 : return *this;
318 : }
319 : template <typename AArg, typename BArg>
320 : Tuple& operator=(const Pair<AArg, BArg>& aOther)
321 : {
322 : Impl::Head(*this) = aOther.first();
323 : Impl::Tail(*this).Head(*this) = aOther.second();
324 : return *this;
325 : }
326 : template <typename AArg, typename BArg>
327 24 : Tuple& operator=(Pair<AArg, BArg>&& aOther)
328 : {
329 24 : Impl::Head(*this) = Forward<AArg>(aOther.first());
330 24 : Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second());
331 24 : return *this;
332 : }
333 : template <typename AArg, typename BArg>
334 : Tuple& operator=(const std::pair<AArg, BArg>& aOther)
335 : {
336 : Impl::Head(*this) = aOther.first;
337 : Impl::Tail(*this).Head(*this) = aOther.second;
338 : return *this;
339 : }
340 : template <typename AArg, typename BArg>
341 : Tuple& operator=(std::pair<AArg, BArg>&& aOther)
342 : {
343 : Impl::Head(*this) = Forward<AArg>(aOther.first);
344 : Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second);
345 : return *this;
346 : }
347 : };
348 :
349 : /**
350 : * Specialization of Tuple for zero arguments.
351 : * This is necessary because if the primary template were instantiated with
352 : * an empty parameter pack, the 'Tuple(Elements...)' constructors would
353 : * become illegal overloads of the default constructor.
354 : */
355 : template <>
356 : class Tuple<> {};
357 :
358 : namespace detail {
359 :
360 : /*
361 : * Helper functions for implementing Get<N>(tuple).
362 : * These functions take a TupleImpl<Index, Elements...>, with Index being
363 : * explicitly specified, and Elements being deduced. By passing a Tuple
364 : * object as argument, template argument deduction will do its magic and
365 : * cast the tuple to the base class which stores the element at Index.
366 : */
367 :
368 : // Const reference version.
369 : template<std::size_t Index, typename... Elements>
370 1245 : auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
371 : -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
372 : {
373 1245 : return TupleImpl<Index, Elements...>::Head(aTuple);
374 : }
375 :
376 : // Non-const reference version.
377 : template<std::size_t Index, typename... Elements>
378 0 : auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
379 : -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
380 : {
381 0 : return TupleImpl<Index, Elements...>::Head(aTuple);
382 : }
383 :
384 : } // namespace detail
385 :
386 : /**
387 : * Index-based access to an element of a tuple.
388 : * The syntax is Get<Index>(tuple). The index is zero-based.
389 : *
390 : * Example:
391 : *
392 : * Tuple<int, float, char> t;
393 : * ...
394 : * float f = Get<1>(t);
395 : */
396 :
397 : // Non-const reference version.
398 : template<std::size_t Index, typename... Elements>
399 1246 : auto Get(Tuple<Elements...>& aTuple)
400 : -> decltype(detail::TupleGetHelper<Index>(aTuple))
401 : {
402 1246 : return detail::TupleGetHelper<Index>(aTuple);
403 : }
404 :
405 : // Const reference version.
406 : template<std::size_t Index, typename... Elements>
407 0 : auto Get(const Tuple<Elements...>& aTuple)
408 : -> decltype(detail::TupleGetHelper<Index>(aTuple))
409 : {
410 0 : return detail::TupleGetHelper<Index>(aTuple);
411 : }
412 :
413 : // Rvalue reference version.
414 : template<std::size_t Index, typename... Elements>
415 : auto Get(Tuple<Elements...>&& aTuple)
416 : -> decltype(Move(mozilla::Get<Index>(aTuple)))
417 : {
418 : // We need a 'mozilla::' qualification here to avoid
419 : // name lookup only finding the current function.
420 : return Move(mozilla::Get<Index>(aTuple));
421 : }
422 :
423 : /**
424 : * A convenience function for constructing a tuple out of a sequence of
425 : * values without specifying the type of the tuple.
426 : * The type of the tuple is deduced from the types of its elements.
427 : *
428 : * Example:
429 : *
430 : * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
431 : */
432 : template<typename... Elements>
433 : inline Tuple<typename Decay<Elements>::Type...>
434 305 : MakeTuple(Elements&&... aElements)
435 : {
436 305 : return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...);
437 : }
438 :
439 : /**
440 : * A convenience function for constructing a tuple of references to a
441 : * sequence of variables. Since assignments to the elements of the tuple
442 : * "go through" to the referenced variables, this can be used to "unpack"
443 : * a tuple into individual variables.
444 : *
445 : * Example:
446 : *
447 : * int i;
448 : * float f;
449 : * char c;
450 : * Tie(i, f, c) = FunctionThatReturnsATuple();
451 : */
452 : template<typename... Elements>
453 : inline Tuple<Elements&...>
454 323 : Tie(Elements&... aVariables)
455 : {
456 323 : return Tuple<Elements&...>(aVariables...);
457 : }
458 :
459 : } // namespace mozilla
460 :
461 : #endif /* mozilla_Tuple_h */
|