summaryrefslogtreecommitdiff
path: root/boost/yap/detail/transform.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/yap/detail/transform.hpp')
-rw-r--r--boost/yap/detail/transform.hpp590
1 files changed, 590 insertions, 0 deletions
diff --git a/boost/yap/detail/transform.hpp b/boost/yap/detail/transform.hpp
new file mode 100644
index 0000000000..eade19aaf0
--- /dev/null
+++ b/boost/yap/detail/transform.hpp
@@ -0,0 +1,590 @@
+// 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>{}>
+ 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>...>;
+
+ 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>
+ 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>{},
+ 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>
+ 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