1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FRUIT_META_METAPROGRAMMING_H 18 #define FRUIT_META_METAPROGRAMMING_H 19 20 #include <fruit/impl/meta/basics.h> 21 #include <fruit/impl/meta/vector.h> 22 23 #include <fruit/impl/fruit_assert.h> 24 #include <fruit/impl/fruit_internal_forward_decls.h> 25 #include <fruit/impl/injection_errors.h> 26 #include <fruit/impl/meta/errors.h> 27 28 #include <memory> 29 30 namespace fruit { 31 namespace impl { 32 namespace meta { 33 34 struct IsConstructible { 35 template <typename C, typename... Args> 36 struct apply; 37 38 template <typename C, typename... Args> 39 struct apply<Type<C>, Type<Args>...> { 40 using type = Bool<std::is_constructible<C, Args...>::value>; 41 }; 42 }; 43 44 struct IsConstructibleWithVector { 45 template <typename C, typename V> 46 struct apply; 47 48 template <typename C, typename... Types> 49 struct apply<Type<C>, Vector<Type<Types>...>> { 50 using type = Bool<std::is_constructible<C, Types...>::value>; 51 }; 52 }; 53 54 struct AddPointer { 55 template <typename T> 56 struct apply; 57 58 template <typename T> 59 struct apply<Type<T>> { 60 using type = Type<T*>; 61 }; 62 }; 63 64 struct IsCallable { 65 template <typename T> 66 struct apply; 67 68 template <typename C> 69 struct apply<Type<C>> { 70 template <typename C1> 71 static Bool<true> test(decltype(&C1::operator())); 72 73 template <typename> 74 static Bool<false> test(...); 75 76 using type = decltype(test<C>(nullptr)); 77 }; 78 }; 79 80 struct GetCallOperatorSignature { 81 template <typename T> 82 struct apply; 83 84 template <typename C> 85 struct apply<Type<C>> { 86 using type = Type<decltype(&C::operator())>; 87 }; 88 }; 89 90 struct AddPointerToVector { 91 template <typename V> 92 struct apply; 93 94 template <typename... Ts> 95 struct apply<Vector<Type<Ts>...>> { 96 using type = Vector<Type<Ts*>...>; 97 }; 98 }; 99 100 struct GetNthTypeHelper { 101 template <typename N, typename... Ts> 102 struct apply; 103 104 template <typename T, typename... Ts> 105 struct apply<Int<0>, T, Ts...> { 106 using type = T; 107 }; 108 109 template <int n, typename T, typename... Ts> 110 struct apply<Int<n>, T, Ts...> { 111 using type = GetNthTypeHelper(Int<n - 1>, Ts...); 112 }; 113 }; 114 115 struct GetNthType { 116 template <typename N, typename V> 117 struct apply; 118 119 template <typename N, typename... Ts> 120 struct apply<N, Vector<Ts...>> { 121 using type = GetNthTypeHelper(N, Ts...); 122 }; 123 }; 124 125 struct FunctorResultHelper { 126 template <typename MethodSignature> 127 struct apply; 128 129 template <typename Result, typename Functor, typename... Args> 130 struct apply<Type<Result (Functor::*)(Args...)>> { 131 using type = Type<Result>; 132 }; 133 }; 134 135 struct FunctorResult { 136 template <typename F> 137 struct apply; 138 139 template <typename F> 140 struct apply<Type<F>> { 141 using type = FunctorResultHelper(Type<decltype(&F::operator())>); 142 }; 143 }; 144 145 struct FunctionSignatureHelper { 146 template <typename LambdaMethod> 147 struct apply; 148 149 template <typename Result, typename LambdaObject, typename... Args> 150 struct apply<Type<Result (LambdaObject::*)(Args...) const>> { 151 using type = Type<Result(Args...)>; 152 }; 153 }; 154 155 // Function is either a plain function type of the form T(*)(Args...) or a lambda. 156 struct FunctionSignature { 157 template <typename Function> 158 struct apply; 159 160 template <typename Function> 161 struct apply<Type<Function>> { 162 using CandidateSignature = FunctionSignatureHelper(GetCallOperatorSignature(Type<Function>)); 163 using type = If(Not(IsCallable(Type<Function>)), ConstructError(NotALambdaErrorTag, Type<Function>), 164 If(Not(IsConstructible(AddPointer(CandidateSignature), Type<Function>)), 165 ConstructError(FunctorUsedAsProviderErrorTag, Type<Function>), CandidateSignature)); 166 }; 167 168 template <typename Result, typename... Args> 169 struct apply<Type<Result(Args...)>> { 170 using type = Type<Result(Args...)>; 171 }; 172 173 template <typename Result, typename... Args> 174 struct apply<Type<Result (*)(Args...)>> { 175 using type = Type<Result(Args...)>; 176 }; 177 }; 178 179 } // namespace meta 180 } // namespace impl 181 } // namespace fruit 182 183 #endif // FRUIT_META_METAPROGRAMMING_H 184