| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 | // Copyright (C) 2016-2018 T. Zachary Laine//// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED#define BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED#include <boost/yap/algorithm_fwd.hpp>#include <boost/hana/transform.hpp>#include <cassert>namespace boost { namespace yap { namespace detail {    template<int I, typename T, typename... Ts>    struct nth_element_impl    {        using type = typename nth_element_impl<I - 1, Ts...>::type;    };    template<typename T, typename... Ts>    struct nth_element_impl<0, T, Ts...>    {        using type = T;    };    template<int I, typename... Ts>    using nth_element = typename nth_element_impl<I, Ts...>::type;    template<typename T, bool RemoveRefs = std::is_rvalue_reference<T>::value>    struct rvalue_ref_to_value;    template<typename T>    struct rvalue_ref_to_value<T, true>    {        using type = typename std::remove_reference<T>::type;    };    template<typename T>    struct rvalue_ref_to_value<T, false>    {        using type = T;    };    template<typename T>    using rvalue_ref_to_value_t = typename rvalue_ref_to_value<T>::type;    template<bool IsRvalueRef>    struct rvalue_mover    {        template<typename T>        constexpr decltype(auto) operator()(T && t) const        {            return static_cast<T &&>(t);        }    };    template<>    struct rvalue_mover<true>    {        template<typename T>        constexpr std::remove_reference_t<T> operator()(T && t) const        {            return std::move(t);        }    };    template<typename... PlaceholderArgs>    struct placeholder_transform_t    {        using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;        placeholder_transform_t(PlaceholderArgs &&... args) :            placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)        {}        template<long long I>        constexpr decltype(auto)        operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const        {            static_assert(                I <= decltype(hana::size(std::declval<tuple_t>()))::value,                "Out of range placeholder index,");            using nth_type = nth_element<I - 1, PlaceholderArgs...>;            return as_expr<minimal_expr>(                rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(                    placeholder_args_[hana::llong<I - 1>{}]));        }        tuple_t placeholder_args_;    };    template<typename... PlaceholderArgs>    struct evaluation_transform_t    {        using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;        constexpr evaluation_transform_t(PlaceholderArgs &&... args) :            placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)        {}        template<long long I>        constexpr decltype(auto)        operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const        {            static_assert(                I <= decltype(hana::size(std::declval<tuple_t>()))::value,                "Out of range placeholder index,");            using nth_type = nth_element<I - 1, PlaceholderArgs...>;            return rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(                placeholder_args_[hana::llong<I - 1>{}]);        }        template<typename T>        constexpr decltype(auto) operator()(expr_tag<expr_kind::terminal>, T && t) const        {            return static_cast<T &&>(t);        }#define BOOST_YAP_UNARY_OPERATOR_CASE(op, op_name)                             \    template<typename T>                                                       \    constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t) const \    {                                                                          \        return op transform(                                                   \            as_expr<minimal_expr>(static_cast<T &&>(t)), *this);               \    }        BOOST_YAP_UNARY_OPERATOR_CASE(+, unary_plus)        BOOST_YAP_UNARY_OPERATOR_CASE(-, negate)        BOOST_YAP_UNARY_OPERATOR_CASE(*, dereference)        BOOST_YAP_UNARY_OPERATOR_CASE(~, complement)        BOOST_YAP_UNARY_OPERATOR_CASE(&, address_of)        BOOST_YAP_UNARY_OPERATOR_CASE(!, logical_not)        BOOST_YAP_UNARY_OPERATOR_CASE(++, pre_inc)        BOOST_YAP_UNARY_OPERATOR_CASE(--, pre_dec)        template<typename T>        constexpr decltype(auto) operator()(expr_tag<expr_kind::post_inc>, T && t) const        {            return transform(                as_expr<minimal_expr>(static_cast<T &&>(t)), *this)++;        }        template<typename T>        constexpr decltype(auto) operator()(expr_tag<expr_kind::post_dec>, T && t) const        {            return transform(                as_expr<minimal_expr>(static_cast<T &&>(t)), *this)--;        }#undef BOOST_YAP_UNARY_OPERATOR_CASE#define BOOST_YAP_BINARY_OPERATOR_CASE(op, op_name)                            \    template<typename T, typename U>                                           \    constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t, U && u) const \    {                                                                          \        return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)   \            op transform(as_expr<minimal_expr>(static_cast<U &&>(u)), *this);  \    }        BOOST_YAP_BINARY_OPERATOR_CASE(<<, shift_left)        BOOST_YAP_BINARY_OPERATOR_CASE(>>, shift_right)        BOOST_YAP_BINARY_OPERATOR_CASE(*, multiplies)        BOOST_YAP_BINARY_OPERATOR_CASE(/, divides)        BOOST_YAP_BINARY_OPERATOR_CASE(%, modulus)        BOOST_YAP_BINARY_OPERATOR_CASE(+, plus)        BOOST_YAP_BINARY_OPERATOR_CASE(-, minus)        BOOST_YAP_BINARY_OPERATOR_CASE(<, less)        BOOST_YAP_BINARY_OPERATOR_CASE(>, greater)        BOOST_YAP_BINARY_OPERATOR_CASE(<=, less_equal)        BOOST_YAP_BINARY_OPERATOR_CASE(>=, greater_equal)        BOOST_YAP_BINARY_OPERATOR_CASE(==, equal_to)        BOOST_YAP_BINARY_OPERATOR_CASE(!=, not_equal_to)        BOOST_YAP_BINARY_OPERATOR_CASE(||, logical_or)        BOOST_YAP_BINARY_OPERATOR_CASE(&&, logical_and)        BOOST_YAP_BINARY_OPERATOR_CASE(&, bitwise_and)        BOOST_YAP_BINARY_OPERATOR_CASE(|, bitwise_or)        BOOST_YAP_BINARY_OPERATOR_CASE (^, bitwise_xor)        // clang-format off//[ evaluation_transform_comma        template<typename T, typename U>        constexpr decltype(auto) operator()(expr_tag<expr_kind::comma>, T && t, U && u) const        {            return transform(                       as_expr<minimal_expr>(static_cast<T &&>(t)), *this),                   transform(                       as_expr<minimal_expr>(static_cast<U &&>(u)), *this);        }//]        // clang-format on        BOOST_YAP_BINARY_OPERATOR_CASE(->*, mem_ptr)        BOOST_YAP_BINARY_OPERATOR_CASE(=, assign)        BOOST_YAP_BINARY_OPERATOR_CASE(<<=, shift_left_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(>>=, shift_right_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(*=, multiplies_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(/=, divides_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(%=, modulus_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(+=, plus_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(-=, minus_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(&=, bitwise_and_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(|=, bitwise_or_assign)        BOOST_YAP_BINARY_OPERATOR_CASE(^=, bitwise_xor_assign)        template<typename T, typename U>        constexpr decltype(auto)        operator()(expr_tag<expr_kind::subscript>, T && t, U && u) const        {            return transform(                as_expr<minimal_expr>(static_cast<T &&>(t)), *this)[transform(                as_expr<minimal_expr>(static_cast<U &&>(u)), *this)];        }#undef BOOST_YAP_BINARY_OPERATOR_CASE        template<typename T, typename U, typename V>        constexpr decltype(auto)        operator()(expr_tag<expr_kind::if_else>, T && t, U && u, V && v) const        {            return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)                       ? transform(                             as_expr<minimal_expr>(static_cast<U &&>(u)), *this)                       : transform(                             as_expr<minimal_expr>(static_cast<V &&>(v)),                             *this);        }        // clang-format off//[ evaluation_transform_call        template<typename Callable, typename... Args>        constexpr decltype(auto) operator()(            expr_tag<expr_kind::call>, Callable && callable, Args &&... args) const        {            return transform(as_expr<minimal_expr>(static_cast<Callable &&>(callable)), *this)(                transform(as_expr<minimal_expr>(static_cast<Args &&>(args)), *this)...            );        }//]        // clang-format on        tuple_t placeholder_args_;    };    template<bool Strict, int I, bool IsExprRef>    struct transform_impl;    template<        bool Strict,        typename Expr,        typename TransformTuple,        int I,        expr_arity Arity,        typename = void_t<>>    struct transform_expression_tag;    // Forward terminals/recurively transform noterminasl; attempted last.    template<bool IsLvalueRef, bool IsTerminal, bool Strict>    struct default_transform    {        template<typename Expr, typename TransformTuple>        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return static_cast<Expr &&>(expr);        }    };    template<bool IsLvalueRef, bool IsTerminal>    struct default_transform<IsLvalueRef, IsTerminal, true>    {        struct incomplete;        // If you're getting an error because this function is uncallable,        // that's by design.  You called yap::transform_strict(expr, xfrom)        // and one or more subexpression of 'expr' are not callable with any        // overload in 'xform'.        template<typename Expr, typename TransformTuple>        constexpr incomplete operator()(Expr && expr, TransformTuple transforms) const;    };    template<        expr_kind Kind,        template<expr_kind, class> class ExprTemplate,        typename OldTuple,        typename NewTuple>    constexpr auto make_expr_from_tuple(        ExprTemplate<Kind, OldTuple> const & expr, NewTuple && tuple)    {        return ExprTemplate<Kind, NewTuple>{std::move(tuple)};    }    template<expr_kind Kind, typename Expr, typename NewTuple>    constexpr auto make_expr_from_tuple(Expr const & expr, NewTuple && tuple)    {        return minimal_expr<Kind, NewTuple>{std::move(tuple)};    }    template<typename Expr, typename Tuple, typename TransformTuple>    constexpr decltype(auto) transform_nonterminal(        Expr const & expr, Tuple && tuple, TransformTuple transforms)    {        auto transformed_tuple =            hana::transform(static_cast<Tuple &&>(tuple), [&](auto && element) {                using element_t = decltype(element);                auto const kind = remove_cv_ref_t<element_t>::kind;                ::boost::yap::detail::                    transform_impl<false, 0, kind == expr_kind::expr_ref>                        xform;                return xform(static_cast<element_t &&>(element), transforms);            });        auto const kind = remove_cv_ref_t<Expr>::kind;        return make_expr_from_tuple<kind>(expr, std::move(transformed_tuple));    }    template<>    struct default_transform<true, false, false>    {        template<typename Expr, typename TransformTuple>        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return transform_nonterminal(expr, expr.elements, transforms);        }    };    template<>    struct default_transform<false, false, false>    {        template<typename Expr, typename TransformTuple>        constexpr decltype(auto)        operator()(Expr && expr, TransformTuple transforms) const        {            return transform_nonterminal(                expr, std::move(expr.elements), transforms);        }    };    // Dispatch to the next transform, or to the default transform if there is    // no next transform.    template<        bool Strict,        typename Expr,        typename TransformTuple,        int I,        bool NextTransformExists>    struct next_or_default_transform    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            // Use the next transform.            constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;            return detail::                transform_impl<Strict, I + 1, kind == expr_kind::expr_ref>{}(                    static_cast<Expr &&>(expr), transforms);        }    };    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct next_or_default_transform<Strict, Expr, TransformTuple, I, false>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            // No next transform exists; use the default transform.            constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;            return default_transform<                std::is_lvalue_reference<Expr>::value,                kind == expr_kind::terminal,                Strict>{}(static_cast<Expr &&>(expr), transforms);        }    };    // Expression-matching; attempted second.    template<        bool Strict,        typename Expr,        typename TransformTuple,        int I,        typename = detail::void_t<>>    struct transform_expression_expr    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            // No expr-matching succeeded; use the next or default transform.            return next_or_default_transform<                Strict,                Expr,                TransformTuple,                I,                I + 1 < decltype(hana::size(                            std::declval<TransformTuple>()))::value>{}(                static_cast<Expr &&>(expr), transforms);        }    };    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct transform_expression_expr<        Strict,        Expr,        TransformTuple,        I,        void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(            std::declval<Expr>()))>>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return (*transforms[hana::llong<I>{}])(static_cast<Expr &&>(expr));        }    };    // Tag-matching; attempted first.    template<        bool Strict,        typename Expr,        typename TransformTuple,        int I,        expr_arity Arity,        typename>    struct transform_expression_tag    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            // No tag-matching succeeded; try expr-matching.            return transform_expression_expr<Strict, Expr, TransformTuple, I>{}(                static_cast<Expr &&>(expr), transforms);        }    };    template<typename T>    constexpr decltype(auto) terminal_value(T && x)    {        return value_impl<true>(static_cast<T &&>(x));    }    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct transform_expression_tag<        Strict,        Expr,        TransformTuple,        I,        expr_arity::one,        void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(            expr_tag<remove_cv_ref_t<Expr>::kind>{},            terminal_value(::boost::yap::value(std::declval<Expr>()))))>>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return (*transforms[hana::llong<I>{}])(                expr_tag<remove_cv_ref_t<Expr>::kind>{},                terminal_value(                    ::boost::yap::value(static_cast<Expr &&>(expr))));        }    };    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct transform_expression_tag<        Strict,        Expr,        TransformTuple,        I,        expr_arity::two,        void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(            expr_tag<remove_cv_ref_t<Expr>::kind>{},            terminal_value(::boost::yap::left(std::declval<Expr>())),            terminal_value(::boost::yap::right(std::declval<Expr>()))))>>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return (*transforms[hana::llong<I>{}])(                expr_tag<remove_cv_ref_t<Expr>::kind>{},                terminal_value(::boost::yap::left(static_cast<Expr &&>(expr))),                terminal_value(                    ::boost::yap::right(static_cast<Expr &&>(expr))));        }    };    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct transform_expression_tag<        Strict,        Expr,        TransformTuple,        I,        expr_arity::three,        void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(            expr_tag<remove_cv_ref_t<Expr>::kind>{},            terminal_value(::boost::yap::cond(std::declval<Expr>())),            terminal_value(::boost::yap::then(std::declval<Expr>())),            terminal_value(::boost::yap::else_(std::declval<Expr>()))))>>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return (*transforms[hana::llong<I>{}])(                expr_tag<remove_cv_ref_t<Expr>::kind>{},                terminal_value(::boost::yap::cond(static_cast<Expr &&>(expr))),                terminal_value(::boost::yap::then(static_cast<Expr &&>(expr))),                terminal_value(                    ::boost::yap::else_(static_cast<Expr &&>(expr))));        }    };    template<typename Expr, typename Transform>    struct transform_call_unpacker    {        template<long long... I>        constexpr auto operator()(            Expr && expr,            Transform & transform,            std::integer_sequence<long long, I...>) const            -> decltype(transform(                expr_tag<expr_kind::call>{},                terminal_value(::boost::yap::get(                    static_cast<Expr &&>(expr), hana::llong_c<I>))...))        {            return transform(                expr_tag<expr_kind::call>{},                terminal_value(::boost::yap::get(                    static_cast<Expr &&>(expr), hana::llong_c<I>))...);        }    };    template<typename Expr>    constexpr auto indices_for(Expr const & expr)    {        constexpr long long size = decltype(hana::size(expr.elements))::value;        return std::make_integer_sequence<long long, size>();    }    template<bool Strict, typename Expr, typename TransformTuple, int I>    struct transform_expression_tag<        Strict,        Expr,        TransformTuple,        I,        expr_arity::n,        void_t<decltype(            transform_call_unpacker<                Expr,                decltype(*std::declval<TransformTuple>()[hana::llong<I>{}])>{}(                std::declval<Expr>(),                *std::declval<TransformTuple>()[hana::llong<I>{}],                indices_for(std::declval<Expr>())))>>    {        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            using transform_t = decltype(*transforms[hana::llong<I>{}]);            return transform_call_unpacker<Expr, transform_t>{}(                static_cast<Expr &&>(expr),                *transforms[hana::llong<I>{}],                indices_for(expr));        }    };    template<bool Strict, int I, bool IsExprRef>    struct transform_impl    {        template<typename Expr, typename TransformTuple>        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;            return detail::transform_expression_tag<                Strict,                Expr,                TransformTuple,                I,                detail::arity_of<kind>()>{}(                static_cast<Expr &&>(expr), transforms);        }    };    template<bool Strict, int I>    struct transform_impl<Strict, I, true>    {        template<typename Expr, typename TransformTuple>        constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const        {            return detail::transform_impl<Strict, I, false>{}(                ::boost::yap::deref(static_cast<Expr &&>(expr)), transforms);        }    };}}}#endif
 |