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_EVAL_H 18 #define FRUIT_META_EVAL_H 19 20 #include <fruit/impl/meta/basics.h> 21 #include <fruit/impl/meta/errors.h> 22 #include <fruit/impl/meta/logical_operations.h> 23 24 #include <functional> 25 26 namespace fruit { 27 namespace impl { 28 namespace meta { 29 30 template <typename MetaExpr> 31 struct DoEval; 32 33 // General case, meta-constant. 34 template <typename MetaExpr> 35 struct DoEval { 36 #if FRUIT_TRACE_INSTANTIATIONS static_warningDoEval37 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 38 return true; 39 } 40 static_assert(static_warning(), ""); 41 #endif 42 using type = MetaExpr; 43 }; 44 45 template <typename Type> 46 struct SimpleIsError { 47 static constexpr bool value = false; 48 }; 49 template <typename ErrorTag, typename... ErrorArgs> 50 struct SimpleIsError<Error<ErrorTag, ErrorArgs...>> { 51 static constexpr bool value = true; 52 }; 53 54 #if FRUIT_EXTRA_DEBUG 55 56 // For debugging, we use a separate DoEvalFun so that we get longer (and more informative) 57 // instantiation traces. 58 59 template <typename MetaFun, typename... Params> 60 struct DoEvalFun { 61 using type = 62 typename DoEval<typename std::conditional<StaticOr<SimpleIsError<Params>::value...>::value, ExtractFirstError, 63 MetaFun>::type::template apply<Params...>::type>::type; 64 }; 65 66 template <typename MetaFun, typename... MetaExprs> 67 struct DoEval<MetaFun(MetaExprs...)> { 68 #if FRUIT_TRACE_INSTANTIATIONS 69 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 70 return true; 71 } 72 static_assert(static_warning(), ""); 73 #endif 74 using type = typename DoEvalFun<MetaFun, typename DoEval<MetaExprs>::type...>::type; 75 }; 76 77 // Similar to the previous specialization, but this will be selected when the function signature 78 // became a function pointer (this happens when a signature parameter is itself a signature). 79 template <typename MetaFun, typename... MetaExprs> 80 struct DoEval<MetaFun (*)(MetaExprs...)> { 81 #if FRUIT_TRACE_INSTANTIATIONS 82 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 83 return true; 84 } 85 static_assert(static_warning(), ""); 86 #endif 87 using type = typename DoEvalFun<MetaFun, typename DoEval<MetaExprs>::type...>::type; 88 }; 89 90 #else // FRUIT_EXTRA_DEBUG 91 92 template <typename MetaFun, typename... MetaExprs> 93 struct DoEval<MetaFun(MetaExprs...)> { 94 #if FRUIT_TRACE_INSTANTIATIONS 95 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 96 return true; 97 } 98 static_assert(static_warning(), ""); 99 #endif 100 using type = typename DoEval<typename std::conditional< 101 StaticOr<SimpleIsError<typename DoEval<MetaExprs>::type>::value...>::value, ExtractFirstError, 102 MetaFun>::type::template apply<typename DoEval<MetaExprs>::type...>::type>::type; 103 }; 104 105 // Similar to the previous specialization, but this will be selected when the function signature 106 // became a function pointer (this happens when a signature parameter is itself a signature). 107 template <typename MetaFun, typename... MetaExprs> 108 struct DoEval<MetaFun (*)(MetaExprs...)> { 109 #if FRUIT_TRACE_INSTANTIATIONS 110 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 111 return true; 112 } 113 static_assert(static_warning(), ""); 114 #endif 115 using type = typename DoEval<typename std::conditional< 116 StaticOr<SimpleIsError<typename DoEval<MetaExprs>::type>::value...>::value, ExtractFirstError, 117 MetaFun>::type::template apply<typename DoEval<MetaExprs>::type...>::type>::type; 118 }; 119 120 #endif // FRUIT_EXTRA_DEBUG 121 122 template <typename ExprResult, typename ErrorTag, typename Handler> 123 struct EvalCatch { 124 using type = ExprResult; 125 }; 126 127 template <typename CaughtErrorTag, typename... ErrorArgs, typename Handler> 128 struct EvalCatch<Error<CaughtErrorTag, ErrorArgs...>, CaughtErrorTag, Handler> { 129 using type = 130 typename DoEval<typename DoEval<Handler>::type::template apply<Error<CaughtErrorTag, ErrorArgs...>>::type>::type; 131 }; 132 133 template <typename ExprResult, typename Handler> 134 struct EvalCatchAll { 135 using type = ExprResult; 136 }; 137 138 template <typename CaughtErrorTag, typename... ErrorArgs, typename Handler> 139 struct EvalCatchAll<Error<CaughtErrorTag, ErrorArgs...>, Handler> { 140 using type = 141 typename DoEval<typename DoEval<Handler>::type::template apply<Error<CaughtErrorTag, ErrorArgs...>>::type>::type; 142 }; 143 144 template <typename Expr, typename ErrorTag, typename Handler> 145 struct DoEval<Catch(Expr, ErrorTag, Handler)> { 146 using type = typename EvalCatch<typename DoEval<Expr>::type, typename DoEval<ErrorTag>::type, Handler>::type; 147 }; 148 149 template <typename Expr, typename ErrorTag, typename Handler> 150 struct DoEval<Catch (*)(Expr, ErrorTag, Handler)> { 151 using type = typename EvalCatch<typename DoEval<Expr>::type, typename DoEval<ErrorTag>::type, Handler>::type; 152 }; 153 154 template <typename Expr, typename Handler> 155 struct DoEval<CatchAll(Expr, Handler)> { 156 using type = typename EvalCatchAll<typename DoEval<Expr>::type, Handler>::type; 157 }; 158 159 template <typename Expr, typename Handler> 160 struct DoEval<CatchAll (*)(Expr, Handler)> { 161 using type = typename EvalCatchAll<typename DoEval<Expr>::type, Handler>::type; 162 }; 163 164 template <typename MetaBool, typename ThenMetaExpr, typename ElseMetaExpr> 165 struct EvalIf; 166 167 template <typename ErrorTag, typename... ErrorArgs, typename ThenMetaExpr, typename ElseMetaExpr> 168 struct EvalIf<Error<ErrorTag, ErrorArgs...>, ThenMetaExpr, ElseMetaExpr> { 169 using type = Error<ErrorTag, ErrorArgs...>; 170 }; 171 172 template <typename ThenMetaExpr, typename ElseMetaExpr> 173 struct EvalIf<Bool<true>, ThenMetaExpr, ElseMetaExpr> { 174 #if FRUIT_TRACE_INSTANTIATIONS 175 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 176 return true; 177 } 178 static_assert(static_warning(), ""); 179 #endif 180 using type = typename DoEval<ThenMetaExpr>::type; 181 }; 182 183 template <typename ThenMetaExpr, typename ElseMetaExpr> 184 struct EvalIf<Bool<false>, ThenMetaExpr, ElseMetaExpr> { 185 #if FRUIT_TRACE_INSTANTIATIONS 186 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 187 return true; 188 } 189 static_assert(static_warning(), ""); 190 #endif 191 using type = typename DoEval<ElseMetaExpr>::type; 192 }; 193 194 template <typename CondMetaExpr, typename ThenMetaExpr, typename ElseMetaExpr> 195 struct DoEval<If(CondMetaExpr, ThenMetaExpr, ElseMetaExpr)> { 196 #if FRUIT_TRACE_INSTANTIATIONS 197 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 198 return true; 199 } 200 static_assert(static_warning(), ""); 201 #endif 202 using type = typename EvalIf<typename DoEval<CondMetaExpr>::type, ThenMetaExpr, ElseMetaExpr>::type; 203 }; 204 205 // Similar to the previous specialization, but this will be selected when the function signature 206 // became a function pointer (this happens when a signature parameter is itself a signature). 207 template <typename CondMetaExpr, typename ThenMetaExpr, typename ElseMetaExpr> 208 struct DoEval<If (*)(CondMetaExpr, ThenMetaExpr, ElseMetaExpr)> { 209 #if FRUIT_TRACE_INSTANTIATIONS 210 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 211 return true; 212 } 213 static_assert(static_warning(), ""); 214 #endif 215 using type = typename EvalIf<typename DoEval<CondMetaExpr>::type, ThenMetaExpr, ElseMetaExpr>::type; 216 }; 217 218 template <typename T, typename ElseMetaExpr> 219 struct EvalPropagateError { 220 using type = typename DoEval<ElseMetaExpr>::type; 221 }; 222 223 template <typename ErrorTag, typename... ErrorArgs, typename ElseMetaExpr> 224 struct EvalPropagateError<Error<ErrorTag, ErrorArgs...>, ElseMetaExpr> { 225 using type = Error<ErrorTag, ErrorArgs...>; 226 }; 227 228 template <typename MaybeErrorMetaExpr, typename ElseMetaExpr> 229 struct DoEval<PropagateError(MaybeErrorMetaExpr, ElseMetaExpr)> { 230 #if FRUIT_TRACE_INSTANTIATIONS 231 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 232 return true; 233 } 234 static_assert(static_warning(), ""); 235 #endif 236 using type = typename EvalPropagateError<typename DoEval<MaybeErrorMetaExpr>::type, ElseMetaExpr>::type; 237 }; 238 239 // Similar to the previous specialization, but this will be selected when the function signature 240 // became a function pointer (this happens when a signature parameter is itself a signature). 241 template <typename MaybeErrorMetaExpr, typename ElseMetaExpr> 242 struct DoEval<PropagateError (*)(MaybeErrorMetaExpr, ElseMetaExpr)> { 243 #if FRUIT_TRACE_INSTANTIATIONS 244 constexpr static bool static_warning() __attribute__((deprecated("static_warning"))) { 245 return true; 246 } 247 static_assert(static_warning(), ""); 248 #endif 249 using type = typename EvalPropagateError<typename DoEval<MaybeErrorMetaExpr>::type, ElseMetaExpr>::type; 250 }; 251 252 template <typename MetaExpr> 253 using Eval = typename DoEval<MetaExpr>::type; 254 255 } // namespace meta 256 } // namespace impl 257 } // namespace fruit 258 259 #endif // FRUIT_META_EVAL_H 260