Bug 1581944 [wpt PR 19124] - cleanup WPT css-transitions timing-function parsing...
[gecko.git] / mfbt / Tuple.h
blobf45471c11a330866dd4d4d94b7acfd20cd23fabd
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/. */
7 /* A variadic tuple class. */
9 #ifndef mozilla_Tuple_h
10 #define mozilla_Tuple_h
12 #include "mozilla/Move.h"
13 #include "mozilla/Pair.h"
14 #include "mozilla/TemplateLib.h"
15 #include "mozilla/TypeTraits.h"
17 #include <stddef.h>
18 #include <utility>
20 namespace mozilla {
22 namespace detail {
25 * A helper class that allows passing around multiple variadic argument lists
26 * by grouping them.
28 template <typename... Ts>
29 struct Group;
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.
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).
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).
47 template <typename Source, typename Target, bool SameSize>
48 struct CheckConvertibilityImpl;
50 template <typename Source, typename Target>
51 struct CheckConvertibilityImpl<Source, Target, false> : FalseType {};
53 template <typename... SourceTypes, typename... TargetTypes>
54 struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
55 true>
56 : IntegralConstant<
57 bool,
58 tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> {};
60 template <typename Source, typename Target>
61 struct CheckConvertibility;
63 template <typename... SourceTypes, typename... TargetTypes>
64 struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
65 : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
66 sizeof...(SourceTypes) ==
67 sizeof...(TargetTypes)> {};
70 * TupleImpl is a helper class used to implement mozilla::Tuple.
71 * It represents one node in a recursive inheritance hierarchy.
72 * 'Index' is the 0-based index of the tuple element stored in this node;
73 * 'Elements...' are the types of the elements stored in this node and its
74 * base classes.
76 * Example:
77 * Tuple<int, float, char> inherits from
78 * TupleImpl<0, int, float, char>, which stores the 'int' and inherits from
79 * TupleImpl<1, float, char>, which stores the 'float' and inherits from
80 * TupleImpl<2, char>, which stores the 'char' and inherits from
81 * TupleImpl<3>, which stores nothing and terminates the recursion.
83 * The purpose of the 'Index' parameter is to allow efficient index-based
84 * access to a tuple element: given a tuple, and an index 'I' that we wish to
85 * access, we can cast the tuple to the base which stores the I'th element
86 * by performing template argument deduction against 'TupleImpl<I, E...>',
87 * where 'I' is specified explicitly and 'E...' is deduced (this is what the
88 * non-member 'Get<N>(t)' function does).
90 * This implementation strategy is borrowed from libstdc++'s std::tuple
91 * implementation.
93 template <std::size_t Index, typename... Elements>
94 struct TupleImpl;
97 * The base case of the inheritance recursion (and also the implementation
98 * of an empty tuple).
100 template <std::size_t Index>
101 struct TupleImpl<Index> {
102 bool operator==(const TupleImpl<Index>& aOther) const { return true; }
104 template <typename F>
105 void ForEach(const F& aFunc) {}
109 * One node of the recursive inheritance hierarchy. It stores the element at
110 * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
111 * that store the remaining elements, of types 'TailT...'.
113 template <std::size_t Index, typename HeadT, typename... TailT>
114 struct TupleImpl<Index, HeadT, TailT...>
115 : public TupleImpl<Index + 1, TailT...> {
116 typedef TupleImpl<Index + 1, TailT...> Base;
118 // Accessors for the head and the tail.
119 // These are static, because the intended usage is for the caller to,
120 // given a tuple, obtain the type B of the base class which stores the
121 // element of interest, and then call B::Head(tuple) to access it.
122 // (Tail() is mostly for internal use, but is exposed for consistency.)
123 static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
124 static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
125 static Base& Tail(TupleImpl& aTuple) { return aTuple; }
126 static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
128 TupleImpl() : Base(), mHead() {}
130 // Construct from const references to the elements.
131 explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
132 : Base(aTail...), mHead(aHead) {}
134 // Construct from objects that are convertible to the elements.
135 // This constructor is enabled only when the argument types are actually
136 // convertible to the element types, otherwise it could become a better
137 // match for certain invocations than the copy constructor.
138 template <typename OtherHeadT, typename... OtherTailT,
139 typename = typename EnableIf<
140 CheckConvertibility<Group<OtherHeadT, OtherTailT...>,
141 Group<HeadT, TailT...>>::value>::Type>
142 explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
143 : Base(std::forward<OtherTailT>(aTail)...),
144 mHead(std::forward<OtherHeadT>(aHead)) {}
146 // Copy and move constructors.
147 // We'd like to use '= default' to implement these, but MSVC 2013's support
148 // for '= default' is incomplete and this doesn't work.
149 TupleImpl(const TupleImpl& aOther)
150 : Base(Tail(aOther)), mHead(Head(aOther)) {}
151 TupleImpl(TupleImpl&& aOther)
152 : Base(std::move(Tail(aOther))),
153 mHead(std::forward<HeadT>(Head(aOther))) {}
155 // Assign from a tuple whose elements are convertible to the elements
156 // of this tuple.
157 template <typename... OtherElements,
158 typename = typename EnableIf<sizeof...(OtherElements) ==
159 sizeof...(TailT) + 1>::Type>
160 TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther) {
161 typedef TupleImpl<Index, OtherElements...> OtherT;
162 Head(*this) = OtherT::Head(aOther);
163 Tail(*this) = OtherT::Tail(aOther);
164 return *this;
166 template <typename... OtherElements,
167 typename = typename EnableIf<sizeof...(OtherElements) ==
168 sizeof...(TailT) + 1>::Type>
169 TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther) {
170 typedef TupleImpl<Index, OtherElements...> OtherT;
171 Head(*this) = std::move(OtherT::Head(aOther));
172 Tail(*this) = std::move(OtherT::Tail(aOther));
173 return *this;
176 // Copy and move assignment operators.
177 TupleImpl& operator=(const TupleImpl& aOther) {
178 Head(*this) = Head(aOther);
179 Tail(*this) = Tail(aOther);
180 return *this;
182 TupleImpl& operator=(TupleImpl&& aOther) {
183 Head(*this) = std::move(Head(aOther));
184 Tail(*this) = std::move(Tail(aOther));
185 return *this;
187 bool operator==(const TupleImpl& aOther) const {
188 return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
191 template <typename F>
192 void ForEach(const F& aFunc) const& {
193 aFunc(Head(*this));
194 Tail(*this).ForEach(aFunc);
197 template <typename F>
198 void ForEach(const F& aFunc) & {
199 aFunc(Head(*this));
200 Tail(*this).ForEach(aFunc);
203 template <typename F>
204 void ForEach(const F& aFunc) && {
205 aFunc(std::move(Head(*this)));
206 std::move(Tail(*this)).ForEach(aFunc);
209 private:
210 HeadT mHead; // The element stored at this index in the tuple.
213 } // namespace detail
216 * Tuple is a class that stores zero or more objects, whose types are specified
217 * as template parameters. It can be thought of as a generalization of Pair,
218 * (which can be thought of as a 2-tuple).
220 * Tuple allows index-based access to its elements (with the index having to be
221 * known at compile time) via the non-member function 'Get<N>(tuple)'.
223 template <typename... Elements>
224 class Tuple : public detail::TupleImpl<0, Elements...> {
225 typedef detail::TupleImpl<0, Elements...> Impl;
227 public:
228 // The constructors and assignment operators here are simple wrappers
229 // around those in TupleImpl.
231 Tuple() : Impl() {}
232 explicit Tuple(const Elements&... aElements) : Impl(aElements...) {}
233 // Here, we can't just use 'typename... OtherElements' because MSVC will give
234 // a warning "C4520: multiple default constructors specified" (even if no one
235 // actually instantiates the constructor with an empty parameter pack -
236 // that's probably a bug) and we compile with warnings-as-errors.
237 template <typename OtherHead, typename... OtherTail,
238 typename = typename EnableIf<detail::CheckConvertibility<
239 detail::Group<OtherHead, OtherTail...>,
240 detail::Group<Elements...>>::value>::Type>
241 explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
242 : Impl(std::forward<OtherHead>(aHead),
243 std::forward<OtherTail>(aTail)...) {}
244 Tuple(const Tuple& aOther) : Impl(aOther) {}
245 Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
247 template <typename... OtherElements,
248 typename = typename EnableIf<sizeof...(OtherElements) ==
249 sizeof...(Elements)>::Type>
250 Tuple& operator=(const Tuple<OtherElements...>& aOther) {
251 static_cast<Impl&>(*this) = aOther;
252 return *this;
254 template <typename... OtherElements,
255 typename = typename EnableIf<sizeof...(OtherElements) ==
256 sizeof...(Elements)>::Type>
257 Tuple& operator=(Tuple<OtherElements...>&& aOther) {
258 static_cast<Impl&>(*this) = std::move(aOther);
259 return *this;
261 Tuple& operator=(const Tuple& aOther) {
262 static_cast<Impl&>(*this) = aOther;
263 return *this;
265 Tuple& operator=(Tuple&& aOther) {
266 static_cast<Impl&>(*this) = std::move(aOther);
267 return *this;
269 bool operator==(const Tuple& aOther) const {
270 return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
275 * Specialization of Tuple for two elements.
276 * This is created to support construction and assignment from a Pair or
277 * std::pair.
279 template <typename A, typename B>
280 class Tuple<A, B> : public detail::TupleImpl<0, A, B> {
281 typedef detail::TupleImpl<0, A, B> Impl;
283 public:
284 // The constructors and assignment operators here are simple wrappers
285 // around those in TupleImpl.
287 Tuple() : Impl() {}
288 explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) {}
289 template <typename AArg, typename BArg,
290 typename = typename EnableIf<detail::CheckConvertibility<
291 detail::Group<AArg, BArg>, detail::Group<A, B>>::value>::Type>
292 explicit Tuple(AArg&& aA, BArg&& aB)
293 : Impl(std::forward<AArg>(aA), std::forward<BArg>(aB)) {}
294 Tuple(const Tuple& aOther) : Impl(aOther) {}
295 Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
296 explicit Tuple(const Pair<A, B>& aOther)
297 : Impl(aOther.first(), aOther.second()) {}
298 explicit Tuple(Pair<A, B>&& aOther)
299 : Impl(std::forward<A>(aOther.first()),
300 std::forward<B>(aOther.second())) {}
301 explicit Tuple(const std::pair<A, B>& aOther)
302 : Impl(aOther.first, aOther.second) {}
303 explicit Tuple(std::pair<A, B>&& aOther)
304 : Impl(std::forward<A>(aOther.first), std::forward<B>(aOther.second)) {}
306 template <typename AArg, typename BArg>
307 Tuple& operator=(const Tuple<AArg, BArg>& aOther) {
308 static_cast<Impl&>(*this) = aOther;
309 return *this;
311 template <typename AArg, typename BArg>
312 Tuple& operator=(Tuple<AArg, BArg>&& aOther) {
313 static_cast<Impl&>(*this) = std::move(aOther);
314 return *this;
316 Tuple& operator=(const Tuple& aOther) {
317 static_cast<Impl&>(*this) = aOther;
318 return *this;
320 Tuple& operator=(Tuple&& aOther) {
321 static_cast<Impl&>(*this) = std::move(aOther);
322 return *this;
324 template <typename AArg, typename BArg>
325 Tuple& operator=(const Pair<AArg, BArg>& aOther) {
326 Impl::Head(*this) = aOther.first();
327 Impl::Tail(*this).Head(*this) = aOther.second();
328 return *this;
330 template <typename AArg, typename BArg>
331 Tuple& operator=(Pair<AArg, BArg>&& aOther) {
332 Impl::Head(*this) = std::forward<AArg>(aOther.first());
333 Impl::Tail(*this).Head(*this) = std::forward<BArg>(aOther.second());
334 return *this;
336 template <typename AArg, typename BArg>
337 Tuple& operator=(const std::pair<AArg, BArg>& aOther) {
338 Impl::Head(*this) = aOther.first;
339 Impl::Tail(*this).Head(*this) = aOther.second;
340 return *this;
342 template <typename AArg, typename BArg>
343 Tuple& operator=(std::pair<AArg, BArg>&& aOther) {
344 Impl::Head(*this) = std::forward<AArg>(aOther.first);
345 Impl::Tail(*this).Head(*this) = std::forward<BArg>(aOther.second);
346 return *this;
351 * Specialization of Tuple for zero arguments.
352 * This is necessary because if the primary template were instantiated with
353 * an empty parameter pack, the 'Tuple(Elements...)' constructors would
354 * become illegal overloads of the default constructor.
356 template <>
357 class Tuple<> {};
359 namespace detail {
362 * Helper functions for implementing Get<N>(tuple).
363 * These functions take a TupleImpl<Index, Elements...>, with Index being
364 * explicitly specified, and Elements being deduced. By passing a Tuple
365 * object as argument, template argument deduction will do its magic and
366 * cast the tuple to the base class which stores the element at Index.
369 // Const reference version.
370 template <std::size_t Index, typename... Elements>
371 auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
372 -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) {
373 return TupleImpl<Index, Elements...>::Head(aTuple);
376 // Non-const reference version.
377 template <std::size_t Index, typename... Elements>
378 auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
379 -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) {
380 return TupleImpl<Index, Elements...>::Head(aTuple);
383 } // namespace detail
386 * Index-based access to an element of a tuple.
387 * The syntax is Get<Index>(tuple). The index is zero-based.
389 * Example:
391 * Tuple<int, float, char> t;
392 * ...
393 * float f = Get<1>(t);
396 // Non-const reference version.
397 template <std::size_t Index, typename... Elements>
398 auto Get(Tuple<Elements...>& aTuple)
399 -> decltype(detail::TupleGetHelper<Index>(aTuple)) {
400 return detail::TupleGetHelper<Index>(aTuple);
403 // Const reference version.
404 template <std::size_t Index, typename... Elements>
405 auto Get(const Tuple<Elements...>& aTuple)
406 -> decltype(detail::TupleGetHelper<Index>(aTuple)) {
407 return detail::TupleGetHelper<Index>(aTuple);
410 // Rvalue reference version.
411 template <std::size_t Index, typename... Elements>
412 auto Get(Tuple<Elements...>&& aTuple)
413 -> decltype(std::move(mozilla::Get<Index>(aTuple))) {
414 // We need a 'mozilla::' qualification here to avoid
415 // name lookup only finding the current function.
416 return std::move(mozilla::Get<Index>(aTuple));
420 * Helpers which call a function for each member of the tuple in turn. This will
421 * typically be used with a lambda function with an `auto&` argument:
423 * Tuple<Foo*, Bar*, SmartPtr<Baz>> tuple{a, b, c};
425 * ForEach(tuple, [](auto& aElem) {
426 * aElem = nullptr;
427 * });
430 template <typename F>
431 inline void ForEach(const Tuple<>& aTuple, const F& aFunc) {}
433 template <typename F>
434 inline void ForEach(Tuple<>& aTuple, const F& aFunc) {}
436 template <typename F, typename... Elements>
437 void ForEach(const Tuple<Elements...>& aTuple, const F& aFunc) {
438 aTuple.ForEach(aTuple, aFunc);
441 template <typename F, typename... Elements>
442 void ForEach(Tuple<Elements...>& aTuple, const F& aFunc) {
443 aTuple.ForEach(aFunc);
446 template <typename F, typename... Elements>
447 void ForEach(Tuple<Elements...>&& aTuple, const F& aFunc) {
448 std::forward<Tuple<Elements...>>(aTuple).ForEach(aFunc);
452 * A convenience function for constructing a tuple out of a sequence of
453 * values without specifying the type of the tuple.
454 * The type of the tuple is deduced from the types of its elements.
456 * Example:
458 * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
460 template <typename... Elements>
461 inline Tuple<typename Decay<Elements>::Type...> MakeTuple(
462 Elements&&... aElements) {
463 return Tuple<typename Decay<Elements>::Type...>(
464 std::forward<Elements>(aElements)...);
468 * A convenience function for constructing a tuple of references to a
469 * sequence of variables. Since assignments to the elements of the tuple
470 * "go through" to the referenced variables, this can be used to "unpack"
471 * a tuple into individual variables.
473 * Example:
475 * int i;
476 * float f;
477 * char c;
478 * Tie(i, f, c) = FunctionThatReturnsATuple();
480 template <typename... Elements>
481 inline Tuple<Elements&...> Tie(Elements&... aVariables) {
482 return Tuple<Elements&...>(aVariables...);
485 } // namespace mozilla
487 #endif /* mozilla_Tuple_h */