Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:55

0001 // Copyright (C) 2016-2018 T. Zachary Laine
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 #ifndef BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
0007 #define BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
0008 
0009 #include <boost/yap/algorithm_fwd.hpp>
0010 
0011 #include <boost/hana/transform.hpp>
0012 
0013 #include <cassert>
0014 
0015 
0016 namespace boost { namespace yap { namespace detail {
0017 
0018     template<int I, typename T, typename... Ts>
0019     struct nth_element_impl
0020     {
0021         using type = typename nth_element_impl<I - 1, Ts...>::type;
0022     };
0023 
0024     template<typename T, typename... Ts>
0025     struct nth_element_impl<0, T, Ts...>
0026     {
0027         using type = T;
0028     };
0029 
0030     template<int I, typename... Ts>
0031     using nth_element = typename nth_element_impl<I, Ts...>::type;
0032 
0033     template<typename T, bool RemoveRefs = std::is_rvalue_reference<T>::value>
0034     struct rvalue_ref_to_value;
0035 
0036     template<typename T>
0037     struct rvalue_ref_to_value<T, true>
0038     {
0039         using type = typename std::remove_reference<T>::type;
0040     };
0041 
0042     template<typename T>
0043     struct rvalue_ref_to_value<T, false>
0044     {
0045         using type = T;
0046     };
0047 
0048     template<typename T>
0049     using rvalue_ref_to_value_t = typename rvalue_ref_to_value<T>::type;
0050 
0051     template<bool IsRvalueRef>
0052     struct rvalue_mover
0053     {
0054         template<typename T>
0055         constexpr decltype(auto) operator()(T && t) const
0056         {
0057             return static_cast<T &&>(t);
0058         }
0059     };
0060 
0061     template<>
0062     struct rvalue_mover<true>
0063     {
0064         template<typename T>
0065         constexpr std::remove_reference_t<T> operator()(T && t) const
0066         {
0067             return std::move(t);
0068         }
0069     };
0070 
0071     template<typename... PlaceholderArgs>
0072     struct placeholder_transform_t
0073     {
0074         using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
0075 
0076         constexpr placeholder_transform_t(PlaceholderArgs &&... args) :
0077             placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
0078         {}
0079 
0080         template<long long I>
0081         constexpr decltype(auto)
0082         operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
0083         {
0084             static_assert(
0085                 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
0086                 "Out of range placeholder index,");
0087             using nth_type = nth_element<I - 1, PlaceholderArgs...>;
0088             return as_expr<minimal_expr>(
0089                 rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
0090                     placeholder_args_[hana::llong<I - 1>{}]));
0091         }
0092 
0093         tuple_t placeholder_args_;
0094     };
0095 
0096     template<typename... PlaceholderArgs>
0097     struct evaluation_transform_t
0098     {
0099         using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
0100 
0101         constexpr evaluation_transform_t(PlaceholderArgs &&... args) :
0102             placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
0103         {}
0104 
0105         template<long long I>
0106         constexpr decltype(auto)
0107         operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
0108         {
0109             static_assert(
0110                 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
0111                 "Out of range placeholder index,");
0112             using nth_type = nth_element<I - 1, PlaceholderArgs...>;
0113             return rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
0114                 placeholder_args_[hana::llong<I - 1>{}]);
0115         }
0116 
0117         template<typename T>
0118         constexpr decltype(auto) operator()(expr_tag<expr_kind::terminal>, T && t) const
0119         {
0120             return static_cast<T &&>(t);
0121         }
0122 
0123 #define BOOST_YAP_UNARY_OPERATOR_CASE(op, op_name)                             \
0124     template<typename T>                                                       \
0125     constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t) const \
0126     {                                                                          \
0127         return op transform(                                                   \
0128             as_expr<minimal_expr>(static_cast<T &&>(t)), *this);               \
0129     }
0130 
0131         BOOST_YAP_UNARY_OPERATOR_CASE(+, unary_plus)
0132         BOOST_YAP_UNARY_OPERATOR_CASE(-, negate)
0133         BOOST_YAP_UNARY_OPERATOR_CASE(*, dereference)
0134         BOOST_YAP_UNARY_OPERATOR_CASE(~, complement)
0135         BOOST_YAP_UNARY_OPERATOR_CASE(&, address_of)
0136         BOOST_YAP_UNARY_OPERATOR_CASE(!, logical_not)
0137         BOOST_YAP_UNARY_OPERATOR_CASE(++, pre_inc)
0138         BOOST_YAP_UNARY_OPERATOR_CASE(--, pre_dec)
0139 
0140         template<typename T>
0141         constexpr decltype(auto) operator()(expr_tag<expr_kind::post_inc>, T && t) const
0142         {
0143             return transform(
0144                 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)++;
0145         }
0146         template<typename T>
0147         constexpr decltype(auto) operator()(expr_tag<expr_kind::post_dec>, T && t) const
0148         {
0149             return transform(
0150                 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)--;
0151         }
0152 
0153 #undef BOOST_YAP_UNARY_OPERATOR_CASE
0154 
0155 #define BOOST_YAP_BINARY_OPERATOR_CASE(op, op_name)                            \
0156     template<typename T, typename U>                                           \
0157     constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t, U && u) const \
0158     {                                                                          \
0159         return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)   \
0160             op transform(as_expr<minimal_expr>(static_cast<U &&>(u)), *this);  \
0161     }
0162 
0163         BOOST_YAP_BINARY_OPERATOR_CASE(<<, shift_left)
0164         BOOST_YAP_BINARY_OPERATOR_CASE(>>, shift_right)
0165         BOOST_YAP_BINARY_OPERATOR_CASE(*, multiplies)
0166         BOOST_YAP_BINARY_OPERATOR_CASE(/, divides)
0167         BOOST_YAP_BINARY_OPERATOR_CASE(%, modulus)
0168         BOOST_YAP_BINARY_OPERATOR_CASE(+, plus)
0169         BOOST_YAP_BINARY_OPERATOR_CASE(-, minus)
0170         BOOST_YAP_BINARY_OPERATOR_CASE(<, less)
0171         BOOST_YAP_BINARY_OPERATOR_CASE(>, greater)
0172         BOOST_YAP_BINARY_OPERATOR_CASE(<=, less_equal)
0173         BOOST_YAP_BINARY_OPERATOR_CASE(>=, greater_equal)
0174         BOOST_YAP_BINARY_OPERATOR_CASE(==, equal_to)
0175         BOOST_YAP_BINARY_OPERATOR_CASE(!=, not_equal_to)
0176         BOOST_YAP_BINARY_OPERATOR_CASE(||, logical_or)
0177         BOOST_YAP_BINARY_OPERATOR_CASE(&&, logical_and)
0178         BOOST_YAP_BINARY_OPERATOR_CASE(&, bitwise_and)
0179         BOOST_YAP_BINARY_OPERATOR_CASE(|, bitwise_or)
0180         BOOST_YAP_BINARY_OPERATOR_CASE (^, bitwise_xor)
0181 
0182         // clang-format off
0183 //[ evaluation_transform_comma
0184         template<typename T, typename U>
0185         constexpr decltype(auto) operator()(expr_tag<expr_kind::comma>, T && t, U && u) const
0186         {
0187             return transform(
0188                        as_expr<minimal_expr>(static_cast<T &&>(t)), *this),
0189                    transform(
0190                        as_expr<minimal_expr>(static_cast<U &&>(u)), *this);
0191         }
0192 //]
0193         // clang-format on
0194 
0195         BOOST_YAP_BINARY_OPERATOR_CASE(->*, mem_ptr)
0196         BOOST_YAP_BINARY_OPERATOR_CASE(=, assign)
0197         BOOST_YAP_BINARY_OPERATOR_CASE(<<=, shift_left_assign)
0198         BOOST_YAP_BINARY_OPERATOR_CASE(>>=, shift_right_assign)
0199         BOOST_YAP_BINARY_OPERATOR_CASE(*=, multiplies_assign)
0200         BOOST_YAP_BINARY_OPERATOR_CASE(/=, divides_assign)
0201         BOOST_YAP_BINARY_OPERATOR_CASE(%=, modulus_assign)
0202         BOOST_YAP_BINARY_OPERATOR_CASE(+=, plus_assign)
0203         BOOST_YAP_BINARY_OPERATOR_CASE(-=, minus_assign)
0204         BOOST_YAP_BINARY_OPERATOR_CASE(&=, bitwise_and_assign)
0205         BOOST_YAP_BINARY_OPERATOR_CASE(|=, bitwise_or_assign)
0206         BOOST_YAP_BINARY_OPERATOR_CASE(^=, bitwise_xor_assign)
0207 
0208         template<typename T, typename U>
0209         constexpr decltype(auto)
0210         operator()(expr_tag<expr_kind::subscript>, T && t, U && u) const
0211         {
0212             return transform(
0213                 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)[transform(
0214                 as_expr<minimal_expr>(static_cast<U &&>(u)), *this)];
0215         }
0216 
0217 #undef BOOST_YAP_BINARY_OPERATOR_CASE
0218 
0219         template<typename T, typename U, typename V>
0220         constexpr decltype(auto)
0221         operator()(expr_tag<expr_kind::if_else>, T && t, U && u, V && v) const
0222         {
0223             return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)
0224                        ? transform(
0225                              as_expr<minimal_expr>(static_cast<U &&>(u)), *this)
0226                        : transform(
0227                              as_expr<minimal_expr>(static_cast<V &&>(v)),
0228                              *this);
0229         }
0230 
0231         // clang-format off
0232 //[ evaluation_transform_call
0233         template<typename Callable, typename... Args>
0234         constexpr decltype(auto) operator()(
0235             expr_tag<expr_kind::call>, Callable && callable, Args &&... args) const
0236         {
0237             return transform(as_expr<minimal_expr>(static_cast<Callable &&>(callable)), *this)(
0238                 transform(as_expr<minimal_expr>(static_cast<Args &&>(args)), *this)...
0239             );
0240         }
0241 //]
0242         // clang-format on
0243 
0244         tuple_t placeholder_args_;
0245     };
0246 
0247 
0248     template<bool Strict, int I, bool IsExprRef>
0249     struct transform_impl;
0250 
0251     template<
0252         bool Strict,
0253         typename Expr,
0254         typename TransformTuple,
0255         int I,
0256         expr_arity Arity,
0257         typename = void_t<>>
0258     struct transform_expression_tag;
0259 
0260 
0261     // Forward terminals/recurively transform noterminasl; attempted last.
0262 
0263     template<bool IsLvalueRef, bool IsTerminal, bool Strict>
0264     struct default_transform
0265     {
0266         template<typename Expr, typename TransformTuple>
0267         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0268         {
0269             return static_cast<Expr &&>(expr);
0270         }
0271     };
0272 
0273     template<bool IsLvalueRef, bool IsTerminal>
0274     struct default_transform<IsLvalueRef, IsTerminal, true>
0275     {
0276         struct incomplete;
0277 
0278         // If you're getting an error because this function is uncallable,
0279         // that's by design.  You called yap::transform_strict(expr, xfrom)
0280         // and one or more subexpression of 'expr' are not callable with any
0281         // overload in 'xform'.
0282         template<typename Expr, typename TransformTuple>
0283         constexpr incomplete operator()(Expr && expr, TransformTuple transforms) const;
0284     };
0285 
0286     template<
0287         expr_kind Kind,
0288         template<expr_kind, class> class ExprTemplate,
0289         typename OldTuple,
0290         typename NewTuple>
0291     constexpr auto make_expr_from_tuple(
0292         ExprTemplate<Kind, OldTuple> const & expr, NewTuple && tuple)
0293     {
0294         return ExprTemplate<Kind, NewTuple>{std::move(tuple)};
0295     }
0296 
0297     template<expr_kind Kind, typename Expr, typename NewTuple>
0298     constexpr auto make_expr_from_tuple(Expr const & expr, NewTuple && tuple)
0299     {
0300         return minimal_expr<Kind, NewTuple>{std::move(tuple)};
0301     }
0302 
0303     template<typename Expr, typename Tuple, typename TransformTuple>
0304     constexpr decltype(auto) transform_nonterminal(
0305         Expr const & expr, Tuple && tuple, TransformTuple transforms)
0306     {
0307         auto transformed_tuple =
0308             hana::transform(static_cast<Tuple &&>(tuple), [&](auto && element) {
0309                 using element_t = decltype(element);
0310                 auto const kind = remove_cv_ref_t<element_t>::kind;
0311                 ::boost::yap::detail::
0312                     transform_impl<false, 0, kind == expr_kind::expr_ref>
0313                         xform;
0314                 return xform(static_cast<element_t &&>(element), transforms);
0315             });
0316         auto const kind = remove_cv_ref_t<Expr>::kind;
0317         return make_expr_from_tuple<kind>(expr, std::move(transformed_tuple));
0318     }
0319 
0320     template<>
0321     struct default_transform<true, false, false>
0322     {
0323         template<typename Expr, typename TransformTuple>
0324         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0325         {
0326             return transform_nonterminal(expr, expr.elements, transforms);
0327         }
0328     };
0329 
0330     template<>
0331     struct default_transform<false, false, false>
0332     {
0333         template<typename Expr, typename TransformTuple>
0334         constexpr decltype(auto)
0335         operator()(Expr && expr, TransformTuple transforms) const
0336         {
0337             return transform_nonterminal(
0338                 expr, std::move(expr.elements), transforms);
0339         }
0340     };
0341 
0342     // Dispatch to the next transform, or to the default transform if there is
0343     // no next transform.
0344 
0345     template<
0346         bool Strict,
0347         typename Expr,
0348         typename TransformTuple,
0349         int I,
0350         bool NextTransformExists>
0351     struct next_or_default_transform
0352     {
0353         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0354         {
0355             // Use the next transform.
0356             constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
0357             return detail::
0358                 transform_impl<Strict, I + 1, kind == expr_kind::expr_ref>{}(
0359                     static_cast<Expr &&>(expr), transforms);
0360         }
0361     };
0362 
0363     template<bool Strict, typename Expr, typename TransformTuple, int I>
0364     struct next_or_default_transform<Strict, Expr, TransformTuple, I, false>
0365     {
0366         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0367         {
0368             // No next transform exists; use the default transform.
0369             constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
0370             return default_transform<
0371                 std::is_lvalue_reference<Expr>::value,
0372                 kind == expr_kind::terminal,
0373                 Strict>{}(static_cast<Expr &&>(expr), transforms);
0374         }
0375     };
0376 
0377     // Expression-matching; attempted second.
0378 
0379     template<
0380         bool Strict,
0381         typename Expr,
0382         typename TransformTuple,
0383         int I,
0384         typename = detail::void_t<>>
0385     struct transform_expression_expr
0386     {
0387         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0388         {
0389             // No expr-matching succeeded; use the next or default transform.
0390             return next_or_default_transform<
0391                 Strict,
0392                 Expr,
0393                 TransformTuple,
0394                 I,
0395                 I + 1 < decltype(hana::size(
0396                             std::declval<TransformTuple>()))::value>{}(
0397                 static_cast<Expr &&>(expr), transforms);
0398         }
0399     };
0400 
0401     template<bool Strict, typename Expr, typename TransformTuple, int I>
0402     struct transform_expression_expr<
0403         Strict,
0404         Expr,
0405         TransformTuple,
0406         I,
0407         void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0408             std::declval<Expr>()))>>
0409     {
0410         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0411         {
0412             return (*transforms[hana::llong<I>{}])(static_cast<Expr &&>(expr));
0413         }
0414     };
0415 
0416 
0417     // Tag-matching; attempted first.
0418 
0419     template<
0420         bool Strict,
0421         typename Expr,
0422         typename TransformTuple,
0423         int I,
0424         expr_arity Arity,
0425         typename>
0426     struct transform_expression_tag
0427     {
0428         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0429         {
0430             // No tag-matching succeeded; try expr-matching.
0431             return transform_expression_expr<Strict, Expr, TransformTuple, I>{}(
0432                 static_cast<Expr &&>(expr), transforms);
0433         }
0434     };
0435 
0436     template<typename T>
0437     constexpr decltype(auto) terminal_value(T && x)
0438     {
0439         return value_impl<true>(static_cast<T &&>(x));
0440     }
0441 
0442 
0443     template<bool Strict, typename Expr, typename TransformTuple, int I>
0444     struct transform_expression_tag<
0445         Strict,
0446         Expr,
0447         TransformTuple,
0448         I,
0449         expr_arity::one,
0450         void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0451             expr_tag<remove_cv_ref_t<Expr>::kind>{},
0452             terminal_value(::boost::yap::value(std::declval<Expr>()))))>>
0453     {
0454         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0455         {
0456             return (*transforms[hana::llong<I>{}])(
0457                 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0458                 terminal_value(
0459                     ::boost::yap::value(static_cast<Expr &&>(expr))));
0460         }
0461     };
0462 
0463     template<bool Strict, typename Expr, typename TransformTuple, int I>
0464     struct transform_expression_tag<
0465         Strict,
0466         Expr,
0467         TransformTuple,
0468         I,
0469         expr_arity::two,
0470         void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0471             expr_tag<remove_cv_ref_t<Expr>::kind>{},
0472             terminal_value(::boost::yap::left(std::declval<Expr>())),
0473             terminal_value(::boost::yap::right(std::declval<Expr>()))))>>
0474     {
0475         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0476         {
0477             return (*transforms[hana::llong<I>{}])(
0478                 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0479                 terminal_value(::boost::yap::left(static_cast<Expr &&>(expr))),
0480                 terminal_value(
0481                     ::boost::yap::right(static_cast<Expr &&>(expr))));
0482         }
0483     };
0484 
0485     template<bool Strict, typename Expr, typename TransformTuple, int I>
0486     struct transform_expression_tag<
0487         Strict,
0488         Expr,
0489         TransformTuple,
0490         I,
0491         expr_arity::three,
0492         void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0493             expr_tag<remove_cv_ref_t<Expr>::kind>{},
0494             terminal_value(::boost::yap::cond(std::declval<Expr>())),
0495             terminal_value(::boost::yap::then(std::declval<Expr>())),
0496             terminal_value(::boost::yap::else_(std::declval<Expr>()))))>>
0497     {
0498         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0499         {
0500             return (*transforms[hana::llong<I>{}])(
0501                 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0502                 terminal_value(::boost::yap::cond(static_cast<Expr &&>(expr))),
0503                 terminal_value(::boost::yap::then(static_cast<Expr &&>(expr))),
0504                 terminal_value(
0505                     ::boost::yap::else_(static_cast<Expr &&>(expr))));
0506         }
0507     };
0508 
0509     template<typename Expr, typename Transform>
0510     struct transform_call_unpacker
0511     {
0512         template<long long... I>
0513         constexpr auto operator()(
0514             Expr && expr,
0515             Transform & transform,
0516             std::integer_sequence<long long, I...>) const
0517             -> decltype(transform(
0518                 expr_tag<expr_kind::call>{},
0519                 terminal_value(::boost::yap::get(
0520                     static_cast<Expr &&>(expr), hana::llong_c<I>))...))
0521         {
0522             return transform(
0523                 expr_tag<expr_kind::call>{},
0524                 terminal_value(::boost::yap::get(
0525                     static_cast<Expr &&>(expr), hana::llong_c<I>))...);
0526         }
0527     };
0528 
0529     template<typename Expr>
0530     constexpr auto indices_for(Expr const & expr)
0531     {
0532         constexpr long long size = decltype(hana::size(expr.elements))::value;
0533         return std::make_integer_sequence<long long, size>();
0534     }
0535 
0536     template<bool Strict, typename Expr, typename TransformTuple, int I>
0537     struct transform_expression_tag<
0538         Strict,
0539         Expr,
0540         TransformTuple,
0541         I,
0542         expr_arity::n,
0543         void_t<decltype(
0544             transform_call_unpacker<
0545                 Expr,
0546                 decltype(*std::declval<TransformTuple>()[hana::llong<I>{}])>{}(
0547                 std::declval<Expr>(),
0548                 *std::declval<TransformTuple>()[hana::llong<I>{}],
0549                 indices_for(std::declval<Expr>())))>>
0550     {
0551         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0552         {
0553             using transform_t = decltype(*transforms[hana::llong<I>{}]);
0554             return transform_call_unpacker<Expr, transform_t>{}(
0555                 static_cast<Expr &&>(expr),
0556                 *transforms[hana::llong<I>{}],
0557                 indices_for(expr));
0558         }
0559     };
0560 
0561     template<bool Strict, int I, bool IsExprRef>
0562     struct transform_impl
0563     {
0564         template<typename Expr, typename TransformTuple>
0565         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0566         {
0567             constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0568             return detail::transform_expression_tag<
0569                 Strict,
0570                 Expr,
0571                 TransformTuple,
0572                 I,
0573                 detail::arity_of<kind>()>{}(
0574                 static_cast<Expr &&>(expr), transforms);
0575         }
0576     };
0577 
0578     template<bool Strict, int I>
0579     struct transform_impl<Strict, I, true>
0580     {
0581         template<typename Expr, typename TransformTuple>
0582         constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0583         {
0584             return detail::transform_impl<Strict, I, false>{}(
0585                 ::boost::yap::deref(static_cast<Expr &&>(expr)), transforms);
0586         }
0587     };
0588 
0589 }}}
0590 
0591 #endif