• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016-2018 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
7 #define BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
8 
9 #include <boost/yap/algorithm_fwd.hpp>
10 
11 #include <boost/hana/size.hpp>
12 #include <boost/hana/tuple.hpp>
13 
14 #include <memory>
15 #include <type_traits>
16 
17 
18 namespace boost { namespace yap { namespace detail {
19 
20     // static_const
21 
22     template<typename T>
23     struct static_const
24     {
25         static constexpr T value{};
26     };
27 
28     template<typename T>
29     constexpr T static_const<T>::value;
30 
31 
32     // partial_decay
33 
34     template<typename T>
35     struct partial_decay
36     {
37         using type = T;
38     };
39 
40     template<typename T>
41     struct partial_decay<T[]>
42     {
43         using type = T *;
44     };
45     template<typename T, std::size_t N>
46     struct partial_decay<T[N]>
47     {
48         using type = T *;
49     };
50 
51     template<typename T>
52     struct partial_decay<T (&)[]>
53     {
54         using type = T *;
55     };
56     template<typename T, std::size_t N>
57     struct partial_decay<T (&)[N]>
58     {
59         using type = T *;
60     };
61 
62     template<typename R, typename... A>
63     struct partial_decay<R(A...)>
64     {
65         using type = R (*)(A...);
66     };
67     template<typename R, typename... A>
68     struct partial_decay<R(A..., ...)>
69     {
70         using type = R (*)(A..., ...);
71     };
72 
73     template<typename R, typename... A>
74     struct partial_decay<R (&)(A...)>
75     {
76         using type = R (*)(A...);
77     };
78     template<typename R, typename... A>
79     struct partial_decay<R (&)(A..., ...)>
80     {
81         using type = R (*)(A..., ...);
82     };
83 
84     template<typename R, typename... A>
85     struct partial_decay<R (*&)(A...)>
86     {
87         using type = R (*)(A...);
88     };
89     template<typename R, typename... A>
90     struct partial_decay<R (*&)(A..., ...)>
91     {
92         using type = R (*)(A..., ...);
93     };
94 
95 
96     // operand_value_type_phase_1
97 
98     template<
99         typename T,
100         typename U = typename detail::partial_decay<T>::type,
101         bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value>
102     struct operand_value_type_phase_1;
103 
104     template<typename T, typename U>
105     struct operand_value_type_phase_1<T, U, true>
106     {
107         using type = U &&;
108     };
109 
110     template<typename T, typename U>
111     struct operand_value_type_phase_1<T, U, false>
112     {
113         using type = U;
114     };
115 
116 
117     // expr_ref
118 
119     template<template<expr_kind, class> class ExprTemplate, typename T>
120     struct expr_ref
121     {
122         using type = expression_ref<ExprTemplate, T>;
123     };
124 
125     template<template<expr_kind, class> class ExprTemplate, typename Tuple>
126     struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &>
127     {
128         using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
129     };
130 
131     template<template<expr_kind, class> class ExprTemplate, typename Tuple>
132     struct expr_ref<
133         ExprTemplate,
134         ExprTemplate<expr_kind::expr_ref, Tuple> const &>
135     {
136         using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
137     };
138 
139     template<template<expr_kind, class> class ExprTemplate, typename T>
140     using expr_ref_t = typename expr_ref<ExprTemplate, T>::type;
141 
142     template<template<expr_kind, class> class ExprTemplate, typename T>
143     struct expr_ref_tuple;
144 
145     template<template<expr_kind, class> class ExprTemplate, typename Tuple>
146     struct expr_ref_tuple<
147         ExprTemplate,
148         ExprTemplate<expr_kind::expr_ref, Tuple>>
149     {
150         using type = Tuple;
151     };
152 
153     template<template<expr_kind, class> class ExprTemplate, typename T>
154     using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type;
155 
156 
157     // operand_type
158 
159     template<
160         template<expr_kind, class> class ExprTemplate,
161         typename T,
162         typename U = typename operand_value_type_phase_1<T>::type,
163         bool RemoveRefs = std::is_rvalue_reference<U>::value,
164         bool IsExpr = is_expr<T>::value,
165         bool IsLRef = std::is_lvalue_reference<T>::value>
166     struct operand_type;
167 
168     template<
169         template<expr_kind, class> class ExprTemplate,
170         typename T,
171         typename U,
172         bool RemoveRefs>
173     struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false>
174     {
175         using type = remove_cv_ref_t<T>;
176     };
177 
178     template<
179         template<expr_kind, class> class ExprTemplate,
180         typename T,
181         typename U,
182         bool RemoveRefs>
183     struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true>
184     {
185         using type = expr_ref_t<ExprTemplate, T>;
186     };
187 
188     template<
189         template<expr_kind, class> class ExprTemplate,
190         typename T,
191         typename U,
192         bool RemoveRefs,
193         bool IsLRef>
194     struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef>
195     {
196         using type = remove_cv_ref_t<T>;
197     };
198 
199     template<
200         template<expr_kind, class> class ExprTemplate,
201         typename T,
202         typename U,
203         bool IsLRef>
204     struct operand_type<ExprTemplate, T, U, true, false, IsLRef>
205     {
206         using type = terminal<ExprTemplate, std::remove_reference_t<U>>;
207     };
208 
209     template<
210         template<expr_kind, class> class ExprTemplate,
211         typename T,
212         typename U,
213         bool IsLRef>
214     struct operand_type<ExprTemplate, T, U, false, false, IsLRef>
215     {
216         using type = terminal<ExprTemplate, U>;
217     };
218 
219     template<template<expr_kind, class> class ExprTemplate, typename T>
220     using operand_type_t = typename operand_type<ExprTemplate, T>::type;
221 
222 
223     // make_operand
224 
225     template<typename T>
226     struct make_operand
227     {
228         template<typename U>
operator ()boost::yap::detail::make_operand229         constexpr auto operator()(U && u)
230         {
231             return T{static_cast<U &&>(u)};
232         }
233     };
234 
235     template<template<expr_kind, class> class ExprTemplate, typename Tuple>
236     struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>>
237     {
operator ()boost::yap::detail::make_operand238         constexpr auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr)
239         {
240             return expr;
241         }
242 
243         template<typename U>
operator ()boost::yap::detail::make_operand244         constexpr auto operator()(U && u)
245         {
246             return ExprTemplate<expr_kind::expr_ref, Tuple>{
247                 Tuple{std::addressof(u)}};
248         }
249     };
250 
251 
252     // free_binary_op_result
253 
254     template<
255         template<expr_kind, class> class ExprTemplate,
256         expr_kind OpKind,
257         typename T,
258         typename U,
259         bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value,
260         bool ULvalueRef = std::is_lvalue_reference<U>::value>
261     struct free_binary_op_result;
262 
263     template<
264         template<expr_kind, class> class ExprTemplate,
265         expr_kind OpKind,
266         typename T,
267         typename U>
268     struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true>
269     {
270         using lhs_type = operand_type_t<ExprTemplate, T>;
271         using rhs_type = expr_ref_t<ExprTemplate, U>;
272         using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>;
273         using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
274     };
275 
276     template<
277         template<expr_kind, class> class ExprTemplate,
278         expr_kind OpKind,
279         typename T,
280         typename U>
281     struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false>
282     {
283         using lhs_type = operand_type_t<ExprTemplate, T>;
284         using rhs_type = remove_cv_ref_t<U>;
285         using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
286     };
287 
288     template<
289         template<expr_kind, class> class ExprTemplate,
290         expr_kind OpKind,
291         typename T,
292         typename U>
293     using free_binary_op_result_t =
294         typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type;
295 
296 
297     // ternary_op_result
298 
299     template<
300         template<expr_kind, class> class ExprTemplate,
301         typename T,
302         typename U,
303         typename V,
304         bool Valid =
305             is_expr<T>::value || is_expr<U>::value || is_expr<V>::value>
306     struct ternary_op_result;
307 
308     template<
309         template<expr_kind, class> class ExprTemplate,
310         typename T,
311         typename U,
312         typename V>
313     struct ternary_op_result<ExprTemplate, T, U, V, true>
314     {
315         using cond_type = operand_type_t<ExprTemplate, T>;
316         using then_type = operand_type_t<ExprTemplate, U>;
317         using else_type = operand_type_t<ExprTemplate, V>;
318         using type = ExprTemplate<
319             expr_kind::if_else,
320             hana::tuple<cond_type, then_type, else_type>>;
321     };
322 
323     template<
324         template<expr_kind, class> class ExprTemplate,
325         typename T,
326         typename U,
327         typename V>
328     using ternary_op_result_t =
329         typename ternary_op_result<ExprTemplate, T, U, V>::type;
330 
331 
332     // udt_any_ternary_op_result
333 
334     template<
335         template<expr_kind, class> class ExprTemplate,
336         typename T,
337         typename U,
338         typename V,
339         template<class> class UdtTrait,
340         bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
341                      !is_expr<V>::value &&
342                      (UdtTrait<remove_cv_ref_t<T>>::value ||
343                       UdtTrait<remove_cv_ref_t<U>>::value ||
344                       UdtTrait<remove_cv_ref_t<V>>::value)>
345     struct udt_any_ternary_op_result;
346 
347     template<
348         template<expr_kind, class> class ExprTemplate,
349         typename T,
350         typename U,
351         typename V,
352         template<class> class UdtTrait>
353     struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true>
354     {
355         using cond_type = operand_type_t<ExprTemplate, T>;
356         using then_type = operand_type_t<ExprTemplate, U>;
357         using else_type = operand_type_t<ExprTemplate, V>;
358         using type = ExprTemplate<
359             expr_kind::if_else,
360             hana::tuple<cond_type, then_type, else_type>>;
361     };
362 
363     template<
364         template<expr_kind, class> class ExprTemplate,
365         typename T,
366         typename U,
367         typename V,
368         template<class> class UdtTrait>
369     using udt_any_ternary_op_result_t =
370         typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>::
371             type;
372 
373 
374     // udt_unary_op_result
375 
376     template<
377         template<expr_kind, class> class ExprTemplate,
378         expr_kind OpKind,
379         typename T,
380         template<class> class UdtTrait,
381         bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value>
382     struct udt_unary_op_result;
383 
384     template<
385         template<expr_kind, class> class ExprTemplate,
386         expr_kind OpKind,
387         typename T,
388         template<class> class UdtTrait>
389     struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true>
390     {
391         using x_type = operand_type_t<ExprTemplate, T>;
392         using type = ExprTemplate<OpKind, hana::tuple<x_type>>;
393     };
394 
395     template<
396         template<expr_kind, class> class ExprTemplate,
397         expr_kind OpKind,
398         typename T,
399         template<class> class UdtTrait>
400     using udt_unary_op_result_t =
401         typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type;
402 
403 
404     // udt_udt_binary_op_result
405 
406     template<typename T, template<class> class UdtTrait>
407     struct is_udt_arg
408     {
409         static bool const value =
410             !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value;
411     };
412 
413     template<
414         template<expr_kind, class> class ExprTemplate,
415         expr_kind OpKind,
416         typename T,
417         typename U,
418         template<class> class TUdtTrait,
419         template<class> class UUdtTrait,
420         bool Valid =
421             is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value>
422     struct udt_udt_binary_op_result;
423 
424     template<
425         template<expr_kind, class> class ExprTemplate,
426         expr_kind OpKind,
427         typename T,
428         typename U,
429         template<class> class TUdtTrait,
430         template<class> class UUdtTrait>
431     struct udt_udt_binary_op_result<
432         ExprTemplate,
433         OpKind,
434         T,
435         U,
436         TUdtTrait,
437         UUdtTrait,
438         true>
439     {
440         using lhs_type = operand_type_t<ExprTemplate, T>;
441         using rhs_type = operand_type_t<ExprTemplate, U>;
442         using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
443     };
444 
445     template<
446         template<expr_kind, class> class ExprTemplate,
447         expr_kind OpKind,
448         typename T,
449         typename U,
450         template<class> class TUdtTrait,
451         template<class> class UUdtTrait>
452     using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result<
453         ExprTemplate,
454         OpKind,
455         T,
456         U,
457         TUdtTrait,
458         UUdtTrait>::type;
459 
460 
461     // udt_any_binary_op_result
462 
463     template<
464         template<expr_kind, class> class ExprTemplate,
465         expr_kind OpKind,
466         typename T,
467         typename U,
468         template<class> class UdtTrait,
469         bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
470                      (UdtTrait<remove_cv_ref_t<T>>::value ||
471                       UdtTrait<remove_cv_ref_t<U>>::value)>
472     struct udt_any_binary_op_result;
473 
474     template<
475         template<expr_kind, class> class ExprTemplate,
476         expr_kind OpKind,
477         typename T,
478         typename U,
479         template<class> class UdtTrait>
480     struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true>
481     {
482         using lhs_type = operand_type_t<ExprTemplate, T>;
483         using rhs_type = operand_type_t<ExprTemplate, U>;
484         using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
485     };
486 
487     template<
488         template<expr_kind, class> class ExprTemplate,
489         expr_kind OpKind,
490         typename T,
491         typename U,
492         template<class> class UdtTrait>
493     using udt_any_binary_op_result_t = typename udt_any_binary_op_result<
494         ExprTemplate,
495         OpKind,
496         T,
497         U,
498         UdtTrait>::type;
499 
500 
501     // not_copy_or_move
502 
503     template<typename LeftT, typename RightT>
504     struct copy_or_move : std::false_type
505     {
506     };
507 
508     template<typename T>
509     struct copy_or_move<T, T const &> : std::true_type
510     {
511     };
512 
513     template<typename T>
514     struct copy_or_move<T, T &> : std::true_type
515     {
516     };
517 
518     template<typename T>
519     struct copy_or_move<T, T &&> : std::true_type
520     {
521     };
522 
523 
524     // expr_arity
525 
526     enum class expr_arity { invalid, one, two, three, n };
527 
528     template<expr_kind Kind>
arity_of()529     constexpr expr_arity arity_of()
530     {
531         switch (Kind) {
532         case expr_kind::expr_ref:
533 
534         case expr_kind::terminal:
535 
536         // unary
537         case expr_kind::unary_plus:  // +
538         case expr_kind::negate:      // -
539         case expr_kind::dereference: // *
540         case expr_kind::complement:  // ~
541         case expr_kind::address_of:  // &
542         case expr_kind::logical_not: // !
543         case expr_kind::pre_inc:     // ++
544         case expr_kind::pre_dec:     // --
545         case expr_kind::post_inc:    // ++(int)
546         case expr_kind::post_dec:    // --(int)
547             return expr_arity::one;
548 
549         // binary
550         case expr_kind::shift_left:         // <<
551         case expr_kind::shift_right:        // >>
552         case expr_kind::multiplies:         // *
553         case expr_kind::divides:            // /
554         case expr_kind::modulus:            // %
555         case expr_kind::plus:               // +
556         case expr_kind::minus:              // -
557         case expr_kind::less:               // <
558         case expr_kind::greater:            // >
559         case expr_kind::less_equal:         // <=
560         case expr_kind::greater_equal:      // >=
561         case expr_kind::equal_to:           // ==
562         case expr_kind::not_equal_to:       // !=
563         case expr_kind::logical_or:         // ||
564         case expr_kind::logical_and:        // &&
565         case expr_kind::bitwise_and:        // &
566         case expr_kind::bitwise_or:         // |
567         case expr_kind::bitwise_xor:        // ^
568         case expr_kind::comma:              // :
569         case expr_kind::mem_ptr:            // ->*
570         case expr_kind::assign:             // =
571         case expr_kind::shift_left_assign:  // <<=
572         case expr_kind::shift_right_assign: // >>=
573         case expr_kind::multiplies_assign:  // *=
574         case expr_kind::divides_assign:     // /=
575         case expr_kind::modulus_assign:     // %=
576         case expr_kind::plus_assign:        // +=
577         case expr_kind::minus_assign:       // -=
578         case expr_kind::bitwise_and_assign: // &=
579         case expr_kind::bitwise_or_assign:  // |=
580         case expr_kind::bitwise_xor_assign: // ^=
581         case expr_kind::subscript:          // []
582             return expr_arity::two;
583 
584         // ternary
585         case expr_kind::if_else: // (analogous to) ?:
586             return expr_arity::three;
587 
588         // n-ary
589         case expr_kind::call: // ()
590             return expr_arity::n;
591 
592         default: return expr_arity::invalid;
593         }
594     }
595 
596 }}}
597 
598 #endif
599