]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/yap/example/pipable_algorithms.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/algorithm.hpp>
13 //[ pipable_algorithms_and_simple_range
14 // An enum to represent all the standard algorithms we want to adapt. In this
15 // example, we only care about std::sort() and std::unique().
16 enum class algorithm_t
{ sort
, unique
};
18 // Just about the simplest range template you could construct. Nothing fancy.
19 template<typename Iter
>
22 Iter
begin() const { return first_
; }
23 Iter
end() const { return last_
; }
29 // This simply calls the standard algorithm that corresponds to "a". This
30 // certainly won't work for all the algorithms, but it works for many of them
31 // that just take a begin/end pair.
32 template<typename Range
>
33 auto call_algorithm(algorithm_t a
, Range
& r
)
35 simple_range
<decltype(r
.begin())> retval
{r
.begin(), r
.end()};
36 if (a
== algorithm_t::sort
) {
37 std::sort(r
.begin(), r
.end());
38 } else if (a
== algorithm_t::unique
) {
39 retval
.last_
= std::unique(r
.begin(), r
.end());
45 // This is the transform that evaluates our piped expressions. It returns a
46 // simple_range<>, not a Yap expression.
49 // A pipe should always have a Yap expression on the left and an
50 // algorithm_t terminal on the right.
51 template<typename LExpr
>
53 boost::yap::expr_tag
<boost::yap::expr_kind::bitwise_or
>,
57 // Recursively evaluate the left ...
58 auto const left_result
=
59 boost::yap::transform(std::forward
<LExpr
>(left
), *this);
60 // ... and use the result to call the function on the right.
61 return call_algorithm(right
, left_result
);
64 // A call operation is evaluated directly. Note that the range parameter
65 // is taken as an lvalue reference, to prevent binding to a temporary and
66 // taking dangling references to its begin and end. We let the compiler
67 // deduce whether the lvalue reference is const.
69 template<typename Range
>
71 boost::yap::expr_tag
<boost::yap::expr_kind::call
>,
75 return call_algorithm(a
, r
);
80 // This is the expression template we use for the general case of a pipable
81 // algorithm expression. Terminals are handled separately.
82 template<boost::yap::expr_kind Kind
, typename Tuple
>
85 static boost::yap::expr_kind
const kind
= Kind
;
89 // This is how we get the nice initializer semantics we see in the example
90 // usage below. This is a bit limited though, because we always create a
91 // temporary. It might therefore be better just to create algorithm_expr
92 // expressions, call yap::evaluate(), and then use the sequence containers
93 // assign() member function to do the actual assignment.
94 template<typename Assignee
>
95 operator Assignee() const
97 // Exercise left for the reader: static_assert() that Assignee is some
98 // sort of container type.
99 auto const range
= boost::yap::transform(*this, algorithm_eval
{});
100 return Assignee(range
.begin(), range
.end());
105 // This is a bit loose, because it allows us to write "sort(v) | unique(u)" or
106 // similar. It works fine for this example, but in production code you may
107 // want to write out the functions generated by this macro, and add SFINAE or
108 // concepts constraints on the right template parameter.
109 BOOST_YAP_USER_BINARY_OPERATOR(bitwise_or
, algorithm_expr
, algorithm_expr
)
111 // It's useful to specially handle terminals, because we want a different set
112 // of operations to apply to them. We don't want "sort(x)(y)" to be
113 // well-formed, for instance, or "sort | unique" either.
116 static boost::yap::expr_kind
const kind
= boost::yap::expr_kind::terminal
;
118 boost::hana::tuple
<algorithm_t
> elements
;
120 BOOST_YAP_USER_CALL_OPERATOR_N(::algorithm_expr
, 1)
123 // Here are ready-made Yap terminals, one for each algorithm enumerated in
125 constexpr algorithm sort
{{algorithm_t::sort
}};
126 constexpr algorithm unique
{{algorithm_t::unique
}};
131 //[ typical_sort_unique_usage
132 std::vector
<int> v1
= {0, 2, 2, 7, 1, 3, 8};
133 std::sort(v1
.begin(), v1
.end());
134 auto it
= std::unique(v1
.begin(), v1
.end());
135 std::vector
<int> const v2(v1
.begin(), it
);
136 assert(v2
== std::vector
<int>({0, 1, 2, 3, 7, 8}));
140 //[ pipable_sort_unique_usage
141 std::vector
<int> v1
= {0, 2, 2, 7, 1, 3, 8};
142 std::vector
<int> const v2
= sort(v1
) | unique
;
143 assert(v2
== std::vector
<int>({0, 1, 2, 3, 7, 8}));