From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/boost/libs/yap/example/let.cpp | 177 +++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/boost/libs/yap/example/let.cpp (limited to 'src/boost/libs/yap/example/let.cpp') diff --git a/src/boost/libs/yap/example/let.cpp b/src/boost/libs/yap/example/let.cpp new file mode 100644 index 00000000..0cac1975 --- /dev/null +++ b/src/boost/libs/yap/example/let.cpp @@ -0,0 +1,177 @@ +// 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) +//[ let +#include + +#include +#include +#include +#include + +#include +#include + + +// Here, we introduce special let-placeholders, so we can use them along side +// the normal YAP placeholders without getting them confused. +template +struct let_placeholder : boost::hana::llong +{ +}; + +// Replaces each let-terminal with the expression with which it was +// initialized in let(). So in 'let(_a = foo)[ _a + 1 ]', this transform will +// be used on '_a + 1' to replace '_a' with 'foo'. The map_ member holds the +// mapping of let-placeholders to their initializers. +template +struct let_terminal_transform +{ + // This matches only let-placeholders. For each one matched, we look up + // its initializer in map_ and return it. + template + auto operator()( + boost::yap::expr_tag, + let_placeholder i) + { + // If we have an entry in map_ for this placeholder, return the value + // of the entry. Otherwise, pass i through as a terminal. + if constexpr (boost::hana::contains( + decltype(boost::hana::keys(map_))(), + boost::hana::llong_c)) { + return map_[boost::hana::llong_c]; + } else { + return boost::yap::make_terminal(i); + } + } + + ExprMap map_; +}; + +// As you can see below, let() is an eager function; this template is used for +// its return values. It contains the mapping from let-placeholders to +// initializer expressions used to transform the expression inside '[]' after +// a let()'. It also has an operator[]() member function that takes the +// expression inside '[]' and returns a version of it with the +// let-placeholders replaced. +template +struct let_result +{ + template + auto operator[](Expr && expr) + { + return boost::yap::transform( + std::forward(expr), let_terminal_transform{map_}); + } + + ExprMap map_; +}; + +// Processes the expressions passed to let() one at a time, adding each one to +// a Hana map of hana::llong<>s to YAP expressions. +template +auto let_impl(Map && map, Expr && expr, Exprs &&... exprs) +{ + static_assert( + Expr::kind == boost::yap::expr_kind::assign, + "Expressions passed to let() must be of the form placeholder = Expression"); + if constexpr (sizeof...(Exprs) == 0) { + using I = typename std::remove_reference::type; + auto const i = boost::hana::llong_c; + using map_t = decltype(boost::hana::insert( + map, boost::hana::make_pair(i, boost::yap::right(expr)))); + return let_result{boost::hana::insert( + map, boost::hana::make_pair(i, boost::yap::right(expr)))}; + } else { + using I = typename std::remove_reference::type; + auto const i = boost::hana::llong_c; + return let_impl( + boost::hana::insert( + map, boost::hana::make_pair(i, boost::yap::right(expr))), + std::forward(exprs)...); + } +} + +// Takes N > 0 expressions of the form 'placeholder = expr', and returns an +// object with an overloaded operator[](). +template +auto let(Expr && expr, Exprs &&... exprs) +{ + return let_impl( + boost::hana::make_map(), + std::forward(expr), + std::forward(exprs)...); +} + +int main() +{ + // Some handy terminals -- the _a and _b let-placeholders and std::cout as + // a YAP terminal. + boost::yap::expression< + boost::yap::expr_kind::terminal, + boost::hana::tuple>> const _a; + boost::yap::expression< + boost::yap::expr_kind::terminal, + boost::hana::tuple>> const _b; + auto const cout = boost::yap::make_terminal(std::cout); + + using namespace boost::yap::literals; + + { + auto expr = let(_a = 2)[_a + 1]; + assert(boost::yap::evaluate(expr) == 3); + } + + { + auto expr = let(_a = 123, _b = 456)[_a + _b]; + assert(boost::yap::evaluate(expr) == 123 + 456); + } + + // This prints out "0 0", because 'i' is passed as an lvalue, so its + // decrement is visible outside the let expression. + { + int i = 1; + + boost::yap::evaluate(let(_a = 1_p)[cout << --_a << ' '], i); + + std::cout << i << std::endl; + } + + // Prints "Hello, World" due to let()'s scoping rules. + { + boost::yap::evaluate( + let(_a = 1_p, _b = 2_p) + [ + // _a here is an int: 1 + + let(_a = 3_p) // hides the outer _a + [ + cout << _a << _b // prints "Hello, World" + ] + ], + 1, " World", "Hello," + ); + } + + std::cout << "\n"; + + // Due to the macro-substitution style that this example uses, this prints + // "3132". Phoenix's let() prints "312", because it only evaluates '1_p + // << 3' once. + { + boost::yap::evaluate( + let(_a = 1_p << 3) + [ + _a << "1", _a << "2" + ], + std::cout + ); + } + + std::cout << "\n"; +} +//] -- cgit v1.2.3