Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / mfbt / Tuple.h
blob85ff3f314e15d1b1f016b009bd417d8900386e34
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 <stddef.h>
14 #include <type_traits>
15 #include <utility>
17 #include "mozilla/CompactPair.h"
18 #include "mozilla/TemplateLib.h"
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> : std::false_type {};
53 template <typename... SourceTypes, typename... TargetTypes>
54 struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
55 true>
56 : std::integral_constant<
57 bool,
58 tl::And<std::is_convertible_v<SourceTypes, TargetTypes>...>::value> {
61 template <typename Source, typename Target>
62 struct CheckConvertibility;
64 template <typename... SourceTypes, typename... TargetTypes>
65 struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
66 : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
67 sizeof...(SourceTypes) ==
68 sizeof...(TargetTypes)> {};
71 * Helper type for Tie(args...) to allow ignoring specific elements
72 * during Tie unpacking. Supports assignment from any type.
74 * Not for direct usage; instead, use mozilla::Ignore in calls to Tie.
76 struct IgnoreImpl {
77 template <typename T>
78 constexpr const IgnoreImpl& operator=(const T&) const {
79 return *this;
84 * TupleImpl is a helper class used to implement mozilla::Tuple.
85 * It represents one node in a recursive inheritance hierarchy.
86 * 'Index' is the 0-based index of the tuple element stored in this node;
87 * 'Elements...' are the types of the elements stored in this node and its
88 * base classes.
90 * Example:
91 * Tuple<int, float, char> inherits from
92 * TupleImpl<0, int, float, char>, which stores the 'int' and inherits from
93 * TupleImpl<1, float, char>, which stores the 'float' and inherits from
94 * TupleImpl<2, char>, which stores the 'char' and inherits from
95 * TupleImpl<3>, which stores nothing and terminates the recursion.
97 * The purpose of the 'Index' parameter is to allow efficient index-based
98 * access to a tuple element: given a tuple, and an index 'I' that we wish to
99 * access, we can cast the tuple to the base which stores the I'th element
100 * by performing template argument deduction against 'TupleImpl<I, E...>',
101 * where 'I' is specified explicitly and 'E...' is deduced (this is what the
102 * non-member 'Get<N>(t)' function does).
104 * This implementation strategy is borrowed from libstdc++'s std::tuple
105 * implementation.
107 template <std::size_t Index, typename... Elements>
108 struct TupleImpl;
111 * The base case of the inheritance recursion (and also the implementation
112 * of an empty tuple).
114 template <std::size_t Index>
115 struct TupleImpl<Index> {
116 bool operator==(const TupleImpl<Index>& aOther) const { return true; }
118 template <typename F>
119 void ForEach(const F& aFunc) {}
123 * One node of the recursive inheritance hierarchy. It stores the element at
124 * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
125 * that store the remaining elements, of types 'TailT...'.
127 template <std::size_t Index, typename HeadT, typename... TailT>
128 struct TupleImpl<Index, HeadT, TailT...>
129 : public TupleImpl<Index + 1, TailT...> {
130 typedef TupleImpl<Index + 1, TailT...> Base;
132 // Accessors for the head and the tail.
133 // These are static, because the intended usage is for the caller to,
134 // given a tuple, obtain the type B of the base class which stores the
135 // element of interest, and then call B::Head(tuple) to access it.
136 // (Tail() is mostly for internal use, but is exposed for consistency.)
137 static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
138 static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
139 static Base& Tail(TupleImpl& aTuple) { return aTuple; }
140 static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
142 TupleImpl() : Base(), mHead() {}
144 // Construct from const references to the elements.
145 explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
146 : Base(aTail...), mHead(aHead) {}
148 // Construct from objects that are convertible to the elements.
149 // This constructor is enabled only when the argument types are actually
150 // convertible to the element types, otherwise it could become a better
151 // match for certain invocations than the copy constructor.
152 template <
153 typename OtherHeadT, typename... OtherTailT,
154 typename = std::enable_if_t<CheckConvertibility<
155 Group<OtherHeadT, OtherTailT...>, Group<HeadT, TailT...>>::value>>
156 explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
157 : Base(std::forward<OtherTailT>(aTail)...),
158 mHead(std::forward<OtherHeadT>(aHead)) {}
160 // Copy and move constructors.
161 // We'd like to use '= default' to implement these, but MSVC 2013's support
162 // for '= default' is incomplete and this doesn't work.
163 TupleImpl(const TupleImpl& aOther)
164 : Base(Tail(aOther)), mHead(Head(aOther)) {}
165 TupleImpl(TupleImpl&& aOther)
166 : Base(std::move(Tail(aOther))),
167 mHead(std::forward<HeadT>(Head(aOther))) {}
169 // Assign from a tuple whose elements are convertible to the elements
170 // of this tuple.
171 template <typename... OtherElements,
172 typename = std::enable_if_t<sizeof...(OtherElements) ==
173 sizeof...(TailT) + 1>>
174 TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther) {
175 typedef TupleImpl<Index, OtherElements...> OtherT;
176 Head(*this) = OtherT::Head(aOther);
177 Tail(*this) = OtherT::Tail(aOther);
178 return *this;
180 template <typename... OtherElements,
181 typename = std::enable_if_t<sizeof...(OtherElements) ==
182 sizeof...(TailT) + 1>>
183 TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther) {
184 typedef TupleImpl<Index, OtherElements...> OtherT;
185 Head(*this) = std::move(OtherT::Head(aOther));
186 Tail(*this) = std::move(OtherT::Tail(aOther));
187 return *this;
190 // Copy and move assignment operators.
191 TupleImpl& operator=(const TupleImpl& aOther) {
192 Head(*this) = Head(aOther);
193 Tail(*this) = Tail(aOther);
194 return *this;
196 TupleImpl& operator=(TupleImpl&& aOther) {
197 Head(*this) = std::move(Head(aOther));
198 Tail(*this) = std::move(Tail(aOther));
199 return *this;
201 bool operator==(const TupleImpl& aOther) const {
202 return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
205 template <typename F>
206 void ForEach(const F& aFunc) const& {
207 aFunc(Head(*this));
208 Tail(*this).ForEach(aFunc);
211 template <typename F>
212 void ForEach(const F& aFunc) & {
213 aFunc(Head(*this));
214 Tail(*this).ForEach(aFunc);
217 template <typename F>
218 void ForEach(const F& aFunc) && {
219 aFunc(std::move(Head(*this)));
220 std::move(Tail(*this)).ForEach(aFunc);
223 private:
224 HeadT mHead; // The element stored at this index in the tuple.
227 } // namespace detail
230 * Tuple is a class that stores zero or more objects, whose types are specified
231 * as template parameters. It can be thought of as a generalization of
232 * std::pair, (which can be thought of as a 2-tuple).
234 * Tuple allows index-based access to its elements (with the index having to be
235 * known at compile time) via the non-member function 'Get<N>(tuple)'.
237 template <typename... Elements>
238 class Tuple : public detail::TupleImpl<0, Elements...> {
239 typedef detail::TupleImpl<0, Elements...> Impl;
241 public:
242 // The constructors and assignment operators here are simple wrappers
243 // around those in TupleImpl.
245 Tuple() : Impl() {}
246 explicit Tuple(const Elements&... aElements) : Impl(aElements...) {}
247 // Here, we can't just use 'typename... OtherElements' because MSVC will give
248 // a warning "C4520: multiple default constructors specified" (even if no one
249 // actually instantiates the constructor with an empty parameter pack -
250 // that's probably a bug) and we compile with warnings-as-errors.
251 template <typename OtherHead, typename... OtherTail,
252 typename = std::enable_if_t<detail::CheckConvertibility<
253 detail::Group<OtherHead, OtherTail...>,
254 detail::Group<Elements...>>::value>>
255 explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
256 : Impl(std::forward<OtherHead>(aHead),
257 std::forward<OtherTail>(aTail)...) {}
258 Tuple(const Tuple& aOther) : Impl(aOther) {}
259 Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
261 template <typename... OtherElements,
262 typename = std::enable_if_t<sizeof...(OtherElements) ==
263 sizeof...(Elements)>>
264 Tuple& operator=(const Tuple<OtherElements...>& aOther) {
265 static_cast<Impl&>(*this) = aOther;
266 return *this;
268 template <typename... OtherElements,
269 typename = std::enable_if_t<sizeof...(OtherElements) ==
270 sizeof...(Elements)>>
271 Tuple& operator=(Tuple<OtherElements...>&& aOther) {
272 static_cast<Impl&>(*this) = std::move(aOther);
273 return *this;
275 Tuple& operator=(const Tuple& aOther) {
276 static_cast<Impl&>(*this) = aOther;
277 return *this;
279 Tuple& operator=(Tuple&& aOther) {
280 static_cast<Impl&>(*this) = std::move(aOther);
281 return *this;
283 bool operator==(const Tuple& aOther) const {
284 return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
289 * Specialization of Tuple for two elements.
290 * This is created to support construction and assignment from a CompactPair or
291 * std::pair.
293 template <typename A, typename B>
294 class Tuple<A, B> : public detail::TupleImpl<0, A, B> {
295 typedef detail::TupleImpl<0, A, B> Impl;
297 public:
298 // The constructors and assignment operators here are simple wrappers
299 // around those in TupleImpl.
301 Tuple() : Impl() {}
302 explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) {}
303 template <typename AArg, typename BArg,
304 typename = std::enable_if_t<detail::CheckConvertibility<
305 detail::Group<AArg, BArg>, detail::Group<A, B>>::value>>
306 explicit Tuple(AArg&& aA, BArg&& aB)
307 : Impl(std::forward<AArg>(aA), std::forward<BArg>(aB)) {}
308 Tuple(const Tuple& aOther) : Impl(aOther) {}
309 Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
310 explicit Tuple(const CompactPair<A, B>& aOther)
311 : Impl(aOther.first(), aOther.second()) {}
312 explicit Tuple(CompactPair<A, B>&& aOther)
313 : Impl(std::forward<A>(aOther.first()),
314 std::forward<B>(aOther.second())) {}
315 explicit Tuple(const std::pair<A, B>& aOther)
316 : Impl(aOther.first, aOther.second) {}
317 explicit Tuple(std::pair<A, B>&& aOther)
318 : Impl(std::forward<A>(aOther.first), std::forward<B>(aOther.second)) {}
320 template <typename AArg, typename BArg>
321 Tuple& operator=(const Tuple<AArg, BArg>& aOther) {
322 static_cast<Impl&>(*this) = aOther;
323 return *this;
325 template <typename AArg, typename BArg>
326 Tuple& operator=(Tuple<AArg, BArg>&& aOther) {
327 static_cast<Impl&>(*this) = std::move(aOther);
328 return *this;
330 Tuple& operator=(const Tuple& aOther) {
331 static_cast<Impl&>(*this) = aOther;
332 return *this;
334 Tuple& operator=(Tuple&& aOther) {
335 static_cast<Impl&>(*this) = std::move(aOther);
336 return *this;
338 template <typename AArg, typename BArg>
339 Tuple& operator=(const CompactPair<AArg, BArg>& aOther) {
340 Impl::Head(*this) = aOther.first();
341 Impl::Tail(*this).Head(*this) = aOther.second();
342 return *this;
344 template <typename AArg, typename BArg>
345 Tuple& operator=(CompactPair<AArg, BArg>&& aOther) {
346 Impl::Head(*this) = std::forward<AArg>(aOther.first());
347 Impl::Tail(*this).Head(*this) = std::forward<BArg>(aOther.second());
348 return *this;
350 template <typename AArg, typename BArg>
351 Tuple& operator=(const std::pair<AArg, BArg>& aOther) {
352 Impl::Head(*this) = aOther.first;
353 Impl::Tail(*this).Head(*this) = aOther.second;
354 return *this;
356 template <typename AArg, typename BArg>
357 Tuple& operator=(std::pair<AArg, BArg>&& aOther) {
358 Impl::Head(*this) = std::forward<AArg>(aOther.first);
359 Impl::Tail(*this).Head(*this) = std::forward<BArg>(aOther.second);
360 return *this;
365 * Specialization of Tuple for zero arguments.
366 * This is necessary because if the primary template were instantiated with
367 * an empty parameter pack, the 'Tuple(Elements...)' constructors would
368 * become illegal overloads of the default constructor.
370 template <>
371 class Tuple<> {};
373 namespace detail {
376 * Helper functions for implementing Get<N>(tuple).
377 * These functions take a TupleImpl<Index, Elements...>, with Index being
378 * explicitly specified, and Elements being deduced. By passing a Tuple
379 * object as argument, template argument deduction will do its magic and
380 * cast the tuple to the base class which stores the element at Index.
383 // Const reference version.
384 template <std::size_t Index, typename... Elements>
385 auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
386 -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) {
387 return TupleImpl<Index, Elements...>::Head(aTuple);
390 // Non-const reference version.
391 template <std::size_t Index, typename... Elements>
392 auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
393 -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) {
394 return TupleImpl<Index, Elements...>::Head(aTuple);
397 } // namespace detail
400 * Index-based access to an element of a tuple.
401 * The syntax is Get<Index>(tuple). The index is zero-based.
403 * Example:
405 * Tuple<int, float, char> t;
406 * ...
407 * float f = Get<1>(t);
410 // Non-const reference version.
411 template <std::size_t Index, typename... Elements>
412 auto Get(Tuple<Elements...>& aTuple)
413 -> decltype(detail::TupleGetHelper<Index>(aTuple)) {
414 return detail::TupleGetHelper<Index>(aTuple);
417 // Const reference version.
418 template <std::size_t Index, typename... Elements>
419 auto Get(const Tuple<Elements...>& aTuple)
420 -> decltype(detail::TupleGetHelper<Index>(aTuple)) {
421 return detail::TupleGetHelper<Index>(aTuple);
424 // Rvalue reference version.
425 template <std::size_t Index, typename... Elements>
426 auto Get(Tuple<Elements...>&& aTuple)
427 -> decltype(std::move(mozilla::Get<Index>(aTuple))) {
428 // We need a 'mozilla::' qualification here to avoid
429 // name lookup only finding the current function.
430 return std::move(mozilla::Get<Index>(aTuple));
434 * Helpers which call a function for each member of the tuple in turn. This will
435 * typically be used with a lambda function with an `auto&` argument:
437 * Tuple<Foo*, Bar*, SmartPtr<Baz>> tuple{a, b, c};
439 * ForEach(tuple, [](auto& aElem) {
440 * aElem = nullptr;
441 * });
444 template <typename F>
445 inline void ForEach(const Tuple<>& aTuple, const F& aFunc) {}
447 template <typename F>
448 inline void ForEach(Tuple<>& aTuple, const F& aFunc) {}
450 template <typename F, typename... Elements>
451 void ForEach(const Tuple<Elements...>& aTuple, const F& aFunc) {
452 aTuple.ForEach(aTuple, aFunc);
455 template <typename F, typename... Elements>
456 void ForEach(Tuple<Elements...>& aTuple, const F& aFunc) {
457 aTuple.ForEach(aFunc);
460 template <typename F, typename... Elements>
461 void ForEach(Tuple<Elements...>&& aTuple, const F& aFunc) {
462 std::forward<Tuple<Elements...>>(aTuple).ForEach(aFunc);
466 * A convenience function for constructing a tuple out of a sequence of
467 * values without specifying the type of the tuple.
468 * The type of the tuple is deduced from the types of its elements.
470 * Example:
472 * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
474 template <typename... Elements>
475 inline Tuple<std::decay_t<Elements>...> MakeTuple(Elements&&... aElements) {
476 return Tuple<std::decay_t<Elements>...>(std::forward<Elements>(aElements)...);
480 * A helper placholder to allow ignoring specific elements during Tie unpacking.
481 * Can be used with any type and any number of elements in a call to Tie.
483 * Usage of Ignore with Tie is equivalent to using std::ignore with
484 * std::tie.
486 * Example:
488 * int i;
489 * float f;
490 * char c;
491 * Tie(i, Ignore, f, c, Ignore) = FunctionThatReturnsATuple();
493 constexpr detail::IgnoreImpl Ignore;
496 * A convenience function for constructing a tuple of references to a
497 * sequence of variables. Since assignments to the elements of the tuple
498 * "go through" to the referenced variables, this can be used to "unpack"
499 * a tuple into individual variables.
501 * Example:
503 * int i;
504 * float f;
505 * char c;
506 * Tie(i, f, c) = FunctionThatReturnsATuple();
508 template <typename... Elements>
509 inline Tuple<Elements&...> Tie(Elements&... aVariables) {
510 return Tuple<Elements&...>(aVariables...);
513 } // namespace mozilla
515 #endif /* mozilla_Tuple_h */