xref: /aosp_15_r20/external/federated-compute/fcp/base/meta.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*14675a02SAndroid Build Coastguard Worker  *
4*14675a02SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker  *
8*14675a02SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker  *
10*14675a02SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker  * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker  */
16*14675a02SAndroid Build Coastguard Worker 
17*14675a02SAndroid Build Coastguard Worker /**
18*14675a02SAndroid Build Coastguard Worker  * This file provides general utilities for metaprogramming.
19*14675a02SAndroid Build Coastguard Worker  *
20*14675a02SAndroid Build Coastguard Worker  *   - LIFT_MEMBER_TO_TYPE: Generates distinct types in correspondence with
21*14675a02SAndroid Build Coastguard Worker  *     member-pointers (for both fields and functions). For example,
22*14675a02SAndroid Build Coastguard Worker  *     LIFT_MEMBER_TO_TYPE(S, X) != LIFT_MEMBER_TO_TYPE(R, X), even if the
23*14675a02SAndroid Build Coastguard Worker  *     declarations of S::X and R::X are identical.
24*14675a02SAndroid Build Coastguard Worker  *
25*14675a02SAndroid Build Coastguard Worker  *   - Unit: An empty struct (i.e. has a single canonical element). It is useful
26*14675a02SAndroid Build Coastguard Worker  *     in contexts where a non-void return type is necessary but undesired: for
27*14675a02SAndroid Build Coastguard Worker  *     example, in a constexpr function called only for static_asserts.
28*14675a02SAndroid Build Coastguard Worker  *
29*14675a02SAndroid Build Coastguard Worker  *   - Pack<T...>: Helps passing around the 'parameter packs' arising from
30*14675a02SAndroid Build Coastguard Worker  *     variadic templates (they are not first-class). In particular, these allow
31*14675a02SAndroid Build Coastguard Worker  *     writing a function such that F<A, B>() and F<Pack<A, B>>() are equivalent
32*14675a02SAndroid Build Coastguard Worker  *     (Pack<A, B> _is_ first-class).
33*14675a02SAndroid Build Coastguard Worker  *
34*14675a02SAndroid Build Coastguard Worker  *   - MemberPointerTraits: Allows removing the 'container' part from
35*14675a02SAndroid Build Coastguard Worker  *     member-pointer types, e.g.
36*14675a02SAndroid Build Coastguard Worker  *       'R T::*' => 'R'
37*14675a02SAndroid Build Coastguard Worker  *       'R (T::*)(A, B)' => 'R(A, B)'
38*14675a02SAndroid Build Coastguard Worker  *
39*14675a02SAndroid Build Coastguard Worker  *   - FunctionTraits: Allows destructuring function types, e.g. 'bool(int,
40*14675a02SAndroid Build Coastguard Worker  *     int)' into ResultType = bool, ArgPackType = Pack<int, int>.
41*14675a02SAndroid Build Coastguard Worker  *
42*14675a02SAndroid Build Coastguard Worker  *   - FailIfReached: Allows writing static_asserts for templates that should
43*14675a02SAndroid Build Coastguard Worker  *     never be instantiated. This is a workaround for the fact that
44*14675a02SAndroid Build Coastguard Worker  *    'static_assert(false, "")' can trigger regardless of where it's located.
45*14675a02SAndroid Build Coastguard Worker  *
46*14675a02SAndroid Build Coastguard Worker  *   - Identity<T>: An alias useful with higher order templates.
47*14675a02SAndroid Build Coastguard Worker  *
48*14675a02SAndroid Build Coastguard Worker  *   - CastContainerElements: Allows 'casting' homogenous containers to
49*14675a02SAndroid Build Coastguard Worker  *     heterogenous tuples, e.g. vector<X> -> tuple<A, B> - useful when
50*14675a02SAndroid Build Coastguard Worker  *     when the type-list was erased earlier.
51*14675a02SAndroid Build Coastguard Worker  *
52*14675a02SAndroid Build Coastguard Worker  *   - LiftVoidReturn: Wraps a callable object, so that returned 'void' becomes
53*14675a02SAndroid Build Coastguard Worker  *     'Unit' (if applicable). This avoids spread of special cases when handling
54*14675a02SAndroid Build Coastguard Worker  *     callables and function-types generically (e.g. 'auto r = f()' is valid
55*14675a02SAndroid Build Coastguard Worker  *     for f() returning anything _except_ void).
56*14675a02SAndroid Build Coastguard Worker  *
57*14675a02SAndroid Build Coastguard Worker  *   - MAKE_LINK and LinkedType<T>: Given types T, U and MAKE_LINK(T, U),
58*14675a02SAndroid Build Coastguard Worker  *     LinkedType<T> == U. This can often be handled with template
59*14675a02SAndroid Build Coastguard Worker  *     specialization, but (like AbslHashValue) we use ADL so that T (and
60*14675a02SAndroid Build Coastguard Worker  *     MAKE_LINK next to it) can appear in any namespace.
61*14675a02SAndroid Build Coastguard Worker  *
62*14675a02SAndroid Build Coastguard Worker  *   - IsTypeOneOf<T, Us...>: A function to determines if the type T is in the
63*14675a02SAndroid Build Coastguard Worker  *     list of types Us.
64*14675a02SAndroid Build Coastguard Worker  *
65*14675a02SAndroid Build Coastguard Worker  *   - IsSubsetOf<Pack<Ts...>, Pack<Us...>>: Determins if a pack of types Ts
66*14675a02SAndroid Build Coastguard Worker  *     is a subset of a pack of types Us.
67*14675a02SAndroid Build Coastguard Worker  */
68*14675a02SAndroid Build Coastguard Worker 
69*14675a02SAndroid Build Coastguard Worker #ifndef FCP_BASE_META_H_
70*14675a02SAndroid Build Coastguard Worker #define FCP_BASE_META_H_
71*14675a02SAndroid Build Coastguard Worker 
72*14675a02SAndroid Build Coastguard Worker #include <tuple>
73*14675a02SAndroid Build Coastguard Worker #include <type_traits>
74*14675a02SAndroid Build Coastguard Worker 
75*14675a02SAndroid Build Coastguard Worker #include "fcp/base/monitoring.h"
76*14675a02SAndroid Build Coastguard Worker 
77*14675a02SAndroid Build Coastguard Worker namespace fcp {
78*14675a02SAndroid Build Coastguard Worker 
79*14675a02SAndroid Build Coastguard Worker /**
80*14675a02SAndroid Build Coastguard Worker  * An empty struct - i.e. there is a single canonical element.
81*14675a02SAndroid Build Coastguard Worker  *
82*14675a02SAndroid Build Coastguard Worker  * It is useful in contexts where a non-void return type is necessary but
83*14675a02SAndroid Build Coastguard Worker  * undesired: for example, in a constexpr function called only for
84*14675a02SAndroid Build Coastguard Worker  * static_asserts.
85*14675a02SAndroid Build Coastguard Worker  *
86*14675a02SAndroid Build Coastguard Worker  * Unit defines equality (they're always equal). True() always returns true,
87*14675a02SAndroid Build Coastguard Worker  * which is convenient for allowing a unit-returning function call in a
88*14675a02SAndroid Build Coastguard Worker  * static_assert.
89*14675a02SAndroid Build Coastguard Worker  *
90*14675a02SAndroid Build Coastguard Worker  * Unit::Ignore(...) sinks any arguments to a Unit. This is useful in C++11's
91*14675a02SAndroid Build Coastguard Worker  * restricted constexpr as well as for parameter-pack expansions.
92*14675a02SAndroid Build Coastguard Worker  */
93*14675a02SAndroid Build Coastguard Worker struct Unit {
94*14675a02SAndroid Build Coastguard Worker   constexpr bool operator==(Unit other) const { return true; }
95*14675a02SAndroid Build Coastguard Worker   constexpr bool operator!=(Unit other) const { return !(*this == other); }
TrueUnit96*14675a02SAndroid Build Coastguard Worker   constexpr bool True() const { return true; }
97*14675a02SAndroid Build Coastguard Worker 
98*14675a02SAndroid Build Coastguard Worker   /** Ignores all arguments (of any type), returning Unit */
99*14675a02SAndroid Build Coastguard Worker   template <typename... ArgTypes>
IgnoreUnit100*14675a02SAndroid Build Coastguard Worker   static constexpr Unit Ignore(ArgTypes... args) {
101*14675a02SAndroid Build Coastguard Worker     return {};
102*14675a02SAndroid Build Coastguard Worker   }
103*14675a02SAndroid Build Coastguard Worker };
104*14675a02SAndroid Build Coastguard Worker 
105*14675a02SAndroid Build Coastguard Worker /**
106*14675a02SAndroid Build Coastguard Worker  * Pack<T...> facilitates passing around a parameter-pack T...
107*14675a02SAndroid Build Coastguard Worker  *
108*14675a02SAndroid Build Coastguard Worker  * Types are more or less first-class, in that you can place one somewhere (e.g.
109*14675a02SAndroid Build Coastguard Worker  * as a struct member) and use it later. This is not the case for
110*14675a02SAndroid Build Coastguard Worker  * parameter-packs: one can only expand T... within some template<typename...
111*14675a02SAndroid Build Coastguard Worker  * T>.
112*14675a02SAndroid Build Coastguard Worker  *
113*14675a02SAndroid Build Coastguard Worker  * Pack<> is a work-around for that:
114*14675a02SAndroid Build Coastguard Worker  *
115*14675a02SAndroid Build Coastguard Worker  *   - To store a parameter-pack T... in hand: Instead store Pack<T...>, e.g.
116*14675a02SAndroid Build Coastguard Worker  *     'using P = Pack<T...>'
117*14675a02SAndroid Build Coastguard Worker  *
118*14675a02SAndroid Build Coastguard Worker  *   - To revitalize the parameter pack later: Define a target function like
119*14675a02SAndroid Build Coastguard Worker  *        template<typename... T> F(Pack<T...>)
120*14675a02SAndroid Build Coastguard Worker  *     and call it as
121*14675a02SAndroid Build Coastguard Worker  *        F(P{})
122*14675a02SAndroid Build Coastguard Worker  *     (noting P from the prior example). The T... in scope of F arises from
123*14675a02SAndroid Build Coastguard Worker  *     template argument deduction.
124*14675a02SAndroid Build Coastguard Worker  */
125*14675a02SAndroid Build Coastguard Worker template <typename... T>
126*14675a02SAndroid Build Coastguard Worker struct Pack {
127*14675a02SAndroid Build Coastguard Worker   /** Returns the related index-sequence type.
128*14675a02SAndroid Build Coastguard Worker    *
129*14675a02SAndroid Build Coastguard Worker    * Example:
130*14675a02SAndroid Build Coastguard Worker    *
131*14675a02SAndroid Build Coastguard Worker    *     template <typename... T, size_t... Idx>
132*14675a02SAndroid Build Coastguard Worker    *     void Impl(Pack<T...>, absl::index_sequence<Idx...>) {
133*14675a02SAndroid Build Coastguard Worker    *       auto zipped[] = {
134*14675a02SAndroid Build Coastguard Worker    *         F<T>(Idx)... // T... and Idx... are zipped together.
135*14675a02SAndroid Build Coastguard Worker    *       };
136*14675a02SAndroid Build Coastguard Worker    *     }
137*14675a02SAndroid Build Coastguard Worker    *
138*14675a02SAndroid Build Coastguard Worker    *     template <typename... T>
139*14675a02SAndroid Build Coastguard Worker    *     void Foo(Pack<T...> pack) {
140*14675a02SAndroid Build Coastguard Worker    *       Impl(pack, pack.MakeIndexSequence());
141*14675a02SAndroid Build Coastguard Worker    *     }
142*14675a02SAndroid Build Coastguard Worker    */
MakeIndexSequencePack143*14675a02SAndroid Build Coastguard Worker   static constexpr absl::index_sequence_for<T...> MakeIndexSequence() {
144*14675a02SAndroid Build Coastguard Worker     return {};
145*14675a02SAndroid Build Coastguard Worker   }
146*14675a02SAndroid Build Coastguard Worker };
147*14675a02SAndroid Build Coastguard Worker 
148*14675a02SAndroid Build Coastguard Worker /**
149*14675a02SAndroid Build Coastguard Worker  * Workaround for static_assert(false) tripping even for un-instantiated
150*14675a02SAndroid Build Coastguard Worker  * templates.
151*14675a02SAndroid Build Coastguard Worker  */
152*14675a02SAndroid Build Coastguard Worker template <typename T>
FailIfReached()153*14675a02SAndroid Build Coastguard Worker constexpr bool FailIfReached() {
154*14675a02SAndroid Build Coastguard Worker   return !std::is_same<T, T>::value;
155*14675a02SAndroid Build Coastguard Worker }
156*14675a02SAndroid Build Coastguard Worker 
157*14675a02SAndroid Build Coastguard Worker namespace meta_internal {
158*14675a02SAndroid Build Coastguard Worker 
159*14675a02SAndroid Build Coastguard Worker template <typename T, T M>
160*14675a02SAndroid Build Coastguard Worker struct MemberTag {
161*14675a02SAndroid Build Coastguard Worker   static_assert(std::is_member_pointer<T>::value,
162*14675a02SAndroid Build Coastguard Worker                 "Expected a member-pointer type");
163*14675a02SAndroid Build Coastguard Worker };
164*14675a02SAndroid Build Coastguard Worker 
165*14675a02SAndroid Build Coastguard Worker template <typename CastOp, typename... T>
166*14675a02SAndroid Build Coastguard Worker using CastResultType = std::tuple<typename CastOp::template TargetType<T>...>;
167*14675a02SAndroid Build Coastguard Worker 
168*14675a02SAndroid Build Coastguard Worker template <typename... T, size_t... Idx, typename Container, typename CastOp>
CastContainerElementsImpl(Container const & container,CastOp const & cast,Pack<T...>,absl::index_sequence<Idx...>)169*14675a02SAndroid Build Coastguard Worker CastResultType<CastOp, T...> CastContainerElementsImpl(
170*14675a02SAndroid Build Coastguard Worker     Container const& container, CastOp const& cast, Pack<T...>,
171*14675a02SAndroid Build Coastguard Worker     absl::index_sequence<Idx...>) {
172*14675a02SAndroid Build Coastguard Worker   FCP_CHECK(sizeof...(T) == container.size());
173*14675a02SAndroid Build Coastguard Worker   return CastResultType<CastOp, T...>{cast.template Cast<T>(container[Idx])...};
174*14675a02SAndroid Build Coastguard Worker }
175*14675a02SAndroid Build Coastguard Worker 
176*14675a02SAndroid Build Coastguard Worker template <typename F>
177*14675a02SAndroid Build Coastguard Worker class VoidLifter {
178*14675a02SAndroid Build Coastguard Worker  private:
179*14675a02SAndroid Build Coastguard Worker   template <typename T>
180*14675a02SAndroid Build Coastguard Worker   struct Tag {};
181*14675a02SAndroid Build Coastguard Worker 
182*14675a02SAndroid Build Coastguard Worker   template <typename... A>
DoCall(Tag<void>,A &&...args)183*14675a02SAndroid Build Coastguard Worker   Unit DoCall(Tag<void>, A&&... args) {
184*14675a02SAndroid Build Coastguard Worker     f_(std::forward<A>(args)...);
185*14675a02SAndroid Build Coastguard Worker     return {};
186*14675a02SAndroid Build Coastguard Worker   }
187*14675a02SAndroid Build Coastguard Worker 
188*14675a02SAndroid Build Coastguard Worker   template <typename R, typename... A>
DoCall(Tag<R>,A &&...args)189*14675a02SAndroid Build Coastguard Worker   R DoCall(Tag<R>, A&&... args) {
190*14675a02SAndroid Build Coastguard Worker     return f_(std::forward<A>(args)...);
191*14675a02SAndroid Build Coastguard Worker   }
192*14675a02SAndroid Build Coastguard Worker 
193*14675a02SAndroid Build Coastguard Worker  public:
VoidLifter(F f)194*14675a02SAndroid Build Coastguard Worker   explicit VoidLifter(F f) : f_(std::move(f)) {}
195*14675a02SAndroid Build Coastguard Worker 
196*14675a02SAndroid Build Coastguard Worker   template <typename... A>
197*14675a02SAndroid Build Coastguard Worker   auto operator()(A&&... args) -> decltype(
198*14675a02SAndroid Build Coastguard Worker       DoCall(Tag<decltype(std::declval<F>()(std::forward<A>(args)...))>{},
199*14675a02SAndroid Build Coastguard Worker              std::forward<A>(args)...)) {
200*14675a02SAndroid Build Coastguard Worker     return DoCall(Tag<decltype(std::declval<F>()(std::forward<A>(args)...))>{},
201*14675a02SAndroid Build Coastguard Worker                   std::forward<A>(args)...);
202*14675a02SAndroid Build Coastguard Worker   }
203*14675a02SAndroid Build Coastguard Worker 
204*14675a02SAndroid Build Coastguard Worker  private:
205*14675a02SAndroid Build Coastguard Worker   F f_;
206*14675a02SAndroid Build Coastguard Worker };
207*14675a02SAndroid Build Coastguard Worker 
208*14675a02SAndroid Build Coastguard Worker template <typename U, typename Dummy = void>
209*14675a02SAndroid Build Coastguard Worker struct FailIfLinkMissing {
210*14675a02SAndroid Build Coastguard Worker   using Type = U;
211*14675a02SAndroid Build Coastguard Worker };
212*14675a02SAndroid Build Coastguard Worker 
213*14675a02SAndroid Build Coastguard Worker template <typename Dummy>
214*14675a02SAndroid Build Coastguard Worker struct FailIfLinkMissing<void, Dummy> {
215*14675a02SAndroid Build Coastguard Worker   static_assert(FailIfReached<Dummy>(),
216*14675a02SAndroid Build Coastguard Worker                 "Expected a type linked from T, via MAKE_LINK(T, U). Note that "
217*14675a02SAndroid Build Coastguard Worker                 "MAKE_LINK must appear in the same namespace as T.");
218*14675a02SAndroid Build Coastguard Worker };
219*14675a02SAndroid Build Coastguard Worker 
220*14675a02SAndroid Build Coastguard Worker template <typename T>
221*14675a02SAndroid Build Coastguard Worker struct LinkedTypeToken {
222*14675a02SAndroid Build Coastguard Worker   using Type = T;
223*14675a02SAndroid Build Coastguard Worker };
224*14675a02SAndroid Build Coastguard Worker 
225*14675a02SAndroid Build Coastguard Worker /**
226*14675a02SAndroid Build Coastguard Worker  * Default case for LookupTypeLink. MAKE_LINK creates overloads which are more
227*14675a02SAndroid Build Coastguard Worker  * specific (argument type matches without needing a template).
228*14675a02SAndroid Build Coastguard Worker  */
229*14675a02SAndroid Build Coastguard Worker template <typename T>
230*14675a02SAndroid Build Coastguard Worker inline LinkedTypeToken<void> TypeLink_(LinkedTypeToken<T>) {
231*14675a02SAndroid Build Coastguard Worker   return {};
232*14675a02SAndroid Build Coastguard Worker }
233*14675a02SAndroid Build Coastguard Worker 
234*14675a02SAndroid Build Coastguard Worker /**
235*14675a02SAndroid Build Coastguard Worker  * Resolves MAKE_LINK at the level of values (i.e. the link target is
236*14675a02SAndroid Build Coastguard Worker  * represented in the return type). May be called qualified, i.e.
237*14675a02SAndroid Build Coastguard Worker  * fcp::meta_internal::LookupTypeLink.
238*14675a02SAndroid Build Coastguard Worker  *
239*14675a02SAndroid Build Coastguard Worker  * This depends on ADL. TypeLink_ is an unqualified name, so those next to T are
240*14675a02SAndroid Build Coastguard Worker  * overload candidates. As such, it's fine to call meta_internal::LookupTypeLink
241*14675a02SAndroid Build Coastguard Worker  * but *not* meta_internal::TypeLink_ (hence this indirection).
242*14675a02SAndroid Build Coastguard Worker  */
243*14675a02SAndroid Build Coastguard Worker template <typename T>
244*14675a02SAndroid Build Coastguard Worker constexpr auto LookupTypeLink(LinkedTypeToken<T> t) -> decltype(TypeLink_(t)) {
245*14675a02SAndroid Build Coastguard Worker   return {};
246*14675a02SAndroid Build Coastguard Worker }
247*14675a02SAndroid Build Coastguard Worker 
248*14675a02SAndroid Build Coastguard Worker template <template <typename> class M, typename Z>
249*14675a02SAndroid Build Coastguard Worker struct UnwrapTemplateImpl {
250*14675a02SAndroid Build Coastguard Worker   static constexpr bool kValid = false;
251*14675a02SAndroid Build Coastguard Worker 
252*14675a02SAndroid Build Coastguard Worker   struct Type {
253*14675a02SAndroid Build Coastguard Worker     static_assert(FailIfReached<Z>(), "Z must be M<T> for some type T");
254*14675a02SAndroid Build Coastguard Worker   };
255*14675a02SAndroid Build Coastguard Worker };
256*14675a02SAndroid Build Coastguard Worker 
257*14675a02SAndroid Build Coastguard Worker template <template <typename> class M, typename T>
258*14675a02SAndroid Build Coastguard Worker struct UnwrapTemplateImpl<M, M<T>> {
259*14675a02SAndroid Build Coastguard Worker   static constexpr bool kValid = true;
260*14675a02SAndroid Build Coastguard Worker   using Type = T;
261*14675a02SAndroid Build Coastguard Worker };
262*14675a02SAndroid Build Coastguard Worker 
263*14675a02SAndroid Build Coastguard Worker template <template <typename> class M, typename Z>
264*14675a02SAndroid Build Coastguard Worker using UnwrapTemplate = meta_internal::UnwrapTemplateImpl<M, std::decay_t<Z>>;
265*14675a02SAndroid Build Coastguard Worker 
266*14675a02SAndroid Build Coastguard Worker }  // namespace meta_internal
267*14675a02SAndroid Build Coastguard Worker 
268*14675a02SAndroid Build Coastguard Worker /**
269*14675a02SAndroid Build Coastguard Worker  * Generates distinct types in correspondence with member-pointers (for both
270*14675a02SAndroid Build Coastguard Worker  * fields and functions).
271*14675a02SAndroid Build Coastguard Worker  *
272*14675a02SAndroid Build Coastguard Worker  * For example, LIFT_MEMBER_TO_TYPE(S, X) != LIFT_MEMBER_TO_TYPE(R, X), even if
273*14675a02SAndroid Build Coastguard Worker  * the declarations of S::X and R::X are identical.
274*14675a02SAndroid Build Coastguard Worker  *
275*14675a02SAndroid Build Coastguard Worker  * The lifted type is always an empty struct, so it can be instantiated with {}
276*14675a02SAndroid Build Coastguard Worker  * (for use in overload resolution) at no cost.
277*14675a02SAndroid Build Coastguard Worker  */
278*14675a02SAndroid Build Coastguard Worker #define LIFT_MEMBER_TO_TYPE(type, member) \
279*14675a02SAndroid Build Coastguard Worker   LIFT_MEMBER_POINTER_TO_TYPE(&type::member)
280*14675a02SAndroid Build Coastguard Worker 
281*14675a02SAndroid Build Coastguard Worker /**
282*14675a02SAndroid Build Coastguard Worker  * Same as LIFT_MEMBER_TO_TYPE, but invoked as e.g.
283*14675a02SAndroid Build Coastguard Worker  * LIFT_MEMBER_POINTER_TO_TYPE(&S::X)
284*14675a02SAndroid Build Coastguard Worker  */
285*14675a02SAndroid Build Coastguard Worker #define LIFT_MEMBER_POINTER_TO_TYPE(ptr) \
286*14675a02SAndroid Build Coastguard Worker   ::fcp::meta_internal::MemberTag<decltype(ptr), ptr>
287*14675a02SAndroid Build Coastguard Worker 
288*14675a02SAndroid Build Coastguard Worker /**
289*14675a02SAndroid Build Coastguard Worker  * Allows removing the 'container' part from member-pointer types, e.g.
290*14675a02SAndroid Build Coastguard Worker  *   'R T::*' => 'R' 'R (T::*)(A, B)' => 'R(A, B)'
291*14675a02SAndroid Build Coastguard Worker  */
292*14675a02SAndroid Build Coastguard Worker template <typename T>
293*14675a02SAndroid Build Coastguard Worker struct MemberPointerTraits {
294*14675a02SAndroid Build Coastguard Worker   static_assert(
295*14675a02SAndroid Build Coastguard Worker       FailIfReached<T>(),
296*14675a02SAndroid Build Coastguard Worker       "Expected a member pointer (both fields and functions are accepted)");
297*14675a02SAndroid Build Coastguard Worker };
298*14675a02SAndroid Build Coastguard Worker 
299*14675a02SAndroid Build Coastguard Worker template <typename T, typename R>
300*14675a02SAndroid Build Coastguard Worker struct MemberPointerTraits<R T::*> {
301*14675a02SAndroid Build Coastguard Worker   using TargetType = R;
302*14675a02SAndroid Build Coastguard Worker };
303*14675a02SAndroid Build Coastguard Worker 
304*14675a02SAndroid Build Coastguard Worker template <typename T>
305*14675a02SAndroid Build Coastguard Worker struct FunctionTraits {
306*14675a02SAndroid Build Coastguard Worker   static_assert(FailIfReached<T>(), "Expected a function type");
307*14675a02SAndroid Build Coastguard Worker };
308*14675a02SAndroid Build Coastguard Worker 
309*14675a02SAndroid Build Coastguard Worker template <typename R, typename... A>
310*14675a02SAndroid Build Coastguard Worker struct FunctionTraits<R(A...)> {
311*14675a02SAndroid Build Coastguard Worker   using ResultType = R;
312*14675a02SAndroid Build Coastguard Worker   using ArgPackType = Pack<A...>;
313*14675a02SAndroid Build Coastguard Worker };
314*14675a02SAndroid Build Coastguard Worker 
315*14675a02SAndroid Build Coastguard Worker /** Type-level identity function; useful for higher order templates */
316*14675a02SAndroid Build Coastguard Worker template <typename T>
317*14675a02SAndroid Build Coastguard Worker using Identity = T;
318*14675a02SAndroid Build Coastguard Worker 
319*14675a02SAndroid Build Coastguard Worker /** See other overload; this one takes a Pack<T...> instead of explicit T... */
320*14675a02SAndroid Build Coastguard Worker template <typename... T, typename Container, typename CastOp>
321*14675a02SAndroid Build Coastguard Worker auto CastContainerElements(Pack<T...> pack, Container const& container,
322*14675a02SAndroid Build Coastguard Worker                            CastOp const& cast)
323*14675a02SAndroid Build Coastguard Worker     -> decltype(meta_internal::CastContainerElementsImpl(
324*14675a02SAndroid Build Coastguard Worker         container, cast, pack, pack.MakeIndexSequence())) {
325*14675a02SAndroid Build Coastguard Worker   return meta_internal::CastContainerElementsImpl(container, cast, pack,
326*14675a02SAndroid Build Coastguard Worker                                                   pack.MakeIndexSequence());
327*14675a02SAndroid Build Coastguard Worker }
328*14675a02SAndroid Build Coastguard Worker 
329*14675a02SAndroid Build Coastguard Worker /**
330*14675a02SAndroid Build Coastguard Worker  * Allows 'casting' homogenous containers to heterogenous tuples, e.g.
331*14675a02SAndroid Build Coastguard Worker  * vector<X> -> tuple<A, B> - useful when when the type-list was erased
332*14675a02SAndroid Build Coastguard Worker  * earlier.
333*14675a02SAndroid Build Coastguard Worker  *
334*14675a02SAndroid Build Coastguard Worker  * 'CastOp' determines how to cast each element. It should be a type like the
335*14675a02SAndroid Build Coastguard Worker  * following:
336*14675a02SAndroid Build Coastguard Worker  *
337*14675a02SAndroid Build Coastguard Worker  *    struct FooCast {
338*14675a02SAndroid Build Coastguard Worker  *     template<typename T>
339*14675a02SAndroid Build Coastguard Worker  *     using TargetType = Y<T>;
340*14675a02SAndroid Build Coastguard Worker  *
341*14675a02SAndroid Build Coastguard Worker  *     template <typename T>
342*14675a02SAndroid Build Coastguard Worker  *     TargetType<T> Cast(X const& val) const {
343*14675a02SAndroid Build Coastguard Worker  *        ...
344*14675a02SAndroid Build Coastguard Worker  *      }
345*14675a02SAndroid Build Coastguard Worker  *     };
346*14675a02SAndroid Build Coastguard Worker  *
347*14675a02SAndroid Build Coastguard Worker  * Supposing vector<X> vx, CastContainerElements<A, B>(vx, FooCast{}) would
348*14675a02SAndroid Build Coastguard Worker  * yield a tuple<Y<A>, Y<B>> with values {Cast<A>(vx[0]), Cast<B>(vx[1])}.
349*14675a02SAndroid Build Coastguard Worker  *
350*14675a02SAndroid Build Coastguard Worker  * This function supports the 'Pack' wrapper. For example, the previous example
351*14675a02SAndroid Build Coastguard Worker  * could also be written as CastContainerElements(Pack<X, Y>{}, vx, FooCast{}).
352*14675a02SAndroid Build Coastguard Worker  */
353*14675a02SAndroid Build Coastguard Worker template <typename... T, typename Container, typename CastOp>
354*14675a02SAndroid Build Coastguard Worker auto CastContainerElements(Container const& container, CastOp const& cast)
355*14675a02SAndroid Build Coastguard Worker     -> decltype(CastContainerElements(Pack<T...>{}, container, cast)) {
356*14675a02SAndroid Build Coastguard Worker   return CastContainerElements(Pack<T...>{}, container, cast);
357*14675a02SAndroid Build Coastguard Worker }
358*14675a02SAndroid Build Coastguard Worker 
359*14675a02SAndroid Build Coastguard Worker /**
360*14675a02SAndroid Build Coastguard Worker  * Wraps a callable object, so that returned 'void' becomes 'Unit' (if
361*14675a02SAndroid Build Coastguard Worker  * applicable). This avoids spread of special cases when handling callables and
362*14675a02SAndroid Build Coastguard Worker  * function-types generically (e.g. 'auto r = f()' is valid for f() returning
363*14675a02SAndroid Build Coastguard Worker  * anything _except_ void).
364*14675a02SAndroid Build Coastguard Worker  */
365*14675a02SAndroid Build Coastguard Worker template <typename F>
366*14675a02SAndroid Build Coastguard Worker meta_internal::VoidLifter<F> LiftVoidReturn(F f) {
367*14675a02SAndroid Build Coastguard Worker   return meta_internal::VoidLifter<F>(std::move(f));
368*14675a02SAndroid Build Coastguard Worker }
369*14675a02SAndroid Build Coastguard Worker 
370*14675a02SAndroid Build Coastguard Worker /** See LinkedType<T> */
371*14675a02SAndroid Build Coastguard Worker #define MAKE_LINK(a, b)                                      \
372*14675a02SAndroid Build Coastguard Worker   inline ::fcp::meta_internal::LinkedTypeToken<b> TypeLink_( \
373*14675a02SAndroid Build Coastguard Worker       ::fcp::meta_internal::LinkedTypeToken<a>) {            \
374*14675a02SAndroid Build Coastguard Worker     return {};                                               \
375*14675a02SAndroid Build Coastguard Worker   }
376*14675a02SAndroid Build Coastguard Worker 
377*14675a02SAndroid Build Coastguard Worker /**
378*14675a02SAndroid Build Coastguard Worker  * See LinkedType<T>. This form returns void instead of failing when a link is
379*14675a02SAndroid Build Coastguard Worker  * missing
380*14675a02SAndroid Build Coastguard Worker  */
381*14675a02SAndroid Build Coastguard Worker template <typename T>
382*14675a02SAndroid Build Coastguard Worker using LinkedTypeOrVoid = typename decltype(meta_internal::LookupTypeLink(
383*14675a02SAndroid Build Coastguard Worker     std::declval<meta_internal::LinkedTypeToken<T>>()))::Type;
384*14675a02SAndroid Build Coastguard Worker 
385*14675a02SAndroid Build Coastguard Worker /**
386*14675a02SAndroid Build Coastguard Worker  * Indicates if some MAKE_LINK(T, ...) is visible.
387*14675a02SAndroid Build Coastguard Worker  */
388*14675a02SAndroid Build Coastguard Worker template <typename T>
389*14675a02SAndroid Build Coastguard Worker constexpr bool HasLinkedType() {
390*14675a02SAndroid Build Coastguard Worker   return !std::is_same<LinkedTypeOrVoid<T>, void>::value;
391*14675a02SAndroid Build Coastguard Worker }
392*14675a02SAndroid Build Coastguard Worker 
393*14675a02SAndroid Build Coastguard Worker /**
394*14675a02SAndroid Build Coastguard Worker  * Given types T, U and MAKE_LINK(T, U), LinkedType<T> == U.
395*14675a02SAndroid Build Coastguard Worker  *
396*14675a02SAndroid Build Coastguard Worker  * This can often be handled with template specialization, but (like
397*14675a02SAndroid Build Coastguard Worker  * AbslHashValue) we use ADL to avoid restrictions on the namespaces in which
398*14675a02SAndroid Build Coastguard Worker  * specializations can appear.
399*14675a02SAndroid Build Coastguard Worker  *
400*14675a02SAndroid Build Coastguard Worker  * The type T can appear in any namespace, but MAKE_LINK(T, U) must appear in
401*14675a02SAndroid Build Coastguard Worker  * the same namespace (ideally, place it right after the declaration of T).
402*14675a02SAndroid Build Coastguard Worker  * LinkedType<T> then works in any namespace.
403*14675a02SAndroid Build Coastguard Worker  *
404*14675a02SAndroid Build Coastguard Worker  * It is an error to use this alias for a T without a MAKE_LINK. See
405*14675a02SAndroid Build Coastguard Worker  * HasLinkedType() and LinkedTypeOrVoid.
406*14675a02SAndroid Build Coastguard Worker  */
407*14675a02SAndroid Build Coastguard Worker template <typename T>
408*14675a02SAndroid Build Coastguard Worker using LinkedType =
409*14675a02SAndroid Build Coastguard Worker     typename meta_internal::FailIfLinkMissing<LinkedTypeOrVoid<T>>::Type;
410*14675a02SAndroid Build Coastguard Worker 
411*14675a02SAndroid Build Coastguard Worker 
412*14675a02SAndroid Build Coastguard Worker /*
413*14675a02SAndroid Build Coastguard Worker  * Given type T and typelist Us... determines if T is one of the types in Us.
414*14675a02SAndroid Build Coastguard Worker  */
415*14675a02SAndroid Build Coastguard Worker template <typename T, typename... Us>
416*14675a02SAndroid Build Coastguard Worker struct IsTypeOneOfT : std::disjunction<std::is_same<T, Us>...> {};
417*14675a02SAndroid Build Coastguard Worker 
418*14675a02SAndroid Build Coastguard Worker template <typename T, typename... Us>
419*14675a02SAndroid Build Coastguard Worker constexpr bool IsTypeOneOf() {
420*14675a02SAndroid Build Coastguard Worker   return IsTypeOneOfT<T, Us...>::value;
421*14675a02SAndroid Build Coastguard Worker }
422*14675a02SAndroid Build Coastguard Worker 
423*14675a02SAndroid Build Coastguard Worker /*
424*14675a02SAndroid Build Coastguard Worker  * Given two typelists Ts... and Us... determines if Ts is a subset of Us.
425*14675a02SAndroid Build Coastguard Worker  */
426*14675a02SAndroid Build Coastguard Worker template <typename Ts, typename Us>
427*14675a02SAndroid Build Coastguard Worker struct IsSubsetOf : std::false_type {};
428*14675a02SAndroid Build Coastguard Worker 
429*14675a02SAndroid Build Coastguard Worker template <typename... Ts, typename... Us>
430*14675a02SAndroid Build Coastguard Worker struct IsSubsetOf<Pack<Ts...>, Pack<Us...>>
431*14675a02SAndroid Build Coastguard Worker     : std::conjunction<IsTypeOneOfT<Ts, Us...>...> {};
432*14675a02SAndroid Build Coastguard Worker 
433*14675a02SAndroid Build Coastguard Worker template <template <typename> class M, typename Z>
434*14675a02SAndroid Build Coastguard Worker using UnapplyTemplate =
435*14675a02SAndroid Build Coastguard Worker     typename meta_internal::UnwrapTemplateImpl<M, std::decay_t<Z>>::Type;
436*14675a02SAndroid Build Coastguard Worker 
437*14675a02SAndroid Build Coastguard Worker template <template <typename> class M, typename Z>
438*14675a02SAndroid Build Coastguard Worker constexpr bool IsAppliedTemplate() {
439*14675a02SAndroid Build Coastguard Worker   return meta_internal::UnwrapTemplateImpl<M, std::decay_t<Z>>::kValid;
440*14675a02SAndroid Build Coastguard Worker }
441*14675a02SAndroid Build Coastguard Worker 
442*14675a02SAndroid Build Coastguard Worker }  // namespace fcp
443*14675a02SAndroid Build Coastguard Worker 
444*14675a02SAndroid Build Coastguard Worker #endif  // FCP_BASE_META_H_
445