From 31cb3b1716531bb1d7e77b20dae2932425be417f Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Thu, 3 Nov 2016 21:08:39 -0500 Subject: [PATCH] Add customization points for plus and minus; sketch in placeholder support. --- sketch.cpp | 301 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 279 insertions(+), 22 deletions(-) diff --git a/sketch.cpp b/sketch.cpp index 81321f3..68387cf 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -9,12 +9,13 @@ #include +#include // TODO: For testing. #define BOOST_PROTO17_STREAM_OPERATORS // TODO: For testing. // TODO: Verbose debugging mode for matching. // TODO: Proto-style "Fuzzy and Exact Matches of Terminals". -namespace boost { namespace proto17 { +namespace boost::proto17 { enum class expr_kind { terminal, @@ -32,6 +33,51 @@ namespace boost { namespace proto17 { template using terminal = expression; +#define BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(expr) \ + noexcept(noexcept(expr)) -> decltype(expr) { return expr; } + + namespace adl_detail { + + template + constexpr auto eval_plus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( + static_cast(t) + static_cast(u) + ) + + struct eval_plus_fn + { + template + constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( + eval_plus(static_cast(t), static_cast(u)) + ) + }; + + template + constexpr auto eval_minus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( + static_cast(t) - static_cast(u) + ) + + struct eval_minus_fn + { + template + constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( + eval_minus(static_cast(t), static_cast(u)) + ) + }; + + } + +#undef BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN + + using adl_detail::eval_plus_fn; + using adl_detail::eval_minus_fn; + + inline namespace function_objects { + + inline constexpr eval_plus_fn eval_plus{}; + inline constexpr eval_minus_fn eval_minus{}; + + } + namespace detail { template @@ -101,28 +147,53 @@ namespace boost { namespace proto17 { constexpr bool is_hana_llong(hana::basic_type>) { return true; }; + // TODO: Fix. + template + auto get_tuple_element(Tuple && tuple, hana::tuple>) + { return hana::at_c(tuple); }; + + template + auto default_eval_expr (expression const & expr, Tuple && tuple) + { + using namespace hana::literals; + if constexpr (Kind == expr_kind::terminal) { + static_assert(sizeof...(T) == 1); + return expr.elements[0_c]; + } else if constexpr (Kind == expr_kind::placeholder) { + static_assert(sizeof...(T) == 1); + // TODO: Fix. + return get_tuple_element(tuple, expr.elements); + } else if constexpr (Kind == expr_kind::plus) { + return + eval_plus( + default_eval_expr(expr.elements[0_c], static_cast(tuple)), + default_eval_expr(expr.elements[1_c], static_cast(tuple)) + ); + } else if constexpr (Kind == expr_kind::minus) { + return + eval_minus( + default_eval_expr(expr.elements[0_c], static_cast(tuple)), + default_eval_expr(expr.elements[1_c], static_cast(tuple)) + ); + } else { + assert(false && "Unhandled expr_kind in default_evaluate!"); + return; + } + } + } -#if 0 // TODO - struct callable - { - auto operator() (TODO) const; - }; -#endif + // TODO: Customization point. + // TODO: static assert/SFINAE std::is_callable<> + // TODO: static assert/SFINAE no placeholders + template + R evaluate_expression_as (expression const & expr) + { return static_cast(detail::default_eval_expr(expr, hana::tuple<>())); } - template - constexpr bool is_terminal (hana::basic_type) - { return false; } - template - constexpr bool is_terminal (hana::basic_type>) - { return true; } - - template - constexpr bool is_expression (hana::basic_type) - { return false; } - template - constexpr bool is_expression (hana::basic_type>) - { return true; } + // TODO: static assert/SFINAE std::is_callable<> + template + auto evaluate (Expr const & expr, T && ...t) + { return detail::default_eval_expr(expr, hana::make_tuple(static_cast(t)...)); } template struct expression @@ -152,6 +223,10 @@ namespace boost { namespace proto17 { tuple_type elements; + template + operator R () + { return evaluate_expression_as(*this); } + template auto operator+ (U && rhs) const & { @@ -169,6 +244,24 @@ namespace boost { namespace proto17 { hana::tuple{std::move(*this), rhs_type{static_cast(rhs)}} }; } + + template + auto operator- (U && rhs) const & + { + using rhs_type = typename detail::rhs_type::type; + return expression{ + hana::tuple{*this, rhs_type{static_cast(rhs)}} + }; + } + + template + auto operator- (U && rhs) && + { + using rhs_type = typename detail::rhs_type::type; + return expression{ + hana::tuple{std::move(*this), rhs_type{static_cast(rhs)}} + }; + } }; template @@ -222,7 +315,7 @@ namespace boost { namespace proto17 { switch (kind) { case expr_kind::plus: return os << "+"; case expr_kind::minus: return os << "-"; - // TODO + // TODO default: return os << "** ERROR: UNKNOWN OPERATOR! **"; } } @@ -375,7 +468,7 @@ namespace boost { namespace proto17 { } -} } +} #include @@ -1223,6 +1316,163 @@ void print () #endif } +void default_eval () +{ + term unity{1.0}; + int i_ = 42; + term i{std::move(i_)}; + bp17::expression< + bp17::expr_kind::minus, + term, + term + > expr = unity - std::move(i); + bp17::expression< + bp17::expr_kind::plus, + term, + bp17::expression< + bp17::expr_kind::minus, + term, + term + > + > unevaluated_expr = unity + std::move(expr); + + { + double result = unity; + std::cout << "unity=" << result << "\n"; // 1 + } + + { + double result = expr; + std::cout << "expr=" << result << "\n"; // -41 + } + + { + double result = unevaluated_expr; + std::cout << "unevaluated_expr=" << result << "\n"; // -40 + } + + { + double result = evaluate(unity, boost::hana::make_tuple(5, 6, 7)); + std::cout << "evaluate(unity)=" << result << "\n"; // 1 + } + + { + double result = evaluate(expr, boost::hana::make_tuple()); + std::cout << "evaluate(expr)=" << result << "\n"; // -41 + } + + { + double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"))); + std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // -40 + } +} + +namespace test { + + struct number + { + explicit operator double () const { return value; } + + double value; + }; + + // User-defined binary-plus! With weird semantics! + inline auto eval_plus (number a, number b) + { return number{a.value - b.value}; } + +} + +void eval () +{ + term unity{{1.0}}; + double d_ = 42.0; + term i{{d_}}; + bp17::expression< + bp17::expr_kind::plus, + term, + term + > expr = unity + std::move(i); + bp17::expression< + bp17::expr_kind::plus, + term, + bp17::expression< + bp17::expr_kind::plus, + term, + term + > + > unevaluated_expr = unity + std::move(expr); + + { + double result = unity; + std::cout << "unity=" << result << "\n"; // 1 + } + + { + double result = expr; + std::cout << "expr=" << result << "\n"; // -41 + } + + { + double result = unevaluated_expr; + std::cout << "unevaluated_expr=" << result << "\n"; // 42 + } + + { + double result = (double)evaluate(unity, boost::hana::make_tuple(5, 6, 7)); + std::cout << "evaluate(unity)=" << result << "\n"; // 1 + } + + { + double result = (double)evaluate(expr, boost::hana::make_tuple()); + std::cout << "evaluate(expr)=" << result << "\n"; // -41 + } + + { + double result = (double)evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"))); + std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 42 + } +} + +#if 0 +void placeholder_eval () +{ + using namespace boost::proto17::literals; + + bp17::placeholder<2> p2 = 2_p; + int i_ = 42; + term i{std::move(i_)}; + bp17::expression< + bp17::expr_kind::plus, + bp17::placeholder<2>, + term + > expr = p2 + std::move(i); + bp17::expression< + bp17::expr_kind::plus, + bp17::placeholder<2>, + bp17::expression< + bp17::expr_kind::plus, + bp17::placeholder<2>, + term + > + > unevaluated_expr = p2 + std::move(expr); + + { + double result = evaluate(p2, boost::hana::make_tuple(5, 6, 7)); + std::cout << "evaluate(p2)=" << result << "\n"; // 7 + } + + { + double result = evaluate(expr, boost::hana::make_tuple(std::string("15"), 3, 1)); + std::cout << "evaluate(expr)=" << result << "\n"; // 43 + } + + { + double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"), 2, 3)); + std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 48 + } +} +#endif + int main () { term_plus_x(); @@ -1235,6 +1485,13 @@ int main () print(); + default_eval(); + eval(); + +#if 0 // TODO: Fix. + placeholder_eval(); +#endif + #if 0 // TODO { bp17::terminal unity{1.0};