]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/yap/example/let.cpp
1 // Copyright (C) 2016-2018 T. Zachary Laine
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/yap/yap.hpp>
9 #include <boost/hana/map.hpp>
10 #include <boost/hana/at_key.hpp>
11 #include <boost/hana/contains.hpp>
12 #include <boost/hana/keys.hpp>
18 // Here, we introduce special let-placeholders, so we can use them along side
19 // the normal YAP placeholders without getting them confused.
21 struct let_placeholder
: boost::hana::llong
<I
>
25 // Replaces each let-terminal with the expression with which it was
26 // initialized in let(). So in 'let(_a = foo)[ _a + 1 ]', this transform will
27 // be used on '_a + 1' to replace '_a' with 'foo'. The map_ member holds the
28 // mapping of let-placeholders to their initializers.
29 template<typename ExprMap
>
30 struct let_terminal_transform
32 // This matches only let-placeholders. For each one matched, we look up
33 // its initializer in map_ and return it.
36 boost::yap::expr_tag
<boost::yap::expr_kind::terminal
>,
39 // If we have an entry in map_ for this placeholder, return the value
40 // of the entry. Otherwise, pass i through as a terminal.
41 if constexpr (boost::hana::contains(
42 decltype(boost::hana::keys(map_
))(),
43 boost::hana::llong_c
<I
>)) {
44 return map_
[boost::hana::llong_c
<I
>];
46 return boost::yap::make_terminal(i
);
53 // As you can see below, let() is an eager function; this template is used for
54 // its return values. It contains the mapping from let-placeholders to
55 // initializer expressions used to transform the expression inside '[]' after
56 // a let()'. It also has an operator[]() member function that takes the
57 // expression inside '[]' and returns a version of it with the
58 // let-placeholders replaced.
59 template<typename ExprMap
>
62 template<typename Expr
>
63 auto operator[](Expr
&& expr
)
65 return boost::yap::transform(
66 std::forward
<Expr
>(expr
), let_terminal_transform
<ExprMap
>{map_
});
72 // Processes the expressions passed to let() one at a time, adding each one to
73 // a Hana map of hana::llong<>s to YAP expressions.
74 template<typename Map
, typename Expr
, typename
... Exprs
>
75 auto let_impl(Map
&& map
, Expr
&& expr
, Exprs
&&... exprs
)
78 Expr::kind
== boost::yap::expr_kind::assign
,
79 "Expressions passed to let() must be of the form placeholder = Expression");
80 if constexpr (sizeof...(Exprs
) == 0) {
81 using I
= typename
std::remove_reference
<decltype(
82 boost::yap::value(boost::yap::left(expr
)))>::type
;
83 auto const i
= boost::hana::llong_c
<I::value
>;
84 using map_t
= decltype(boost::hana::insert(
85 map
, boost::hana::make_pair(i
, boost::yap::right(expr
))));
86 return let_result
<map_t
>{boost::hana::insert(
87 map
, boost::hana::make_pair(i
, boost::yap::right(expr
)))};
89 using I
= typename
std::remove_reference
<decltype(
90 boost::yap::value(boost::yap::left(expr
)))>::type
;
91 auto const i
= boost::hana::llong_c
<I::value
>;
94 map
, boost::hana::make_pair(i
, boost::yap::right(expr
))),
95 std::forward
<Exprs
>(exprs
)...);
99 // Takes N > 0 expressions of the form 'placeholder = expr', and returns an
100 // object with an overloaded operator[]().
101 template<typename Expr
, typename
... Exprs
>
102 auto let(Expr
&& expr
, Exprs
&&... exprs
)
105 boost::hana::make_map(),
106 std::forward
<Expr
>(expr
),
107 std::forward
<Exprs
>(exprs
)...);
112 // Some handy terminals -- the _a and _b let-placeholders and std::cout as
114 boost::yap::expression
<
115 boost::yap::expr_kind::terminal
,
116 boost::hana::tuple
<let_placeholder
<0>>> const _a
;
117 boost::yap::expression
<
118 boost::yap::expr_kind::terminal
,
119 boost::hana::tuple
<let_placeholder
<1>>> const _b
;
120 auto const cout
= boost::yap::make_terminal(std::cout
);
122 using namespace boost::yap::literals
;
125 auto expr
= let(_a
= 2)[_a
+ 1];
126 assert(boost::yap::evaluate(expr
) == 3);
130 auto expr
= let(_a
= 123, _b
= 456)[_a
+ _b
];
131 assert(boost::yap::evaluate(expr
) == 123 + 456);
134 // This prints out "0 0", because 'i' is passed as an lvalue, so its
135 // decrement is visible outside the let expression.
139 boost::yap::evaluate(let(_a
= 1_p
)[cout
<< --_a
<< ' '], i
);
141 std::cout
<< i
<< std::endl
;
144 // Prints "Hello, World" due to let()'s scoping rules.
146 boost::yap::evaluate(
147 let(_a
= 1_p
, _b
= 2_p
)
149 // _a here is an int: 1
151 let(_a
= 3_p
) // hides the outer _a
153 cout
<< _a
<< _b
// prints "Hello, World"
156 1, " World", "Hello,"
162 // Due to the macro-substitution style that this example uses, this prints
163 // "3132". Phoenix's let() prints "312", because it only evaluates '1_p
166 boost::yap::evaluate(