• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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