Home | History | Annotate | Download | only in meta
      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
     37   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