summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/yap/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/yap/test')
-rw-r--r--src/boost/libs/yap/test/CMakeLists.txt131
-rw-r--r--src/boost/libs/yap/test/Jamfile.v263
-rw-r--r--src/boost/libs/yap/test/call_expr.cpp198
-rw-r--r--src/boost/libs/yap/test/comma.cpp126
-rw-r--r--src/boost/libs/yap/test/compile_const_term.cpp77
-rw-r--r--src/boost/libs/yap/test/compile_is_expr.cpp99
-rw-r--r--src/boost/libs/yap/test/compile_move_only_types.cpp46
-rw-r--r--src/boost/libs/yap/test/compile_placeholders.cpp50
-rw-r--r--src/boost/libs/yap/test/compile_term_plus_expr.cpp308
-rw-r--r--src/boost/libs/yap/test/compile_term_plus_term.cpp221
-rw-r--r--src/boost/libs/yap/test/compile_term_plus_x.cpp174
-rw-r--r--src/boost/libs/yap/test/compile_term_plus_x_this_ref_overloads.cpp174
-rw-r--r--src/boost/libs/yap/test/compile_tests_main.cpp29
-rw-r--r--src/boost/libs/yap/test/compile_user_macros.cpp58
-rw-r--r--src/boost/libs/yap/test/compile_x_plus_term.cpp174
-rw-r--r--src/boost/libs/yap/test/default_eval.cpp103
-rw-r--r--src/boost/libs/yap/test/depth_stress_test_left.cpp69
-rw-r--r--src/boost/libs/yap/test/depth_stress_test_right.cpp70
-rw-r--r--src/boost/libs/yap/test/deref.cpp174
-rw-r--r--src/boost/libs/yap/test/expression_function.cpp70
-rw-r--r--src/boost/libs/yap/test/fail_argument.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_callable.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_cond.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_else.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_get.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_left.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_make_expression.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_make_terminal.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_right.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_then.cpp12
-rw-r--r--src/boost/libs/yap/test/fail_transform.cpp15
-rw-r--r--src/boost/libs/yap/test/if_else.cpp114
-rw-r--r--src/boost/libs/yap/test/lazy_vector_alloc_test.cpp108
-rw-r--r--src/boost/libs/yap/test/left.cpp318
-rw-r--r--src/boost/libs/yap/test/operators_unary.cpp174
-rw-r--r--src/boost/libs/yap/test/placeholder_eval.cpp65
-rw-r--r--src/boost/libs/yap/test/print.cpp1595
-rw-r--r--src/boost/libs/yap/test/reference_returns.cpp89
-rw-r--r--src/boost/libs/yap/test/right.cpp264
-rw-r--r--src/boost/libs/yap/test/transform.cpp78
-rw-r--r--src/boost/libs/yap/test/user_expression_transform_1.cpp948
-rw-r--r--src/boost/libs/yap/test/user_expression_transform_2.cpp257
-rw-r--r--src/boost/libs/yap/test/value.cpp208
-rw-r--r--src/boost/libs/yap/test/vector_alloc_test.cpp172
44 files changed, 6939 insertions, 0 deletions
diff --git a/src/boost/libs/yap/test/CMakeLists.txt b/src/boost/libs/yap/test/CMakeLists.txt
new file mode 100644
index 00000000..0188b806
--- /dev/null
+++ b/src/boost/libs/yap/test/CMakeLists.txt
@@ -0,0 +1,131 @@
+include_directories(${CMAKE_HOME_DIRECTORY})
+
+include(CTest)
+
+enable_testing()
+
+add_custom_target(yap_check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR})
+if (NOT TARGET check)
+ add_custom_target(check DEPENDS yap_check)
+else()
+ add_dependencies(check yap_check)
+endif()
+
+set(coverage_gcda_files)
+
+macro(add_test_executable name)
+ add_executable(${name} ${name}.cpp)
+ target_link_libraries(${name} yap)
+ target_compile_definitions(${name} PRIVATE BOOST_NO_AUTO_PTR)
+ add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name})
+ if (clang_on_linux)
+ target_link_libraries(${name} c++)
+ endif ()
+ list(APPEND coverage_gcda_files ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${name}.dir/${name}.cpp.gcda)
+endmacro()
+
+add_test_executable(deref)
+add_test_executable(value)
+add_test_executable(left)
+add_test_executable(right)
+add_test_executable(print)
+add_test_executable(default_eval)
+add_test_executable(user_expression_transform_1)
+add_test_executable(user_expression_transform_2)
+add_test_executable(placeholder_eval)
+add_test_executable(call_expr)
+add_test_executable(reference_returns)
+add_test_executable(depth_stress_test_left)
+add_test_executable(depth_stress_test_right)
+add_test_executable(lazy_vector_alloc_test)
+add_test_executable(vector_alloc_test)
+add_test_executable(operators_unary)
+add_test_executable(comma)
+add_test_executable(if_else)
+add_test_executable(expression_function)
+add_test_executable(transform)
+
+add_executable(
+ compile_tests
+ compile_tests_main.cpp
+ compile_is_expr.cpp
+ compile_const_term.cpp
+ compile_placeholders.cpp
+ compile_term_plus_expr.cpp
+ compile_term_plus_term.cpp
+ compile_term_plus_x.cpp
+ compile_x_plus_term.cpp
+ compile_term_plus_x_this_ref_overloads.cpp
+ compile_const_term.cpp
+ compile_move_only_types.cpp
+ compile_user_macros.cpp
+)
+target_link_libraries(compile_tests yap)
+if (clang_on_linux)
+ target_link_libraries(compile_tests c++)
+endif ()
+
+function(add_compile_fail_test name)
+ try_compile(
+ compiles
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp
+ COMPILE_DEFINITIONS
+ ${std_flag} -I${Boost_INCLUDE_DIRS} -I${CMAKE_SOURCE_DIR}/include
+ OUTPUT_VARIABLE foo
+ )
+ #message("foo=${foo}")
+ if (compiles)
+ message(FATAL_ERROR "Compile-fail test ${name} does not fail to compile.")
+ endif ()
+endfunction()
+
+add_compile_fail_test(fail_transform)
+add_compile_fail_test(fail_get)
+add_compile_fail_test(fail_left)
+add_compile_fail_test(fail_right)
+add_compile_fail_test(fail_cond)
+add_compile_fail_test(fail_then)
+add_compile_fail_test(fail_else)
+add_compile_fail_test(fail_callable)
+add_compile_fail_test(fail_argument)
+add_compile_fail_test(fail_make_expression)
+add_compile_fail_test(fail_make_terminal)
+
+if (BUILD_COVERAGE AND UNIX)
+ if (APPLE)
+ add_custom_target(
+ coverage
+ rm -rf ${coverage_gcda_files} lcov-all.info lcov.info output
+ COMMAND
+ ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}
+ COMMAND
+ cd ${CMAKE_BINARY_DIR}
+ COMMAND
+ llvm-cov gcov -f -b ${coverage_gcda_files}
+ COMMAND
+ lcov --directory . --base-directory . --gcov-tool ${CMAKE_SOURCE_DIR}/llvm-gcov.sh --capture -o lcov-all.info
+ COMMAND
+ lcov -e lcov-all.info ${CMAKE_SOURCE_DIR}/include/boost/yap/* ${CMAKE_SOURCE_DIR}/include/boost/yap/detail/* -o lcov.info
+ COMMAND
+ genhtml lcov.info -o output
+ )
+ else ()
+ add_custom_target(
+ coverage
+ rm -rf ${coverage_gcda_files} lcov-all.info lcov.info output
+ COMMAND
+ ${CMAKE_CTEST_COMMAND} -j4 -VV -C ${CMAKE_CFG_INTDIR}
+ COMMAND
+ cd ${CMAKE_BINARY_DIR}
+ COMMAND
+ gcov -f -b ${coverage_gcda_files}
+ COMMAND
+ lcov --directory . --base-directory . --capture -o lcov-all.info
+ COMMAND
+ lcov -e lcov-all.info ${CMAKE_SOURCE_DIR}/include/boost/yap/* ${CMAKE_SOURCE_DIR}/include/boost/yap/detail/* -o lcov.info
+ COMMAND
+ genhtml lcov.info -o output
+ )
+ endif ()
+endif ()
diff --git a/src/boost/libs/yap/test/Jamfile.v2 b/src/boost/libs/yap/test/Jamfile.v2
new file mode 100644
index 00000000..17bfd90c
--- /dev/null
+++ b/src/boost/libs/yap/test/Jamfile.v2
@@ -0,0 +1,63 @@
+# Copyright (c) 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
+
+import config : requires ;
+import testing ;
+
+project
+ : requirements
+ [ requires
+ cxx14_constexpr
+ cxx14_decltype_auto
+ cxx14_generic_lambdas
+ cxx14_return_type_deduction
+ ]
+ ;
+
+run deref.cpp ;
+run value.cpp ;
+run left.cpp ;
+run right.cpp ;
+run print.cpp ;
+run default_eval.cpp ;
+run user_expression_transform_1.cpp ;
+run user_expression_transform_2.cpp ;
+run placeholder_eval.cpp ;
+run call_expr.cpp ;
+run reference_returns.cpp ;
+run depth_stress_test_left.cpp ;
+run depth_stress_test_right.cpp ;
+run lazy_vector_alloc_test.cpp ;
+run vector_alloc_test.cpp ;
+run operators_unary.cpp ;
+run comma.cpp ;
+run if_else.cpp ;
+run expression_function.cpp ;
+run transform.cpp ;
+
+compile compile_is_expr.cpp ;
+compile compile_const_term.cpp ;
+compile compile_placeholders.cpp ;
+compile compile_term_plus_expr.cpp ;
+compile compile_term_plus_term.cpp ;
+compile compile_term_plus_x.cpp ;
+compile compile_x_plus_term.cpp ;
+compile compile_term_plus_x_this_ref_overloads.cpp ;
+compile compile_move_only_types.cpp ;
+compile compile_user_macros.cpp ;
+
+compile-fail fail_transform.cpp ;
+compile-fail fail_get.cpp ;
+compile-fail fail_left.cpp ;
+compile-fail fail_right.cpp ;
+compile-fail fail_cond.cpp ;
+compile-fail fail_then.cpp ;
+compile-fail fail_else.cpp ;
+compile-fail fail_callable.cpp ;
+compile-fail fail_argument.cpp ;
+compile-fail fail_make_expression.cpp ;
+compile-fail fail_make_terminal.cpp ;
diff --git a/src/boost/libs/yap/test/call_expr.cpp b/src/boost/libs/yap/test/call_expr.cpp
new file mode 100644
index 00000000..2e5c343f
--- /dev/null
+++ b/src/boost/libs/yap/test/call_expr.cpp
@@ -0,0 +1,198 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+namespace user {
+
+ struct number
+ {
+ explicit operator double() const { return value; }
+
+ double value;
+ };
+
+ number naxpy(number a, number x, number y)
+ {
+ return number{a.value * x.value + y.value + 10.0};
+ }
+
+ struct tag_type
+ {};
+
+ inline number tag_function(double a, double b) { return number{a + b}; }
+
+ struct eval_xform_tag
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::call>, tag_type, number a, double b)
+ {
+ return tag_function(a.value, b);
+ }
+
+ int operator()(
+ yap::expr_tag<yap::expr_kind::call>, tag_type, double a, double b)
+ {
+ return 42;
+ }
+
+ char const * operator()() { return "42"; }
+ };
+
+ struct empty_xform
+ {};
+
+ struct eval_xform_expr
+ {
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::call,
+ bh::tuple<
+ ref<term<user::tag_type>>,
+ term<user::number>,
+ term<int>>> const & expr)
+ {
+ using namespace boost::hana::literals;
+ return tag_function(
+ (double)yap::value(expr.elements[1_c]).value,
+ (double)yap::value(expr.elements[2_c]));
+ }
+
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::call,
+ bh::tuple<
+ ref<term<user::tag_type>>,
+ ref<term<user::number>>,
+ term<int>>> const & expr)
+ {
+ using namespace boost::hana::literals;
+ return tag_function(
+ (double)yap::value(expr.elements[1_c]).value,
+ (double)yap::value(expr.elements[2_c]));
+ }
+ };
+
+ struct eval_xform_both
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::call>,
+ tag_type,
+ user::number a,
+ double b)
+ {
+ return tag_function(a.value, b);
+ }
+
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::call,
+ bh::tuple<
+ ref<term<user::tag_type>>,
+ term<user::number>,
+ term<int>>> const & expr)
+ {
+ using namespace boost::hana::literals;
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return tag_function(
+ (double)yap::value(expr.elements[1_c]).value,
+ (double)yap::value(expr.elements[2_c]));
+ }
+
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::call,
+ bh::tuple<
+ ref<term<user::tag_type>>,
+ ref<term<user::number>>,
+ term<int>>> const & expr)
+ {
+ using namespace boost::hana::literals;
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return tag_function(
+ (double)yap::value(expr.elements[1_c]).value,
+ (double)yap::value(expr.elements[2_c]));
+ }
+ };
+}
+
+
+int test_main(int, char * [])
+{
+ {
+ using namespace boost::yap::literals;
+
+ {
+ auto plus = yap::make_terminal(user::tag_type{});
+ auto expr = plus(user::number{13}, 1);
+
+ {
+ transform(expr, user::empty_xform{});
+ }
+
+ {
+ user::number result = transform(expr, user::eval_xform_tag{});
+ BOOST_CHECK(result.value == 14);
+ }
+
+ {
+ user::number result = transform(expr, user::eval_xform_expr{});
+ BOOST_CHECK(result.value == 14);
+ }
+
+ {
+ user::number result = transform(expr, user::eval_xform_both{});
+ BOOST_CHECK(result.value == 14);
+ }
+ }
+
+ {
+ auto plus = yap::make_terminal(user::tag_type{});
+ auto thirteen = yap::make_terminal(user::number{13});
+ auto expr = plus(thirteen, 1);
+
+ {
+ user::number result = transform(expr, user::eval_xform_tag{});
+ BOOST_CHECK(result.value == 14);
+ }
+
+ {
+ user::number result = transform(expr, user::eval_xform_expr{});
+ BOOST_CHECK(result.value == 14);
+ }
+
+ {
+ user::number result = transform(expr, user::eval_xform_both{});
+ BOOST_CHECK(result.value == 14);
+ }
+ }
+
+ {
+ term<user::number> a{{1.0}};
+ term<user::number> x{{42.0}};
+ term<user::number> y{{3.0}};
+ auto n = yap::make_terminal(user::naxpy);
+
+ auto expr = n(a, x, y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 55);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/comma.cpp b/src/boost/libs/yap/test/comma.cpp
new file mode 100644
index 00000000..af3814cf
--- /dev/null
+++ b/src/boost/libs/yap/test/comma.cpp
@@ -0,0 +1,126 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using term_ref = boost::yap::expression_ref<boost::yap::expression, term<T> &>;
+
+template<typename T>
+using term_cref =
+ boost::yap::expression_ref<boost::yap::expression, term<T> const &>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+struct void_callable
+{
+ void operator()() { *called_ = (*call_count_)++; }
+ int * call_count_;
+ int * called_;
+};
+
+struct int_callable
+{
+ int operator()()
+ {
+ *called_ = (*call_count_)++;
+ return 42;
+ }
+ int * call_count_;
+ int * called_;
+};
+
+struct double_callable
+{
+ double operator()()
+ {
+ *called_ = (*call_count_)++;
+ return 13.0;
+ }
+ int * call_count_;
+ int * called_;
+};
+
+
+int test_main(int, char * [])
+{
+{
+ {
+ int call_count = 0;
+ int int_called = -1;
+ int double_called = -1;
+
+ auto int_double_expr =
+ (term<int_callable>{{&call_count, &int_called}}(),
+ term<double_callable>{{&call_count, &double_called}}());
+
+ BOOST_CHECK(evaluate(int_double_expr) == 13.0);
+ BOOST_CHECK(int_called == 0);
+ BOOST_CHECK(double_called == 1);
+ }
+
+ {
+ int call_count = 0;
+ int int_called = -1;
+ int double_called = -1;
+
+ auto double_int_expr =
+ (term<double_callable>{{&call_count, &double_called}}(),
+ term<int_callable>{{&call_count, &int_called}}());
+
+ BOOST_CHECK(evaluate(double_int_expr) == 42);
+ BOOST_CHECK(int_called == 1);
+ BOOST_CHECK(double_called == 0);
+ }
+}
+
+{
+ {
+ int call_count = 0;
+ int void_called = -1;
+ int int_called = -1;
+
+ auto void_int_expr =
+ (term<void_callable>{{&call_count, &void_called}}(),
+ term<int_callable>{{&call_count, &int_called}}());
+
+ BOOST_CHECK(evaluate(void_int_expr) == 42);
+ BOOST_CHECK(void_called == 0);
+ BOOST_CHECK(int_called == 1);
+ }
+
+ {
+ int call_count = 0;
+ int void_called = -1;
+ int int_called = -1;
+
+ auto int_void_expr =
+ (term<int_callable>{{&call_count, &int_called}}(),
+ term<void_callable>{{&call_count, &void_called}}());
+
+ using eval_type = decltype(evaluate(int_void_expr));
+ BOOST_MPL_ASSERT(
+ (std::is_same<void, eval_type>));
+
+ evaluate(int_void_expr);
+ BOOST_CHECK(void_called == 1);
+ BOOST_CHECK(int_called == 0);
+ }
+}
+
+return 0;
+}
diff --git a/src/boost/libs/yap/test/compile_const_term.cpp b/src/boost/libs/yap/test/compile_const_term.cpp
new file mode 100644
index 00000000..11ff761d
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_const_term.cpp
@@ -0,0 +1,77 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_const_term()
+{
+ {
+ term<double const> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double const> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double const> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double const> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> const unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> const &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> const &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> const &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int const &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const &>>> const expr =
+ unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const &>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_is_expr.cpp b/src/boost/libs/yap/test/compile_is_expr.cpp
new file mode 100644
index 00000000..3bf030d4
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_is_expr.cpp
@@ -0,0 +1,99 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+namespace yap = boost::yap;
+
+struct alternate_expr_1
+{
+ static const yap::expr_kind kind = yap::expr_kind::plus;
+ boost::hana::tuple<> elements;
+};
+
+struct alternate_expr_2
+{
+ static const yap::expr_kind kind = yap::expr_kind::plus;
+ boost::hana::tuple<int, double> elements;
+};
+
+
+struct non_expr_1
+{};
+
+struct non_expr_2
+{
+ boost::hana::tuple<int, double> elements;
+};
+
+struct non_expr_3
+{
+ static const int kind = 0;
+ boost::hana::tuple<int, double> elements;
+};
+
+struct non_expr_4
+{
+ int kind;
+ boost::hana::tuple<int, double> elements;
+};
+
+struct non_expr_5
+{
+ static const yap::expr_kind kind = yap::expr_kind::plus;
+};
+
+struct non_expr_6
+{
+ static const yap::expr_kind kind = yap::expr_kind::plus;
+ int elements;
+};
+
+
+void compile_is_expr()
+{
+ static_assert(
+ yap::is_expr<yap::terminal<yap::expression, double>>::value, "");
+
+ static_assert(
+ yap::is_expr<yap::terminal<yap::expression, double> const>::value, "");
+ static_assert(
+ yap::is_expr<yap::terminal<yap::expression, double> const &>::value,
+ "");
+ static_assert(
+ yap::is_expr<yap::terminal<yap::expression, double> &>::value, "");
+ static_assert(
+ yap::is_expr<yap::terminal<yap::expression, double> &&>::value, "");
+
+ {
+ using namespace yap::literals;
+ static_assert(yap::is_expr<decltype(1_p)>::value, "");
+ }
+
+ static_assert(
+ yap::is_expr<yap::expression<
+ yap::expr_kind::unary_plus,
+ boost::hana::tuple<yap::terminal<yap::expression, double>>>>::value,
+ "");
+ static_assert(
+ yap::is_expr<yap::expression<
+ yap::expr_kind::plus,
+ boost::hana::tuple<
+ yap::terminal<yap::expression, double>,
+ yap::terminal<yap::expression, double>>>>::value,
+ "");
+
+ static_assert(yap::is_expr<alternate_expr_1>::value, "");
+ static_assert(yap::is_expr<alternate_expr_2>::value, "");
+
+ static_assert(!yap::is_expr<int>::value, "");
+ static_assert(!yap::is_expr<non_expr_1>::value, "");
+ static_assert(!yap::is_expr<non_expr_2>::value, "");
+ static_assert(!yap::is_expr<non_expr_3>::value, "");
+ static_assert(!yap::is_expr<non_expr_4>::value, "");
+ static_assert(!yap::is_expr<non_expr_5>::value, "");
+ static_assert(!yap::is_expr<non_expr_6>::value, "");
+}
diff --git a/src/boost/libs/yap/test/compile_move_only_types.cpp b/src/boost/libs/yap/test/compile_move_only_types.cpp
new file mode 100644
index 00000000..2649ff00
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_move_only_types.cpp
@@ -0,0 +1,46 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <memory>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+inline auto double_to_float(term<double> expr)
+{
+ return term<float>{(float)expr.value()};
+}
+
+void compile_move_only_types()
+{
+ term<double> unity{1.0};
+ term<std::unique_ptr<int>> i{new int{7}};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::unique_ptr<int>>>>
+ expr_1 = unity + std::move(i);
+
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::unique_ptr<int>>>>>>
+ expr_2 = unity + std::move(expr_1);
+
+ auto transformed_expr = transform(std::move(expr_2), double_to_float);
+ (void)transformed_expr;
+}
diff --git a/src/boost/libs/yap/test/compile_placeholders.cpp b/src/boost/libs/yap/test/compile_placeholders.cpp
new file mode 100644
index 00000000..8a4e50aa
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_placeholders.cpp
@@ -0,0 +1,50 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<long long I>
+using place_term =
+ boost::yap::terminal<boost::yap::expression, boost::yap::placeholder<I>>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_placeholders()
+{
+ using namespace boost::yap::literals;
+
+ {
+ place_term<1> p1 = 1_p;
+ (void)p1;
+ }
+
+ {
+ place_term<1> p1 = 1_p;
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<place_term<1> &>, ref<term<double> &>>>
+ expr = p1 + unity;
+ (void)expr;
+ }
+
+ {
+ place_term<1> p1 = 1_p;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<place_term<1> &>, place_term<2>>>
+ expr = p1 + 2_p;
+ (void)expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_term_plus_expr.cpp b/src/boost/libs/yap/test/compile_term_plus_expr.cpp
new file mode 100644
index 00000000..9a90f9ac
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_term_plus_expr.cpp
@@ -0,0 +1,308 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_term_plus_expr()
+{
+ // values
+ {
+ term<double> unity{1.0};
+ term<int> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> &>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int const> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const> &>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ // const value terminals/expressions
+ {
+ term<double> unity{1.0};
+ term<int> const i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> const &>>> const expr =
+ unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<term<int> const &>>> const &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> &>>> const expr =
+ unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> &>>> const &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ // lvalue refs
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int &> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int &> &>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int const &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const &> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<term<int const &> &>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ ref<yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>> &>>>
+ unevaluated_expr = unity + expr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int &> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int &> &>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int const &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const &> &>>>
+ expr = unity + i;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const &> &>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ // rvalue refs
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_term_plus_term.cpp b/src/boost/libs/yap/test/compile_term_plus_term.cpp
new file mode 100644
index 00000000..d1037ce6
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_term_plus_term.cpp
@@ -0,0 +1,221 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <string>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_term_plus_term()
+{
+ using namespace std::literals;
+
+ // char const * string
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<char const *>>>
+ unevaluated_expr = unity + term<char const *>{"3"};
+ (void)unevaluated_expr;
+ }
+
+ // std::string temporary
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::string>>>
+ unevaluated_expr = unity + term<std::string>{"3"s};
+ (void)unevaluated_expr;
+ }
+
+ // pointers
+ {
+ term<double> unity{1.0};
+ int ints_[] = {1, 2};
+ term<int *> ints = {ints_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int *> &>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints_[] = {1, 2};
+ term<int const *> ints = {ints_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const *> &>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints_[] = {1, 2};
+ term<int *> ints = {ints_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + std::move(ints);
+ (void)unevaluated_expr;
+ }
+
+ // const pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ term<int * const> int_ptr = {ints};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int * const> &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ term<int const * const> int_ptr = {ints};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const * const> &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ term<int * const> int_ptr = {ints};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int * const>>>
+ unevaluated_expr = unity + std::move(int_ptr);
+ (void)unevaluated_expr;
+ }
+
+ // values
+ {
+ term<double> unity{1.0};
+ term<int> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int const> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const> &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int> i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+
+ // const value terminals
+ {
+ term<double> unity{1.0};
+ term<int> const i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int> const &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ term<int const> const i = {1};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const> const &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ // lvalue refs
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int &> &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int const &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<int const &> &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &> i{i_};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+
+ // rvalue refs
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 1;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_term_plus_x.cpp b/src/boost/libs/yap/test/compile_term_plus_x.cpp
new file mode 100644
index 00000000..1382abf9
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_term_plus_x.cpp
@@ -0,0 +1,174 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <string>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_term_plus_x()
+{
+ using namespace std::literals;
+
+ // char const * string
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<char const *>>>
+ unevaluated_expr = unity + "3";
+ (void)unevaluated_expr;
+ }
+
+ // std::string temporary
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::string>>>
+ unevaluated_expr = unity + "3"s;
+ (void)unevaluated_expr;
+ }
+
+ // arrays
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const *>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + std::move(ints);
+ (void)unevaluated_expr;
+ }
+
+ // pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *&>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const *&>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + std::move(int_ptr);
+ (void)unevaluated_expr;
+ }
+
+ // const pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int * const &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const * const &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int * const>>>
+ unevaluated_expr = unity + std::move(int_ptr);
+ (void)unevaluated_expr;
+ }
+
+ // values
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_term_plus_x_this_ref_overloads.cpp b/src/boost/libs/yap/test/compile_term_plus_x_this_ref_overloads.cpp
new file mode 100644
index 00000000..58541609
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_term_plus_x_this_ref_overloads.cpp
@@ -0,0 +1,174 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <string>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_term_plus_x_this_ref_overloads()
+{
+ using namespace std::literals;
+
+ // char const * string
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<char const *>>>
+ unevaluated_expr = unity + "3";
+ (void)unevaluated_expr;
+ }
+
+ // std::string temporary
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::string>>>
+ unevaluated_expr = unity + "3"s;
+ (void)unevaluated_expr;
+ }
+
+ // arrays
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const *>>>
+ unevaluated_expr = unity + ints;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + std::move(ints);
+ (void)unevaluated_expr;
+ }
+
+ // pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *&>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const *&>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int *>>>
+ unevaluated_expr = unity + std::move(int_ptr);
+ (void)unevaluated_expr;
+ }
+
+ // const pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int * const &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const * const &>>>
+ unevaluated_expr = unity + int_ptr;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int * const>>>
+ unevaluated_expr = unity + std::move(int_ptr);
+ (void)unevaluated_expr;
+ }
+
+ // values
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int const &>>>
+ unevaluated_expr = unity + i;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>
+ unevaluated_expr = unity + std::move(i);
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/compile_tests_main.cpp b/src/boost/libs/yap/test/compile_tests_main.cpp
new file mode 100644
index 00000000..7c77fc4e
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_tests_main.cpp
@@ -0,0 +1,29 @@
+// 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)
+void compile_is_expr();
+void compile_const_term();
+void compile_move_only_types();
+void compile_placeholders();
+void compile_term_plus_expr();
+void compile_term_plus_term();
+void compile_term_plus_x();
+void compile_term_plus_x_this_ref_overloads();
+void compile_x_plus_term();
+void compile_user_macros();
+
+int main()
+{
+ compile_is_expr();
+ compile_const_term();
+ compile_move_only_types();
+ compile_placeholders();
+ compile_term_plus_expr();
+ compile_term_plus_term();
+ compile_term_plus_x();
+ compile_term_plus_x_this_ref_overloads();
+ compile_x_plus_term();
+ compile_user_macros();
+}
diff --git a/src/boost/libs/yap/test/compile_user_macros.cpp b/src/boost/libs/yap/test/compile_user_macros.cpp
new file mode 100644
index 00000000..f9fd01f4
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_user_macros.cpp
@@ -0,0 +1,58 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<yap::expr_kind Kind, typename Tuple>
+struct expr
+{
+ static yap::expr_kind const kind = Kind;
+ Tuple elements;
+
+ BOOST_YAP_USER_ASSIGN_OPERATOR(expr, ::expr);
+};
+
+
+static_assert(yap::detail::copy_or_move<int, int const &>::value, "");
+static_assert(yap::detail::copy_or_move<int, int &>::value, "");
+static_assert(yap::detail::copy_or_move<int, int &&>::value, "");
+static_assert(!yap::detail::copy_or_move<int, int const &&>::value, "");
+static_assert(!yap::detail::copy_or_move<int, int>::value, "");
+
+
+void compile_user_macros()
+{
+ using namespace boost::hana::literals;
+
+ expr<yap::expr_kind::negate, bh::tuple<int>> negation1;
+ negation1.elements[0_c] = 1;
+ expr<yap::expr_kind::negate, bh::tuple<int>> negation2;
+ negation2.elements[0_c] = 2;
+
+ // Normal-rules assignment.
+ negation2 = negation1;
+ assert(negation2.elements[0_c] == 1);
+
+ negation2.elements[0_c] = 2;
+
+ // Normal-rules move assignment.
+ negation2 = std::move(negation1);
+ assert(negation2.elements[0_c] == 1);
+
+ // Produce a new expression via BOOST_YAP_USER_ASSIGN_OPERATOR.
+ auto expr = negation1 = 2;
+ (void)expr;
+}
diff --git a/src/boost/libs/yap/test/compile_x_plus_term.cpp b/src/boost/libs/yap/test/compile_x_plus_term.cpp
new file mode 100644
index 00000000..2eef6eba
--- /dev/null
+++ b/src/boost/libs/yap/test/compile_x_plus_term.cpp
@@ -0,0 +1,174 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <string>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+void compile_x_plus_term()
+{
+ using namespace std::literals;
+
+ // char const * string
+ {
+ term<double> unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<char const *>, ref<term<double> &>>>
+ unevaluated_expr = "3" + unity;
+ (void)unevaluated_expr;
+ }
+
+ // std::string temporary
+ {
+ term<double> const unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<std::string>, ref<term<double> const &>>>
+ unevaluated_expr = "3"s + unity;
+ (void)unevaluated_expr;
+ }
+
+ // arrays
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int *>, ref<term<double> &>>>
+ unevaluated_expr = ints + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int const *>, ref<term<double> &>>>
+ unevaluated_expr = ints + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int *>, ref<term<double> &>>>
+ unevaluated_expr = std::move(ints) + unity;
+ (void)unevaluated_expr;
+ }
+
+ // pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int *&>, ref<term<double> &>>>
+ unevaluated_expr = int_ptr + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int const *&>, ref<term<double> &>>>
+ unevaluated_expr = int_ptr + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int *>, ref<term<double> &>>>
+ unevaluated_expr = std::move(int_ptr) + unity;
+ (void)unevaluated_expr;
+ }
+
+ // const pointers
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int * const &>, ref<term<double> &>>>
+ unevaluated_expr = int_ptr + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const ints[] = {1, 2};
+ int const * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int const * const &>, ref<term<double> &>>>
+ unevaluated_expr = int_ptr + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int ints[] = {1, 2};
+ int * const int_ptr = ints;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int * const>, ref<term<double> &>>>
+ unevaluated_expr = std::move(int_ptr) + unity;
+ (void)unevaluated_expr;
+ }
+
+ // values
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int &>, ref<term<double> &>>>
+ unevaluated_expr = i + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int const i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int const &>, ref<term<double> &>>>
+ unevaluated_expr = i + unity;
+ (void)unevaluated_expr;
+ }
+
+ {
+ term<double> unity{1.0};
+ int i = 1;
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<term<int>, ref<term<double> &>>>
+ unevaluated_expr = std::move(i) + unity;
+ (void)unevaluated_expr;
+ }
+}
diff --git a/src/boost/libs/yap/test/default_eval.cpp b/src/boost/libs/yap/test/default_eval.cpp
new file mode 100644
index 00000000..27087f95
--- /dev/null
+++ b/src/boost/libs/yap/test/default_eval.cpp
@@ -0,0 +1,103 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity - std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr_1 = unity + std::move(expr);
+
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<double> &>>>
+ unevaluated_expr_2 = unity + unity;
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ unevaluated_expr_3 = unity + const_unity;
+
+ {
+ double result = evaluate(unity);
+ BOOST_CHECK(result == 1);
+ }
+
+ {
+ double result = evaluate(expr);
+ BOOST_CHECK(result == -41);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_1);
+ BOOST_CHECK(result == -40);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_2);
+ BOOST_CHECK(result == 2);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_3);
+ BOOST_CHECK(result == 2);
+ }
+
+ {
+ double result = evaluate(unity, 5, 6, 7);
+ BOOST_CHECK(result == 1);
+ }
+
+ {
+ double result = evaluate(expr);
+ BOOST_CHECK(result == -41);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_1, std::string("15"));
+ BOOST_CHECK(result == -40);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_2, std::string("15"));
+ BOOST_CHECK(result == 2);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr_3, std::string("15"));
+ BOOST_CHECK(result == 2);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/depth_stress_test_left.cpp b/src/boost/libs/yap/test/depth_stress_test_left.cpp
new file mode 100644
index 00000000..ec2724e1
--- /dev/null
+++ b/src/boost/libs/yap/test/depth_stress_test_left.cpp
@@ -0,0 +1,69 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template <typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+
+
+int test_main(int, char * [])
+{
+{
+ term<double> unity{1.0};
+
+ {
+ auto expr = (unity + (unity + (unity + (unity + (unity + (unity + (unity + unity)))))));
+ double result = boost::yap::evaluate(expr);
+ BOOST_CHECK(result == 8.0);
+ }
+
+ {
+ auto expr =
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))));
+ double result = boost::yap::evaluate(expr);
+ BOOST_CHECK(result == 64.0);
+ }
+
+#if 0 // This makes the Travis VMs barf.
+ {
+ auto expr =
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity +
+ (unity + (unity + (unity + (unity + (unity + (unity + (unity + (unity))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))));
+ double result = boost::yap::evaluate(
+ (expr + (expr + (expr + (expr + (expr + (expr + (expr + (expr +
+ (expr + (expr + (expr + (expr + (expr + (expr + (expr + (expr +
+ (expr + (expr + (expr + (expr + (expr + (expr + (expr + (expr +
+ (expr + (expr + (expr + (expr + (expr + (expr + (expr + (expr))))))))))))))))))))))))))))))))
+ );
+ BOOST_CHECK(result == 64.0 * 32.0);
+ }
+#endif
+}
+
+return 0;
+}
diff --git a/src/boost/libs/yap/test/depth_stress_test_right.cpp b/src/boost/libs/yap/test/depth_stress_test_right.cpp
new file mode 100644
index 00000000..33c5be1b
--- /dev/null
+++ b/src/boost/libs/yap/test/depth_stress_test_right.cpp
@@ -0,0 +1,70 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<double> unity{1.0};
+
+ {
+ auto expr =
+ unity + unity + unity + unity + unity + unity + unity + unity;
+ double result = boost::yap::evaluate(expr);
+ BOOST_CHECK(result == 8.0);
+ }
+
+ {
+ auto expr =
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity;
+ double result = boost::yap::evaluate(expr);
+ BOOST_CHECK(result == 64.0);
+ }
+
+#if 0 // This makes the Travis VMs barf.
+ {
+ auto expr =
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity +
+ unity + unity + unity + unity + unity + unity + unity + unity;
+ double result = boost::yap::evaluate(
+ expr + expr + expr + expr + expr + expr + expr + expr +
+ expr + expr + expr + expr + expr + expr + expr + expr +
+ expr + expr + expr + expr + expr + expr + expr + expr +
+ expr + expr + expr + expr + expr + expr + expr + expr
+ );
+ BOOST_CHECK(result == 64.0 * 32.0);
+ }
+#endif
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/deref.cpp b/src/boost/libs/yap/test/deref.cpp
new file mode 100644
index 00000000..137b51e8
--- /dev/null
+++ b/src/boost/libs/yap/test/deref.cpp
@@ -0,0 +1,174 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct user_expr
+{
+ static boost::yap::expr_kind const kind = Kind;
+
+ Tuple elements;
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
+
+template<typename T>
+using user_term = boost::yap::terminal<user_expr, T>;
+
+template<typename T>
+using user_ref = boost::yap::expression_ref<user_expr, T>;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+
+ {
+ ref<term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(std::move(ref))),
+ term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ ref<term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::deref(ref)), term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ ref<term<double> &> const ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::deref(ref)), term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ term<double> const unity = {{1.0}};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> const &>, term<int>>>
+ plus_expr = unity + term<int>{{1}};
+
+ {
+ ref<term<double> const &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(std::move(ref))),
+ term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ ref<term<double> const &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(ref)),
+ term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ ref<term<double> const &> const ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(ref)),
+ term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+
+ {
+ user_ref<user_term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(std::move(ref))),
+ user_term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ user_ref<user_term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::deref(ref)), user_term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ user_ref<user_term<double> &> const ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::deref(ref)), user_term<double> &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ user_term<double> const unity = {{1.0}};
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> const &>, user_term<int>>>
+ plus_expr = unity + user_term<int>{{1}};
+
+ {
+ user_ref<user_term<double> const &> ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(std::move(ref))),
+ user_term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ user_ref<user_term<double> const &> ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(ref)),
+ user_term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+
+ {
+ user_ref<user_term<double> const &> const ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::deref(ref)),
+ user_term<double> const &>));
+ BOOST_CHECK(yap::value(ref) == 1.0);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/expression_function.cpp b/src/boost/libs/yap/test/expression_function.cpp
new file mode 100644
index 00000000..4819e0f3
--- /dev/null
+++ b/src/boost/libs/yap/test/expression_function.cpp
@@ -0,0 +1,70 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<int> number = {{42}};
+
+ auto fn = yap::make_expression_function(number);
+ auto fn_copy = fn;
+
+ BOOST_CHECK(fn() == 42);
+ BOOST_CHECK(fn_copy() == 42);
+
+ yap::value(number) = 21;
+
+ BOOST_CHECK(fn() == 21);
+ BOOST_CHECK(fn_copy() == 21);
+ }
+
+ {
+ term<int> number = {{42}};
+
+ auto fn = yap::make_expression_function(std::move(number));
+ auto fn_copy = fn;
+
+ BOOST_CHECK(fn() == 42);
+ BOOST_CHECK(fn_copy() == 42);
+
+ yap::value(number) = 21;
+
+ BOOST_CHECK(fn() == 42);
+ BOOST_CHECK(fn_copy() == 42);
+ }
+
+ {
+ term<std::unique_ptr<int>> number = {
+ {std::unique_ptr<int>(new int(42))}};
+
+ auto fn = yap::make_expression_function(std::move(number));
+
+ BOOST_CHECK(*fn() == 42);
+
+ auto fn_2 = std::move(fn);
+ BOOST_CHECK(*fn_2() == 42);
+
+ yap::value(number) = std::unique_ptr<int>(new int(21));
+
+ BOOST_CHECK(*fn_2() == 42);
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/fail_argument.cpp b/src/boost/libs/yap/test/fail_argument.cpp
new file mode 100644
index 00000000..69d2cc48
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_argument.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::argument(boost::yap::make_terminal(1), boost::hana::llong_c<0>);
+}
diff --git a/src/boost/libs/yap/test/fail_callable.cpp b/src/boost/libs/yap/test/fail_callable.cpp
new file mode 100644
index 00000000..ebdfe0a0
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_callable.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::callable(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_cond.cpp b/src/boost/libs/yap/test/fail_cond.cpp
new file mode 100644
index 00000000..73d2d6d4
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_cond.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::cond(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_else.cpp b/src/boost/libs/yap/test/fail_else.cpp
new file mode 100644
index 00000000..a4a65ae8
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_else.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::then(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_get.cpp b/src/boost/libs/yap/test/fail_get.cpp
new file mode 100644
index 00000000..c56f1efc
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_get.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::get(boost::yap::make_terminal(1), boost::hana::llong_c<1>);
+}
diff --git a/src/boost/libs/yap/test/fail_left.cpp b/src/boost/libs/yap/test/fail_left.cpp
new file mode 100644
index 00000000..0a6f1086
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_left.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::left(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_make_expression.cpp b/src/boost/libs/yap/test/fail_make_expression.cpp
new file mode 100644
index 00000000..3509656a
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_make_expression.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::make_expression<boost::yap::expr_kind::plus>(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_make_terminal.cpp b/src/boost/libs/yap/test/fail_make_terminal.cpp
new file mode 100644
index 00000000..59e49647
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_make_terminal.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::make_terminal(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_right.cpp b/src/boost/libs/yap/test/fail_right.cpp
new file mode 100644
index 00000000..2889df5e
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_right.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::right(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_then.cpp b/src/boost/libs/yap/test/fail_then.cpp
new file mode 100644
index 00000000..a4a65ae8
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_then.cpp
@@ -0,0 +1,12 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+int main()
+{
+ boost::yap::then(boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/fail_transform.cpp b/src/boost/libs/yap/test/fail_transform.cpp
new file mode 100644
index 00000000..54f5916b
--- /dev/null
+++ b/src/boost/libs/yap/test/fail_transform.cpp
@@ -0,0 +1,15 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+
+struct xform
+{};
+
+int main()
+{
+ boost::yap::transform(xform{}, boost::yap::make_terminal(1));
+}
diff --git a/src/boost/libs/yap/test/if_else.cpp b/src/boost/libs/yap/test/if_else.cpp
new file mode 100644
index 00000000..c3ed5204
--- /dev/null
+++ b/src/boost/libs/yap/test/if_else.cpp
@@ -0,0 +1,114 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using term_ref = boost::yap::expression_ref<boost::yap::expression, term<T> &>;
+
+template<typename T>
+using term_cref =
+ boost::yap::expression_ref<boost::yap::expression, term<T> const &>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+struct callable
+{
+ int operator()() { return 42; }
+};
+
+struct side_effect_callable_1
+{
+ int operator()()
+ {
+ *value_ = 1;
+ return 0;
+ }
+
+ int * value_;
+};
+
+struct side_effect_callable_2
+{
+ int operator()()
+ {
+ *value_ = 2;
+ return 0;
+ }
+
+ int * value_;
+};
+
+
+int test_main(int, char * [])
+{
+ {
+ int one = 0;
+ int two = 0;
+
+ auto true_nothrow_throw_expr = if_else(
+ term<bool>{{true}},
+ term<callable>{}(),
+ term<side_effect_callable_1>{{&one}}());
+
+ BOOST_CHECK(yap::evaluate(true_nothrow_throw_expr) == 42);
+ BOOST_CHECK(one == 0);
+ BOOST_CHECK(two == 0);
+ }
+
+ {
+ int one = 0;
+ int two = 0;
+
+ auto false_nothrow_throw_expr = if_else(
+ term<bool>{{false}},
+ term<callable>{}(),
+ term<side_effect_callable_1>{{&one}}());
+
+ BOOST_CHECK(yap::evaluate(false_nothrow_throw_expr) == 0);
+ BOOST_CHECK(one == 1);
+ BOOST_CHECK(two == 0);
+ }
+
+ {
+ int one = 0;
+ int two = 0;
+
+ auto true_throw1_throw2_expr = if_else(
+ term<bool>{{true}},
+ term<side_effect_callable_1>{{&one}}(),
+ term<side_effect_callable_2>{{&two}}());
+
+ BOOST_CHECK(yap::evaluate(true_throw1_throw2_expr) == 0);
+ BOOST_CHECK(one == 1);
+ BOOST_CHECK(two == 0);
+ }
+
+ {
+ int one = 0;
+ int two = 0;
+
+ auto false_throw1_throw2_expr = if_else(
+ term<bool>{{false}},
+ term<side_effect_callable_1>{{&one}}(),
+ term<side_effect_callable_2>{{&two}}());
+
+ BOOST_CHECK(yap::evaluate(false_throw1_throw2_expr) == 0);
+ BOOST_CHECK(one == 0);
+ BOOST_CHECK(two == 2);
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/lazy_vector_alloc_test.cpp b/src/boost/libs/yap/test/lazy_vector_alloc_test.cpp
new file mode 100644
index 00000000..e074247b
--- /dev/null
+++ b/src/boost/libs/yap/test/lazy_vector_alloc_test.cpp
@@ -0,0 +1,108 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <vector>
+
+#include <boost/test/minimal.hpp>
+
+
+int allocations = 0;
+
+void * operator new(std::size_t size)
+{
+ ++allocations;
+ void * retval = malloc(size);
+ if (!retval)
+ throw std::bad_alloc();
+ return retval;
+}
+
+void operator delete(void * ptr) noexcept { free(ptr); }
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct lazy_vector_expr;
+
+
+struct take_nth
+{
+ boost::yap::terminal<lazy_vector_expr, double> operator()(
+ boost::yap::terminal<lazy_vector_expr, std::vector<double>> const &
+ expr);
+
+ std::size_t n;
+};
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct lazy_vector_expr
+{
+ static const boost::yap::expr_kind kind = Kind;
+
+ Tuple elements;
+
+ auto operator[](std::size_t n) const
+ {
+ return boost::yap::evaluate(boost::yap::transform(*this, take_nth{n}));
+ }
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, lazy_vector_expr, lazy_vector_expr)
+BOOST_YAP_USER_BINARY_OPERATOR(minus, lazy_vector_expr, lazy_vector_expr)
+
+boost::yap::terminal<lazy_vector_expr, double> take_nth::operator()(
+ boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr)
+{
+ double x = boost::yap::value(expr)[n];
+ return boost::yap::make_terminal<lazy_vector_expr, double>(std::move(x));
+}
+
+struct lazy_vector : lazy_vector_expr<
+ boost::yap::expr_kind::terminal,
+ boost::hana::tuple<std::vector<double>>>
+{
+ lazy_vector() {}
+
+ explicit lazy_vector(std::vector<double> && vec)
+ {
+ elements = boost::hana::tuple<std::vector<double>>(std::move(vec));
+ }
+
+ template<boost::yap::expr_kind Kind, typename Tuple>
+ lazy_vector & operator+=(lazy_vector_expr<Kind, Tuple> const & rhs)
+ {
+ std::vector<double> & this_vec = boost::yap::value(*this);
+ for (int i = 0, size = (int)this_vec.size(); i < size; ++i) {
+ this_vec[i] += rhs[i];
+ }
+ return *this;
+ }
+};
+
+
+int test_main(int, char * [])
+{
+ lazy_vector v1{std::vector<double>(4, 1.0)};
+ lazy_vector v2{std::vector<double>(4, 2.0)};
+ lazy_vector v3{std::vector<double>(4, 3.0)};
+
+ // Reset allocation count. There should be none from this point on.
+ allocations = 0;
+
+ double d1 = (v2 + v3)[2];
+ std::cout << d1 << "\n";
+
+ v1 += v2 - v3;
+ std::cout << '{' << v1[0] << ',' << v1[1] << ',' << v1[2] << ',' << v1[3]
+ << '}' << "\n";
+
+ BOOST_CHECK(allocations == 0);
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/left.cpp b/src/boost/libs/yap/test/left.cpp
new file mode 100644
index 00000000..d6aa9d18
--- /dev/null
+++ b/src/boost/libs/yap/test/left.cpp
@@ -0,0 +1,318 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct user_expr
+{
+ static boost::yap::expr_kind const kind = Kind;
+
+ Tuple elements;
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
+
+template<typename T>
+using user_term = boost::yap::terminal<user_expr, T>;
+
+template<typename T>
+using user_ref = boost::yap::expression_ref<user_expr, T>;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr))),
+ ref<term<double> &> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ ref<term<double> &> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ ref<term<double> &> const &>));
+ }
+
+ {
+ term<double> const unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> const &>, term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr))),
+ ref<term<double> const &> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ ref<term<double> const &> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ ref<term<double> const &> const &>));
+ }
+ }
+
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+
+ using plus_plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<plus_expr_type &>, term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr_ref))),
+ ref<term<double> &> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ ref<term<double> &> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ ref<term<double> &> &>));
+ }
+ }
+
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+ plus_expr_type const plus_expr = unity + term<int>{{1}};
+
+ using plus_plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<plus_expr_type const &>, term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr_ref))),
+ ref<term<double> &> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ ref<term<double> &> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ ref<term<double> &> const &>));
+ }
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr))),
+ user_ref<user_term<double> &> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ user_ref<user_term<double> &> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ user_ref<user_term<double> &> const &>));
+ }
+
+ {
+ user_term<double> const unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> const &>, user_term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr))),
+ user_ref<user_term<double> const &> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr)),
+ user_ref<user_term<double> const &> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ decltype(yap::left(plus_expr)),
+ user_ref<user_term<double> const &> const &>));
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+
+ using plus_plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<plus_expr_type &>, user_term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr_ref))),
+ user_ref<user_term<double> &> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ user_ref<user_term<double> &> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ user_ref<user_term<double> &> &>));
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+ plus_expr_type const plus_expr = unity + user_term<int>{{1}};
+
+ using plus_plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<plus_expr_type const &>, user_term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(std::move(plus_expr_ref))),
+ user_ref<user_term<double> &> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ user_ref<user_term<double> &> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::left(plus_expr_ref)),
+ user_ref<user_term<double> &> const &>));
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/operators_unary.cpp b/src/boost/libs/yap/test/operators_unary.cpp
new file mode 100644
index 00000000..6372f3d3
--- /dev/null
+++ b/src/boost/libs/yap/test/operators_unary.cpp
@@ -0,0 +1,174 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using term_ref = boost::yap::expression_ref<boost::yap::expression, term<T> &>;
+
+template<typename T>
+using term_cref =
+ boost::yap::expression_ref<boost::yap::expression, term<T> const &>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<uint32_t> x{{2u}};
+ term<uint32_t> const cx{{3u}};
+
+ {
+ yap::expression<
+ yap::expr_kind::unary_plus,
+ bh::tuple<term<uint32_t>>>
+ term_expr = +term<uint32_t>{{1u}};
+ yap::expression<
+ yap::expr_kind::unary_plus,
+ bh::tuple<term_ref<uint32_t>>>
+ term_ref_expr = +x;
+ yap::expression<
+ yap::expr_kind::unary_plus,
+ bh::tuple<term_cref<uint32_t>>>
+ term_const_ref_expr = +cx;
+
+ BOOST_CHECK(evaluate(term_expr) == 1u);
+ BOOST_CHECK(evaluate(term_ref_expr) == 2u);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == 3u);
+ }
+
+ {
+ yap::expression<yap::expr_kind::negate, bh::tuple<term<uint32_t>>>
+ term_expr = -term<uint32_t>{{1u}};
+ yap::expression<
+ yap::expr_kind::negate,
+ bh::tuple<term_ref<uint32_t>>>
+ term_ref_expr = -x;
+ yap::expression<
+ yap::expr_kind::negate,
+ bh::tuple<term_cref<uint32_t>>>
+ term_const_ref_expr = -cx;
+
+ BOOST_CHECK(evaluate(term_expr) == 0u - 1u);
+ BOOST_CHECK(evaluate(term_ref_expr) == 0u - 2u);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == 0u - 3u);
+ }
+
+ {
+ yap::expression<
+ yap::expr_kind::complement,
+ bh::tuple<term<uint32_t>>>
+ term_expr = ~term<uint32_t>{{1u}};
+ yap::expression<
+ yap::expr_kind::complement,
+ bh::tuple<term_ref<uint32_t>>>
+ term_ref_expr = ~x;
+ yap::expression<
+ yap::expr_kind::complement,
+ bh::tuple<term_cref<uint32_t>>>
+ term_const_ref_expr = ~cx;
+
+ BOOST_CHECK(evaluate(term_expr) == 0xfffffffe);
+ BOOST_CHECK(evaluate(term_ref_expr) == 0xfffffffd);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == 0xfffffffc);
+ }
+
+ {
+ yap::expression<
+ yap::expr_kind::logical_not,
+ bh::tuple<term<uint32_t>>>
+ term_expr = !term<uint32_t>{{1u}};
+ yap::expression<
+ yap::expr_kind::logical_not,
+ bh::tuple<term_ref<uint32_t>>>
+ term_ref_expr = !x;
+ yap::expression<
+ yap::expr_kind::logical_not,
+ bh::tuple<term_cref<uint32_t>>>
+ term_const_ref_expr = !cx;
+
+ BOOST_CHECK(evaluate(term_expr) == false);
+ BOOST_CHECK(evaluate(term_ref_expr) == false);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == false);
+ }
+
+ {
+ yap::expression<yap::expr_kind::pre_inc, bh::tuple<term<uint32_t>>>
+ term_expr = ++term<uint32_t>{{1u}};
+ yap::expression<
+ yap::expr_kind::pre_inc,
+ bh::tuple<term_ref<uint32_t>>>
+ term_ref_expr = ++x;
+ yap::expression<
+ yap::expr_kind::pre_inc,
+ bh::tuple<term_cref<uint32_t>>>
+ term_const_ref_expr = ++cx;
+ (void)term_const_ref_expr;
+
+ BOOST_CHECK(evaluate(term_expr) == 2u);
+ BOOST_CHECK(evaluate(term_ref_expr) == 3u);
+ }
+ }
+
+ {
+ {
+ uint32_t i = 1, j = 2, k = 3;
+ term<uint32_t &> x{{j}};
+ term<uint32_t &> const cx{{k}};
+
+ yap::expression<
+ yap::expr_kind::address_of,
+ bh::tuple<term<uint32_t &>>>
+ term_expr = &term<uint32_t &>{{i}};
+ yap::expression<
+ yap::expr_kind::address_of,
+ bh::tuple<term_ref<uint32_t &>>>
+ term_ref_expr = &x;
+ yap::expression<
+ yap::expr_kind::address_of,
+ bh::tuple<term_cref<uint32_t &>>>
+ term_const_ref_expr = &cx;
+
+ BOOST_CHECK(evaluate(term_expr) == &i);
+ BOOST_CHECK(evaluate(term_ref_expr) == &j);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == &k);
+ }
+
+ {
+ uint32_t i = 1, j = 2, k = 3;
+ term<uint32_t *> x{{&j}};
+ term<uint32_t *> const cx{{&k}};
+
+ yap::expression<
+ yap::expr_kind::dereference,
+ bh::tuple<term<uint32_t *>>>
+ term_expr = *term<uint32_t *>{{&i}};
+ yap::expression<
+ yap::expr_kind::dereference,
+ bh::tuple<term_ref<uint32_t *>>>
+ term_ref_expr = *x;
+ yap::expression<
+ yap::expr_kind::dereference,
+ bh::tuple<term_cref<uint32_t *>>>
+ term_const_ref_expr = *cx;
+
+ BOOST_CHECK(evaluate(term_expr) == i);
+ BOOST_CHECK(evaluate(term_ref_expr) == j);
+ BOOST_CHECK(evaluate(term_const_ref_expr) == k);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/placeholder_eval.cpp b/src/boost/libs/yap/test/placeholder_eval.cpp
new file mode 100644
index 00000000..76f9c378
--- /dev/null
+++ b/src/boost/libs/yap/test/placeholder_eval.cpp
@@ -0,0 +1,65 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<long long I>
+using place_term =
+ boost::yap::terminal<boost::yap::expression, boost::yap::placeholder<I>>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+int test_main(int, char * [])
+{
+ {
+ using namespace boost::yap::literals;
+
+ place_term<3> p3 = 3_p;
+ int i_ = 42;
+ term<int> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<place_term<3> &>, term<int>>>
+ expr = p3 + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<place_term<3> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<place_term<3> &>, term<int>>>>>
+ unevaluated_expr = p3 + std::move(expr);
+
+ {
+ double result = evaluate(p3, 5, 6, 7);
+ BOOST_CHECK(result == 7);
+ }
+
+ {
+ double result = evaluate(expr, std::string("15"), 3, 1);
+ BOOST_CHECK(result == 43);
+ }
+
+ {
+ double result = evaluate(unevaluated_expr, std::string("15"), 2, 3);
+ BOOST_CHECK(result == 48);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/print.cpp b/src/boost/libs/yap/test/print.cpp
new file mode 100644
index 00000000..106dcea4
--- /dev/null
+++ b/src/boost/libs/yap/test/print.cpp
@@ -0,0 +1,1595 @@
+// 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)
+#include <boost/yap/expression.hpp>
+#include <boost/yap/print.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+#include <regex>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct user_expr
+{
+ static boost::yap::expr_kind const kind = Kind;
+
+ Tuple elements;
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
+
+template<typename T>
+using user_term = boost::yap::terminal<user_expr, T>;
+
+template<typename T>
+using user_ref = boost::yap::expression_ref<user_expr, T>;
+
+struct thing
+{};
+
+std::string fix_tti(std::string s)
+{
+ // msvc: remove struct/class prefixes
+ static const std::regex estruct("(struct|class) ");
+ s = std::regex_replace(s, estruct, "");
+
+ // gcc/clang: strip integral literals suffixes
+ static const std::regex eint("(\\d)u?l{0,2}");
+ s = std::regex_replace(s, eint, "$1");
+
+ return s;
+}
+
+int test_main(int, char * [])
+{
+ {
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::terminal) == std::string("term"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::unary_plus) == std::string("+"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::negate) == std::string("-"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::dereference) == std::string("*"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::complement) == std::string("~"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::address_of) == std::string("&"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::logical_not) == std::string("!"));
+
+ BOOST_CHECK(yap::op_string(yap::expr_kind::pre_inc) == std::string("++"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::pre_dec) == std::string("--"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::post_inc) == std::string("++(int)"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::post_dec) == std::string("--(int)"));
+
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::shift_left) == std::string("<<"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::shift_right) == std::string(">>"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::multiplies) == std::string("*"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::divides) == std::string("/"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::modulus) == std::string("%"));
+
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::multiplies_assign) ==
+ std::string("*="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::divides_assign) ==
+ std::string("/="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::modulus_assign) ==
+ std::string("%="));
+
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::plus_assign) == std::string("+="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::minus_assign) == std::string("-="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::bitwise_and_assign) ==
+ std::string("&="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::bitwise_or_assign) ==
+ std::string("|="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::bitwise_xor_assign) ==
+ std::string("^="));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind::subscript) == std::string("[]"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::if_else) == std::string("?:"));
+ BOOST_CHECK(yap::op_string(yap::expr_kind::call) == std::string("()"));
+ BOOST_CHECK(
+ yap::op_string(yap::expr_kind(-1)) ==
+ std::string("** ERROR: UNKNOWN OPERATOR! **"));
+ }
+
+ {
+ user_term<double> unity{1.0};
+ int i_ = 42;
+ user_term<int &&> i{std::move(i_)};
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int &&>>>
+ expr = unity + std::move(i);
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<
+ user_ref<user_term<double> &>,
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<
+ user_ref<user_term<double> &>,
+ user_term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ expr<+>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ user_term<thing> a_thing{bh::make_tuple(thing{})};
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ user_term<double> const const_unity{1.0};
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<
+ user_ref<user_term<double> &>,
+ user_ref<user_term<double> const &>>>
+ nonconst_plus_const = unity + const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_plus_const);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ auto nonconst_plus_nonconst_plus_const = unity + nonconst_plus_const;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_plus_nonconst_plus_const);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ expr<+> &
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ auto const const_nonconst_plus_const = nonconst_plus_const;
+ auto nonconst_plus_nonconst_plus_const_2 =
+ unity + const_nonconst_plus_const;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_plus_nonconst_plus_const_2);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ expr<+> const &
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity + std::move(i);
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity + std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ expr<+>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_plus_const = unity + const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_plus_const);
+ BOOST_CHECK(oss.str() == R"(expr<+>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity - std::move(i);
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity - std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<->
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<->
+ term<double>[=1] &
+ expr<->
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::minus,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_minus_const = unity - const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_minus_const);
+ BOOST_CHECK(oss.str() == R"(expr<->
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::less,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity < std::move(i);
+ yap::expression<
+ yap::expr_kind::less,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::less,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity < std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<<>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<<>
+ term<double>[=1] &
+ expr<<>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::less,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_less_const = unity < const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_less_const);
+ BOOST_CHECK(oss.str() == R"(expr<<>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::greater,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity > std::move(i);
+ yap::expression<
+ yap::expr_kind::greater,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::greater,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity > std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<>>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<>>
+ term<double>[=1] &
+ expr<>>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::greater,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_greater_const = unity > const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_greater_const);
+ BOOST_CHECK(oss.str() == R"(expr<>>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::less_equal,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity <= std::move(i);
+ yap::expression<
+ yap::expr_kind::less_equal,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::less_equal,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity <= std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<<=>
+ term<double>[=1] &
+ expr<<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::less_equal,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_less_equal_const = unity <= const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_less_equal_const);
+ BOOST_CHECK(oss.str() == R"(expr<<=>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::greater_equal,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity >= std::move(i);
+ yap::expression<
+ yap::expr_kind::greater_equal,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::greater_equal,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity >= std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<>=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<>=>
+ term<double>[=1] &
+ expr<>=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::greater_equal,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_greater_equal_const = unity >= const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_greater_equal_const);
+ BOOST_CHECK(oss.str() == R"(expr<>=>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::equal_to,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity == std::move(i);
+ yap::expression<
+ yap::expr_kind::equal_to,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::equal_to,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity == std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<==>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<==>
+ term<double>[=1] &
+ expr<==>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::equal_to,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_equal_to_const = unity == const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_equal_to_const);
+ BOOST_CHECK(oss.str() == R"(expr<==>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::not_equal_to,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity != std::move(i);
+ yap::expression<
+ yap::expr_kind::not_equal_to,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::not_equal_to,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity != std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<!=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<!=>
+ term<double>[=1] &
+ expr<!=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::not_equal_to,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_not_equal_to_const = unity != const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_not_equal_to_const);
+ BOOST_CHECK(oss.str() == R"(expr<!=>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::logical_or,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity || std::move(i);
+ yap::expression<
+ yap::expr_kind::logical_or,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::logical_or,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity || std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<||>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<||>
+ term<double>[=1] &
+ expr<||>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::logical_or,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_logical_or_const = unity || const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_logical_or_const);
+ BOOST_CHECK(oss.str() == R"(expr<||>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::logical_and,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity && std::move(i);
+ yap::expression<
+ yap::expr_kind::logical_and,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::logical_and,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity && std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<&&>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<&&>
+ term<double>[=1] &
+ expr<&&>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::logical_and,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_logical_and_const = unity && const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_logical_and_const);
+ BOOST_CHECK(oss.str() == R"(expr<&&>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::bitwise_and,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity & std::move(i);
+ yap::expression<
+ yap::expr_kind::bitwise_and,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::bitwise_and,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity & std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<&>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<&>
+ term<double>[=1] &
+ expr<&>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::bitwise_and,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_bitwise_and_const = unity & const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_bitwise_and_const);
+ BOOST_CHECK(oss.str() == R"(expr<&>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::bitwise_or,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity | std::move(i);
+ yap::expression<
+ yap::expr_kind::bitwise_or,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::bitwise_or,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity | std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<|>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<|>
+ term<double>[=1] &
+ expr<|>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::bitwise_or,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_bitwise_or_const = unity | const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_bitwise_or_const);
+ BOOST_CHECK(oss.str() == R"(expr<|>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::bitwise_xor,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity ^ std::move(i);
+ yap::expression<
+ yap::expr_kind::bitwise_xor,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::bitwise_xor,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity ^ std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<^>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<^>
+ term<double>[=1] &
+ expr<^>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::bitwise_xor,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_bitwise_xor_const = unity ^ const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_bitwise_xor_const);
+ BOOST_CHECK(oss.str() == R"(expr<^>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::comma,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = (unity, std::move(i));
+ yap::expression<
+ yap::expr_kind::comma,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::comma,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = (unity, std::move(expr));
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<,>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<,>
+ term<double>[=1] &
+ expr<,>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::comma,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_comma_const = (unity, const_unity);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_comma_const);
+ BOOST_CHECK(oss.str() == R"(expr<,>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::mem_ptr,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity->*std::move(i);
+ yap::expression<
+ yap::expr_kind::mem_ptr,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::mem_ptr,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity->*std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<->*>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<->*>
+ term<double>[=1] &
+ expr<->*>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::mem_ptr,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_mem_ptr_const = unity->*const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_mem_ptr_const);
+ BOOST_CHECK(oss.str() == R"(expr<->*>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity = std::move(i);
+ yap::expression<
+ yap::expr_kind::assign,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity = std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<=>
+ term<double>[=1] &
+ expr<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::shift_left_assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity <<= std::move(i);
+ yap::expression<
+ yap::expr_kind::shift_left_assign,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::shift_left_assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity <<= std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<<<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<<<=>
+ term<double>[=1] &
+ expr<<<=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::shift_left_assign,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_shift_left_assign_const = unity <<= const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_shift_left_assign_const);
+ BOOST_CHECK(oss.str() == R"(expr<<<=>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ int i_ = 42;
+ term<int &&> i{std::move(i_)};
+ yap::expression<
+ yap::expr_kind::shift_right_assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>
+ expr = unity >>= std::move(i);
+ yap::expression<
+ yap::expr_kind::shift_right_assign,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::shift_right_assign,
+ bh::tuple<ref<term<double> &>, term<int &&>>>>>
+ unevaluated_expr = unity >>= std::move(expr);
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unity);
+ BOOST_CHECK(oss.str() == R"(term<double>[=1]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, expr);
+ BOOST_CHECK(oss.str() == R"(expr<>>=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, unevaluated_expr);
+ BOOST_CHECK(oss.str() == R"(expr<>>=>
+ term<double>[=1] &
+ expr<>>=>
+ term<double>[=1] &
+ term<int &&>[=42]
+)");
+ }
+
+ term<thing> a_thing(thing{});
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, a_thing);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
+)");
+ }
+
+ term<double> const const_unity{1.0};
+ yap::expression<
+ yap::expr_kind::shift_right_assign,
+ bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
+ nonconst_shift_right_assign_const = unity >>= const_unity;
+
+ {
+ std::ostringstream oss;
+ yap::print(oss, nonconst_shift_right_assign_const);
+ BOOST_CHECK(oss.str() == R"(expr<>>=>
+ term<double>[=1] &
+ term<double>[=1] const &
+)");
+ }
+
+ {
+ using namespace yap::literals;
+ std::ostringstream oss;
+ yap::print(oss, 1_p);
+ BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
+)");
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/reference_returns.cpp b/src/boost/libs/yap/test/reference_returns.cpp
new file mode 100644
index 00000000..e03e9a3c
--- /dev/null
+++ b/src/boost/libs/yap/test/reference_returns.cpp
@@ -0,0 +1,89 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+
+namespace reference_returning {
+
+ struct number
+ {
+ double value;
+ };
+
+ number a_result{3.0};
+ number const the_result{13.0};
+
+ number const & operator+(number a, number b) { return the_result; }
+
+ number & operator-(number a, number b) { return a_result; }
+}
+
+int test_main(int, char * [])
+{
+ {
+ term<reference_returning::number> unity = {{1.0}};
+ auto plus_expr = unity + reference_returning::number{1.0};
+
+ {
+ reference_returning::number const & n = evaluate(plus_expr);
+ BOOST_CHECK(&n == &reference_returning::the_result);
+ }
+
+ using plus_eval_type = decltype(evaluate(plus_expr));
+ BOOST_MPL_ASSERT((std::is_same<
+ plus_eval_type,
+ reference_returning::number const &>));
+
+ auto minus_expr = unity - reference_returning::number{1.0};
+
+ {
+ reference_returning::number & n = evaluate(minus_expr);
+ BOOST_CHECK(&n == &reference_returning::a_result);
+ }
+
+ using minus_eval_type = decltype(evaluate(minus_expr));
+ BOOST_MPL_ASSERT((std::is_same<
+ minus_eval_type,
+ reference_returning::number &>));
+
+ using namespace yap::literals;
+
+ {
+ reference_returning::number & n =
+ evaluate(1_p, reference_returning::a_result);
+ BOOST_CHECK(&n == &reference_returning::a_result);
+ }
+
+ using a_eval_type = decltype(evaluate(1_p, reference_returning::a_result));
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ a_eval_type,
+ reference_returning::number &>));
+
+ {
+ reference_returning::number const & n =
+ evaluate(1_p, reference_returning::the_result);
+ BOOST_CHECK(&n == &reference_returning::the_result);
+ }
+
+ using the_eval_type = decltype(evaluate(1_p, reference_returning::the_result));
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ the_eval_type,
+ reference_returning::number const &>));
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/right.cpp b/src/boost/libs/yap/test/right.cpp
new file mode 100644
index 00000000..6a868423
--- /dev/null
+++ b/src/boost/libs/yap/test/right.cpp
@@ -0,0 +1,264 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct user_expr
+{
+ static boost::yap::expr_kind const kind = Kind;
+
+ Tuple elements;
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
+
+template<typename T>
+using user_term = boost::yap::terminal<user_expr, T>;
+
+template<typename T>
+using user_ref = boost::yap::expression_ref<user_expr, T>;
+
+
+int test_main(int, char * [])
+{
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(std::move(plus_expr))),
+ term<int> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::right(plus_expr)), term<int> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr)),
+ term<int> const &>));
+ }
+
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+
+ using plus_plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<plus_expr_type &>, term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ decltype(yap::right(std::move(plus_expr_ref))),
+ term<int> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ term<int> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ term<int> &>));
+ }
+ }
+
+ {
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+ plus_expr_type const plus_expr = unity + term<int>{{1}};
+
+ using plus_plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<plus_expr_type const &>, term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ decltype(yap::right(std::move(plus_expr_ref))),
+ term<int> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ term<int> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr = plus_expr + term<int>{{1}};
+ ref<plus_expr_type const &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ term<int> const &>));
+ }
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(std::move(plus_expr))),
+ user_term<int> &&>));
+ }
+
+ {
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr)),
+ user_term<int> &>));
+ }
+
+ {
+ plus_expr_type const plus_expr = unity + user_term<int>{{1}};
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr)),
+ user_term<int> const &>));
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+
+ using plus_plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<plus_expr_type &>, user_term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ decltype(yap::right(std::move(plus_expr_ref))),
+ user_term<int> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ user_term<int> &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ user_term<int> &>));
+ }
+ }
+
+ {
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+ plus_expr_type const plus_expr = unity + user_term<int>{{1}};
+
+ using plus_plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<plus_expr_type const &>, user_term<int>>>;
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<
+ decltype(yap::right(std::move(plus_expr_ref))),
+ user_term<int> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ user_term<int> const &>));
+ }
+
+ {
+ plus_plus_expr_type plus_plus_expr =
+ plus_expr + user_term<int>{{1}};
+ user_ref<plus_expr_type const &> const plus_expr_ref =
+ bh::front(plus_plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::right(plus_expr_ref)),
+ user_term<int> const &>));
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/transform.cpp b/src/boost/libs/yap/test/transform.cpp
new file mode 100644
index 00000000..edca1670
--- /dev/null
+++ b/src/boost/libs/yap/test/transform.cpp
@@ -0,0 +1,78 @@
+// 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)
+#include <boost/yap/yap.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+#include <sstream>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::minimal_expr, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+struct iota_terminal_transform
+{
+ template<typename T>
+ auto operator()(boost::yap::expr_tag<boost::yap::expr_kind::terminal>, T && t)
+ {
+ return boost::yap::make_terminal(index_++);
+ }
+
+ template<typename CallableExpr, typename... Arg>
+ auto operator()(boost::yap::expr_tag<boost::yap::expr_kind::call>,
+ CallableExpr callable, Arg &&... arg)
+ {
+ return boost::yap::make_expression<boost::yap::expr_kind::call>(
+ callable, boost::yap::transform(arg, *this)...);
+ }
+
+ int index_;
+};
+
+struct plus_expr_t
+{
+ static yap::expr_kind const kind = yap::expr_kind::plus;
+
+ bh::tuple<term<int>, term<int>> elements;
+};
+
+int test_main(int, char * [])
+{
+ // Each node instantiated from from yap::expression.
+ {
+ auto plus_expr = yap::terminal<yap::expression, int>{{5}} + 6;
+
+ BOOST_CHECK(yap::evaluate(plus_expr) == 11);
+
+ BOOST_CHECK(
+ yap::evaluate(
+ yap::transform(plus_expr, iota_terminal_transform{0})) == 1);
+ }
+
+ // Each node instantiated from from yap::minimal_expr.
+ {
+ yap::minimal_expr<yap::expr_kind::plus, bh::tuple<term<int>, term<int>>>
+ plus_expr;
+
+ yap::evaluate(yap::transform(plus_expr, iota_terminal_transform{0}), 1);
+ }
+
+ // Leaves are instantiated from from yap::minimal_expr; nonterminal
+ // expr_kind::plus does not even come from a template.
+ {
+ plus_expr_t plus_expr;
+
+ yap::evaluate(yap::transform(plus_expr, iota_terminal_transform{0}), 1);
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/user_expression_transform_1.cpp b/src/boost/libs/yap/test/user_expression_transform_1.cpp
new file mode 100644
index 00000000..b58b6e25
--- /dev/null
+++ b/src/boost/libs/yap/test/user_expression_transform_1.cpp
@@ -0,0 +1,948 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+namespace user {
+
+ struct number
+ {
+ double value;
+
+ friend number operator+(number lhs, number rhs)
+ {
+ return number{lhs.value + rhs.value};
+ }
+
+ friend number operator-(number lhs, number rhs)
+ {
+ return number{lhs.value - rhs.value};
+ }
+
+ friend number operator*(number lhs, number rhs)
+ {
+ return number{lhs.value * rhs.value};
+ }
+
+ friend number operator-(number n) { return number{-n.value}; }
+
+ friend bool operator<(number lhs, double rhs)
+ {
+ return lhs.value < rhs;
+ }
+
+ friend bool operator<(double lhs, number rhs)
+ {
+ return lhs < rhs.value;
+ }
+ };
+
+ number naxpy(number a, number x, number y)
+ {
+ return number{a.value * x.value + y.value + 10.0};
+ }
+
+ struct empty_xform
+ {};
+
+ struct eval_xform_tag
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return n;
+ }
+ };
+
+ struct eval_xform_expr
+ {
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ return ::boost::yap::value(expr);
+ }
+ };
+
+ struct eval_xform_both
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return n;
+ }
+
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return ::boost::yap::value(expr);
+ }
+ };
+
+ struct plus_to_minus_xform_tag
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ user::number const & lhs,
+ user::number const & rhs)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ term<user::number>{lhs}, term<user::number>{rhs});
+ }
+ };
+
+ struct plus_to_minus_xform_expr
+ {
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ ::boost::yap::left(expr), ::boost::yap::right(expr));
+ }
+ };
+
+ struct plus_to_minus_xform_both
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ user::number const & lhs,
+ user::number const & rhs)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ term<user::number>{lhs}, term<user::number>{rhs});
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return yap::make_expression<yap::expr_kind::minus>(
+ ::boost::yap::left(expr), ::boost::yap::right(expr));
+ }
+ };
+
+ struct term_nonterm_xform_tag
+ {
+ auto operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return yap::make_terminal(n * user::number{2.0});
+ }
+
+ auto operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ user::number const & lhs,
+ user::number const & rhs)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ yap::transform(::boost::yap::make_terminal(lhs), *this),
+ yap::transform(::boost::yap::make_terminal(rhs), *this));
+ }
+ };
+
+ struct term_nonterm_xform_expr
+ {
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ return yap::make_terminal(
+ ::boost::yap::value(expr) * user::number{2.0});
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ yap::transform(::boost::yap::left(expr), *this),
+ yap::transform(::boost::yap::right(expr), *this));
+ }
+ };
+
+ struct term_nonterm_xform_both
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return yap::make_terminal(n * user::number{2.0});
+ }
+
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ return yap::make_terminal(
+ ::boost::yap::value(expr) * user::number{2.0});
+ }
+
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ user::number const & lhs,
+ user::number const & rhs)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ yap::transform(::boost::yap::make_terminal(lhs), *this),
+ yap::transform(::boost::yap::make_terminal(rhs), *this));
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ return yap::make_expression<yap::expr_kind::minus>(
+ yap::transform(::boost::yap::left(expr), *this),
+ yap::transform(::boost::yap::right(expr), *this));
+ }
+ };
+
+ struct eval_term_nonterm_xform_tag
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return n * user::number{2.0};
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ Expr1 const & lhs,
+ Expr2 const & rhs)
+ {
+ return boost::yap::transform(::boost::yap::as_expr(lhs), *this) -
+ boost::yap::transform(::boost::yap::as_expr(rhs), *this);
+ }
+ };
+
+ struct eval_term_nonterm_xform_expr
+ {
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ return ::boost::yap::value(expr) * user::number{2.0};
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ return boost::yap::transform(::boost::yap::left(expr), *this) -
+ boost::yap::transform(::boost::yap::right(expr), *this);
+ }
+ };
+
+ struct eval_term_nonterm_xform_both
+ {
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
+ {
+ return n * user::number{2.0};
+ }
+
+ decltype(auto) operator()(term<user::number> const & expr)
+ {
+ return ::boost::yap::value(expr) * user::number{2.0};
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::plus>,
+ Expr1 const & lhs,
+ Expr2 const & rhs)
+ {
+ return boost::yap::transform(::boost::yap::as_expr(lhs), *this) -
+ boost::yap::transform(::boost::yap::as_expr(rhs), *this);
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ return boost::yap::transform(::boost::yap::left(expr), *this) -
+ boost::yap::transform(::boost::yap::right(expr), *this);
+ }
+ };
+
+ decltype(auto)
+ naxpy_eager_nontemplate_xform(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ yap::expression<
+ yap::expr_kind::multiplies,
+ bh::tuple<
+ ref<term<user::number> &>,
+ ref<term<user::number> &>>>,
+ ref<term<user::number> &>>> const & expr)
+ {
+ auto a = evaluate(expr.left().left());
+ auto x = evaluate(expr.left().right());
+ auto y = evaluate(expr.right());
+ return yap::make_terminal(naxpy(a, x, y));
+ }
+
+ decltype(auto)
+ naxpy_lazy_nontemplate_xform(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ yap::expression<
+ yap::expr_kind::multiplies,
+ bh::tuple<
+ ref<term<user::number> &>,
+ ref<term<user::number> &>>>,
+ ref<term<user::number> &>>> const & expr)
+ {
+ decltype(auto) a = expr.left().left().value();
+ decltype(auto) x = expr.left().right().value();
+ decltype(auto) y = expr.right().value();
+ return yap::make_terminal(naxpy)(a, x, y);
+ }
+
+ struct naxpy_xform
+ {
+ template<typename Expr1, typename Expr2, typename Expr3>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ yap::expression<
+ yap::expr_kind::multiplies,
+ bh::tuple<Expr1, Expr2>>,
+ Expr3>> const & expr)
+ {
+ return yap::make_terminal(naxpy)(
+ transform(expr.left().left(), naxpy_xform{}),
+ transform(expr.left().right(), naxpy_xform{}),
+ transform(expr.right(), naxpy_xform{}));
+ }
+ };
+
+
+ // unary transforms
+
+ struct disable_negate_xform_tag
+ {
+ auto
+ operator()(yap::expr_tag<yap::expr_kind::negate>, user::number value)
+ {
+ return yap::make_terminal(std::move(value));
+ }
+
+ template<typename Expr>
+ auto
+ operator()(yap::expr_tag<yap::expr_kind::negate>, Expr const & expr)
+ {
+ return expr;
+ }
+ };
+
+ struct disable_negate_xform_expr
+ {
+ template<typename Expr>
+ decltype(auto) operator()(
+ yap::expression<yap::expr_kind::negate, bh::tuple<Expr>> const &
+ expr)
+ {
+ return ::boost::yap::value(expr);
+ }
+ };
+
+ struct disable_negate_xform_both
+ {
+ decltype(auto)
+ operator()(yap::expr_tag<yap::expr_kind::negate>, user::number value)
+ {
+ return yap::make_terminal(std::move(value));
+ }
+
+ template<typename Expr>
+ decltype(auto)
+ operator()(yap::expr_tag<yap::expr_kind::negate>, Expr const & expr)
+ {
+ return expr;
+ }
+
+ template<typename Expr>
+ decltype(auto) operator()(
+ yap::expression<yap::expr_kind::negate, bh::tuple<Expr>> const &
+ expr)
+ {
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return ::boost::yap::value(expr);
+ }
+ };
+
+
+ // ternary transforms
+
+ //[ tag_xform
+ struct ternary_to_else_xform_tag
+ {
+ template<typename Expr>
+ decltype(auto) operator()(
+ boost::yap::expr_tag<yap::expr_kind::if_else>,
+ Expr const & cond,
+ user::number then,
+ user::number else_)
+ {
+ return boost::yap::make_terminal(std::move(else_));
+ }
+ };
+ //]
+
+ //[ expr_xform
+ struct ternary_to_else_xform_expr
+ {
+ template<typename Cond, typename Then, typename Else>
+ decltype(auto)
+ operator()(boost::yap::expression<
+ boost::yap::expr_kind::if_else,
+ boost::hana::tuple<Cond, Then, Else>> const & expr)
+ {
+ return ::boost::yap::else_(expr);
+ }
+ };
+ //]
+
+ struct ternary_to_else_xform_both
+ {
+ template<typename Expr>
+ decltype(auto) operator()(
+ yap::expr_tag<yap::expr_kind::if_else>,
+ Expr const & cond,
+ user::number then,
+ user::number else_)
+ {
+ return yap::make_terminal(std::move(else_));
+ }
+
+ template<typename Cond, typename Then, typename Else>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::if_else,
+ bh::tuple<Cond, Then, Else>> const & expr)
+ {
+ throw std::logic_error("Oops! Picked the wrong overload!");
+ return ::boost::yap::else_(expr);
+ }
+ };
+}
+
+auto double_to_float(term<double> expr)
+{
+ return term<float>{(float)expr.value()};
+}
+
+auto check_unique_ptrs_equal_7(term<std::unique_ptr<int>> && expr)
+{
+ using namespace boost::hana::literals;
+ BOOST_CHECK(*expr.elements[0_c] == 7);
+ return std::move(expr);
+}
+
+int test_main(int, char * [])
+{
+ {
+ term<user::number> a{{1.0}};
+ term<user::number> x{{42.0}};
+ term<user::number> y{{3.0}};
+
+ {
+ auto expr = a;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ auto transformed_expr = transform(expr, user::empty_xform{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ auto transformed_expr = transform(expr, user::eval_xform_tag{});
+ BOOST_CHECK(transformed_expr.value == 1);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::eval_xform_expr{});
+ BOOST_CHECK(transformed_expr.value == 1);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::eval_xform_both{});
+ BOOST_CHECK(transformed_expr.value == 1);
+ }
+ }
+
+ {
+ auto expr = x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::plus_to_minus_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::plus_to_minus_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::plus_to_minus_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39);
+ }
+ }
+
+ {
+ auto expr = x + user::number{3.0};
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+ }
+
+ {
+ auto expr = x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+ }
+
+ {
+ auto expr = (x + y) + user::number{1.0};
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 46);
+ }
+
+ {
+ // Differs from those below, because it matches terminals, not
+ // expressions.
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 40 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 38 * 2);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::term_nonterm_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 38 * 2);
+ }
+ }
+
+ {
+ auto expr = x + user::number{3.0};
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_tag{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_expr{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_both{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+ }
+
+ {
+ auto expr = x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_tag{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_expr{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_both{});
+ BOOST_CHECK(result.value == 39 * 2);
+ }
+ }
+
+ {
+ auto expr = (x + y) + user::number{1.0};
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 46);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_tag{});
+ BOOST_CHECK(result.value == 38 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_expr{});
+ BOOST_CHECK(result.value == 38 * 2);
+ }
+
+ {
+ user::number result =
+ transform(expr, user::eval_term_nonterm_xform_both{});
+ BOOST_CHECK(result.value == 38 * 2);
+ }
+ }
+
+ {
+ auto expr = a * x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ auto transformed_expr =
+ transform(expr, user::naxpy_eager_nontemplate_xform);
+ {
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 55);
+ }
+ }
+
+ {
+ auto expr = a + (a * x + y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 46);
+ }
+
+ auto transformed_expr =
+ transform(expr, user::naxpy_eager_nontemplate_xform);
+ {
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 56);
+ }
+ }
+
+ {
+ auto expr = a * x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ auto transformed_expr =
+ transform(expr, user::naxpy_lazy_nontemplate_xform);
+ {
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 55);
+ }
+ }
+
+ {
+ auto expr = a + (a * x + y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 46);
+ }
+
+ auto transformed_expr =
+ transform(expr, user::naxpy_lazy_nontemplate_xform);
+ {
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 56);
+ }
+ }
+
+ {
+ auto expr = (a * x + y) * (a * x + y) + (a * x + y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 45 * 45 + 45);
+ }
+
+ auto transformed_expr = transform(expr, user::naxpy_xform{});
+ {
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 55 * 55 + 55 + 10);
+ }
+ }
+ }
+
+ {
+ term<double> unity{1.0};
+ term<std::unique_ptr<int>> i{new int{7}};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<std::unique_ptr<int>>>>
+ expr_1 = unity + std::move(i);
+
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<
+ ref<term<double> &>,
+ term<std::unique_ptr<int>>>>>>
+ expr_2 = unity + std::move(expr_1);
+
+ auto transformed_expr = transform(std::move(expr_2), double_to_float);
+
+ transform(std::move(transformed_expr), check_unique_ptrs_equal_7);
+ }
+
+ {
+ term<user::number> a{{1.0}};
+ term<user::number> x{{42.0}};
+ term<user::number> y{{3.0}};
+
+ {
+ auto expr = -x;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == -42);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 42);
+ }
+ }
+
+ {
+ auto expr = a * -x + y;
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == -39);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+ }
+
+ {
+ auto expr = -(x + y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == -45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::disable_negate_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 45);
+ }
+ }
+ }
+
+ {
+ term<user::number> a{{1.0}};
+ term<user::number> x{{42.0}};
+ term<user::number> y{{3.0}};
+
+ {
+ auto expr = if_else(0 < a, x, y);
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 3);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 3);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 3);
+ }
+ }
+
+ {
+ auto expr = y * if_else(0 < a, x, y) + user::number{0.0};
+ {
+ user::number result = evaluate(expr);
+ BOOST_CHECK(result.value == 126);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_tag{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 9);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_expr{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 9);
+ }
+
+ {
+ auto transformed_expr =
+ transform(expr, user::ternary_to_else_xform_both{});
+ user::number result = evaluate(transformed_expr);
+ BOOST_CHECK(result.value == 9);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/user_expression_transform_2.cpp b/src/boost/libs/yap/test/user_expression_transform_2.cpp
new file mode 100644
index 00000000..da231b4b
--- /dev/null
+++ b/src/boost/libs/yap/test/user_expression_transform_2.cpp
@@ -0,0 +1,257 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+namespace user {
+
+ struct number
+ {
+ double value;
+ };
+
+ struct eval_xform
+ {
+ auto
+ operator()(yap::expr_tag<yap::expr_kind::terminal>, number const & n)
+ {
+ return n;
+ }
+
+ template<typename Expr>
+ decltype(auto) operator()(
+ yap::expression<yap::expr_kind::negate, bh::tuple<Expr>> const &
+ expr)
+ {
+ number const n = transform(yap::value(expr), *this);
+ return number{-n.value};
+ }
+
+ template<typename Expr1, typename Expr2>
+ decltype(auto) operator()(yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<Expr1, Expr2>> const & expr)
+ {
+ number const lhs = transform(yap::left(expr), *this);
+ number const rhs = transform(yap::right(expr), *this);
+ return number{lhs.value + rhs.value};
+ }
+ };
+}
+
+template<typename Expr>
+auto make_ref(Expr && expr)
+{
+ using type = yap::detail::operand_type_t<yap::expression, Expr>;
+ return yap::detail::make_operand<type>{}(static_cast<Expr &&>(expr));
+}
+
+int test_main(int, char * [])
+{
+{
+ {
+ term<user::number> a{{1.0}};
+
+ {
+ user::number result = transform(a, user::eval_xform{});
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ user::number result = transform(make_ref(a), user::eval_xform{});
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ user::number result = transform(-a, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr = make_ref(a);
+ user::number result = transform(-expr, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr = -a;
+ user::number result = transform(expr, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr1 = make_ref(a);
+ auto expr2 = make_ref(expr1);
+ user::number result = transform(expr2, user::eval_xform{});
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ auto expr1 = -a;
+ auto expr2 = make_ref(expr1);
+ user::number result = transform(expr2, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr1 = make_ref(a);
+ auto expr2 = -expr1;
+ user::number result = transform(expr2, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr1 = a;
+ auto expr2 = make_ref(expr1);
+ auto expr3 = make_ref(expr2);
+ user::number result = transform(expr3, user::eval_xform{});
+ BOOST_CHECK(result.value == 1);
+ }
+
+ {
+ auto expr1 = -a;
+ auto expr2 = make_ref(expr1);
+ auto expr3 = make_ref(expr2);
+ user::number result = transform(expr3, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr1 = make_ref(a);
+ auto expr2 = -expr1;
+ auto expr3 = make_ref(expr2);
+ user::number result = transform(expr3, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+
+ {
+ auto expr1 = make_ref(a);
+ auto expr2 = make_ref(expr1);
+ auto expr3 = -expr2;
+ user::number result = transform(expr3, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+ }
+
+ {
+ user::number result =
+ transform(-term<user::number>{{1.0}}, user::eval_xform{});
+ BOOST_CHECK(result.value == -1);
+ }
+}
+
+{
+ term<user::number> a{{1.0}};
+ term<user::number> x{{41.0}};
+
+ {
+ user::number result = transform(a + x, user::eval_xform{});
+ BOOST_CHECK(result.value == 42);
+ }
+
+
+ {
+ user::number result =
+ transform(make_ref(a) + make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ user::number result = transform(make_ref(a) + x, user::eval_xform{});
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ user::number result = transform(a + make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == 42);
+ }
+
+ {
+ user::number result = transform(a + x, user::eval_xform{});
+ BOOST_CHECK(result.value == 42);
+ }
+
+
+ {
+ user::number result =
+ transform(-make_ref(a) + make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == 40);
+ }
+
+ {
+ user::number result = transform(-make_ref(a) + x, user::eval_xform{});
+ BOOST_CHECK(result.value == 40);
+ }
+
+ {
+ user::number result = transform(-a + make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == 40);
+ }
+
+ {
+ user::number result = transform(-a + x, user::eval_xform{});
+ BOOST_CHECK(result.value == 40);
+ }
+
+
+ {
+ user::number result =
+ transform(make_ref(a) + -make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == -40);
+ }
+
+ {
+ user::number result = transform(make_ref(a) + -x, user::eval_xform{});
+ BOOST_CHECK(result.value == -40);
+ }
+
+ {
+ user::number result = transform(a + -make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == -40);
+ }
+
+ {
+ user::number result = transform(a + -x, user::eval_xform{});
+ BOOST_CHECK(result.value == -40);
+ }
+
+
+ {
+ user::number result =
+ transform(-make_ref(a) + -make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == -42);
+ }
+
+ {
+ user::number result = transform(-make_ref(a) + -x, user::eval_xform{});
+ BOOST_CHECK(result.value == -42);
+ }
+
+ {
+ user::number result = transform(-a + -make_ref(x), user::eval_xform{});
+ BOOST_CHECK(result.value == -42);
+ }
+
+ {
+ user::number result = transform(-a + -x, user::eval_xform{});
+ BOOST_CHECK(result.value == -42);
+ }
+}
+
+return 0;
+}
diff --git a/src/boost/libs/yap/test/value.cpp b/src/boost/libs/yap/test/value.cpp
new file mode 100644
index 00000000..5ca933af
--- /dev/null
+++ b/src/boost/libs/yap/test/value.cpp
@@ -0,0 +1,208 @@
+// 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)
+#include <boost/yap/expression.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/test/minimal.hpp>
+
+
+template<typename T>
+using term = boost::yap::terminal<boost::yap::expression, T>;
+
+template<typename T>
+using ref = boost::yap::expression_ref<boost::yap::expression, T>;
+
+namespace yap = boost::yap;
+namespace bh = boost::hana;
+
+
+template<boost::yap::expr_kind Kind, typename Tuple>
+struct user_expr
+{
+ static boost::yap::expr_kind const kind = Kind;
+
+ Tuple elements;
+};
+
+BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
+
+template<typename T>
+using user_term = boost::yap::terminal<user_expr, T>;
+
+template<typename T>
+using user_ref = boost::yap::expression_ref<user_expr, T>;
+
+
+int test_main(int, char * [])
+{
+ {
+ {
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(1.0)), double &&>));
+ BOOST_CHECK(yap::value(1.0) == 1.0);
+ }
+
+ {
+ double d = 2.0;
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(d)), double &>));
+ BOOST_CHECK(yap::value(d) == 2.0);
+ }
+
+ {
+ double const d = 3.0;
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(d)), double const &>));
+ BOOST_CHECK(yap::value(d) == 3.0);
+ }
+ }
+
+ {
+ {
+ term<double> td = {{1.0}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(std::move(td))), double &&>));
+ BOOST_CHECK(yap::value(std::move(td)) == 1.0);
+ }
+
+ {
+ term<double> td = {{2.0}};
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(td)), double &>));
+ BOOST_CHECK(yap::value(td) == 2.0);
+ }
+
+ {
+ term<double> const td = {{3.0}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(td)), double const &>));
+ BOOST_CHECK(yap::value(td) == 3.0);
+ }
+
+ term<double> unity = {{1.0}};
+ using plus_expr_type = yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> &>, term<int>>>;
+ plus_expr_type plus_expr = unity + term<int>{{1}};
+
+ {
+ ref<term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(std::move(ref))), double &>));
+ }
+
+ {
+ ref<term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(ref)), double &>));
+ }
+
+ {
+ ref<term<double> &> const ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(ref)), double &>));
+ }
+
+ {
+ term<double> const unity = {{1.0}};
+ yap::expression<
+ yap::expr_kind::plus,
+ bh::tuple<ref<term<double> const &>, term<int>>>
+ plus_expr = unity + term<int>{{1}};
+
+ {
+ ref<term<double> const &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::value(std::move(ref))),
+ double const &>));
+ }
+
+ {
+ ref<term<double> const &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(ref)), double const &>));
+ }
+
+ {
+ ref<term<double> const &> const ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(ref)), double const &>));
+ }
+ }
+ }
+
+ {
+ {
+ user_term<double> td = {{1.0}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(std::move(td))), double &&>));
+ BOOST_CHECK(yap::value(std::move(td)) == 1.0);
+ }
+
+ {
+ user_term<double> td = {{2.0}};
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(td)), double &>));
+ BOOST_CHECK(yap::value(td) == 2.0);
+ }
+
+ {
+ user_term<double> const td = {{3.0}};
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(td)), double const &>));
+ BOOST_CHECK(yap::value(td) == 3.0);
+ }
+
+ user_term<double> unity = {{1.0}};
+ using plus_expr_type = user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> &>, user_term<int>>>;
+ plus_expr_type plus_expr = unity + user_term<int>{{1}};
+
+ {
+ user_ref<user_term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(std::move(ref))), double &>));
+ }
+
+ {
+ user_ref<user_term<double> &> ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(ref)), double &>));
+ }
+
+ {
+ user_ref<user_term<double> &> const ref = bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<decltype(yap::value(ref)), double &>));
+ }
+
+ {
+ user_term<double> const unity = {{1.0}};
+ user_expr<
+ yap::expr_kind::plus,
+ bh::tuple<user_ref<user_term<double> const &>, user_term<int>>>
+ plus_expr = unity + user_term<int>{{1}};
+
+ {
+ user_ref<user_term<double> const &> ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT((std::is_same<
+ decltype(yap::value(std::move(ref))),
+ double const &>));
+ }
+
+ {
+ user_ref<user_term<double> const &> ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(ref)), double const &>));
+ }
+
+ {
+ user_ref<user_term<double> const &> const ref =
+ bh::front(plus_expr.elements);
+ BOOST_MPL_ASSERT(
+ (std::is_same<decltype(yap::value(ref)), double const &>));
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/yap/test/vector_alloc_test.cpp b/src/boost/libs/yap/test/vector_alloc_test.cpp
new file mode 100644
index 00000000..8ab808c2
--- /dev/null
+++ b/src/boost/libs/yap/test/vector_alloc_test.cpp
@@ -0,0 +1,172 @@
+// 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)
+#include <boost/yap/yap.hpp>
+
+#include <vector>
+#include <iostream>
+
+#include <boost/test/minimal.hpp>
+
+
+int allocations = 0;
+
+void * operator new(std::size_t size)
+{
+ ++allocations;
+ void * retval = malloc(size);
+ if (!retval)
+ throw std::bad_alloc();
+ return retval;
+}
+
+void operator delete(void * ptr) noexcept { free(ptr); }
+
+
+struct take_nth
+{
+ template<typename T>
+ auto operator()(
+ boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
+ std::vector<T> const & vec)
+ {
+ return boost::yap::make_terminal(vec[n]);
+ }
+
+ std::size_t n;
+};
+
+struct equal_sizes_impl
+{
+ template<typename T>
+ auto operator()(
+ boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
+ std::vector<T> const & vec)
+ {
+ auto const expr_size = vec.size();
+ if (expr_size != size)
+ value = false;
+ return 0;
+ }
+
+ std::size_t const size;
+ bool value;
+};
+
+template<typename Expr>
+bool equal_sizes(std::size_t size, Expr const & expr)
+{
+ equal_sizes_impl impl{size, true};
+ boost::yap::transform(boost::yap::as_expr(expr), impl);
+ return impl.value;
+}
+
+
+template<typename T, typename Expr>
+std::vector<T> & assign(std::vector<T> & vec, Expr const & e)
+{
+ decltype(auto) expr = boost::yap::as_expr(e);
+ assert(equal_sizes(vec.size(), expr));
+ for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
+ vec[i] = boost::yap::evaluate(
+ boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
+ }
+ return vec;
+}
+
+template<typename T, typename Expr>
+std::vector<T> & operator+=(std::vector<T> & vec, Expr const & e)
+{
+ decltype(auto) expr = boost::yap::as_expr(e);
+ assert(equal_sizes(vec.size(), expr));
+ for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
+ vec[i] += boost::yap::evaluate(
+ boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
+ }
+ return vec;
+}
+
+template<typename T>
+struct is_vector : std::false_type
+{
+};
+
+template<typename T, typename A>
+struct is_vector<std::vector<T, A>> : std::true_type
+{
+};
+
+BOOST_YAP_USER_UDT_UNARY_OPERATOR(
+ negate, boost::yap::expression, is_vector); // -
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ multiplies, boost::yap::expression, is_vector); // *
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ divides, boost::yap::expression, is_vector); // /
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ modulus, boost::yap::expression, is_vector); // %
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ plus, boost::yap::expression, is_vector); // +
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ minus, boost::yap::expression, is_vector); // -
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ less, boost::yap::expression, is_vector); // <
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ greater, boost::yap::expression, is_vector); // >
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ less_equal, boost::yap::expression, is_vector); // <=
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ greater_equal, boost::yap::expression, is_vector); // >=
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ equal_to, boost::yap::expression, is_vector); // ==
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ not_equal_to, boost::yap::expression, is_vector); // !=
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ logical_or, boost::yap::expression, is_vector); // ||
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ logical_and, boost::yap::expression, is_vector); // &&
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ bitwise_and, boost::yap::expression, is_vector); // &
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ bitwise_or, boost::yap::expression, is_vector); // |
+BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
+ bitwise_xor, boost::yap::expression, is_vector); // ^
+
+int test_main(int, char * [])
+{
+ int i;
+ int const n = 10;
+ std::vector<int> a(n), b(n), c(n), d(n);
+ std::vector<double> e(n);
+
+ // Reset allocation count. There should be none from this point on.
+ allocations = 0;
+
+ for (i = 0; i < n; ++i) {
+ a[i] = i;
+ b[i] = 2 * i;
+ c[i] = 3 * i;
+ d[i] = i;
+ }
+
+ assign(b, 2);
+ assign(d, a + b * c);
+
+ if_else(d < 30, b, c);
+ a += if_else(d < 30, b, c);
+
+ assign(e, c);
+ e += e - 4 / (c + 1);
+
+ for (i = 0; i < n; ++i) {
+ std::cout << " a(" << i << ") = " << a[i] << " b(" << i
+ << ") = " << b[i] << " c(" << i << ") = " << c[i] << " d("
+ << i << ") = " << d[i] << " e(" << i << ") = " << e[i]
+ << std::endl;
+ }
+
+ BOOST_CHECK(allocations == 0);
+
+ return 0;
+}