]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fusion/example/cookbook/do_the_bind.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / fusion / example / cookbook / do_the_bind.cpp
1 /*=============================================================================
2 Copyright (c) 2006-2007 Tobias Schwinger
3
4 Use modification and distribution are subject to the Boost Software
5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt).
7
8 Problem:
9
10 How to "do the Bind?"
11
12 This recipe shows how to implement a function binder, similar to
13 Boost.Bind based on the Functional module of Fusion.
14
15 It works as follows:
16
17 'bind' is a global, stateless function object. It is implemented in
18 fused form (fused_binder) and transformed into a variadic function
19 object. When called, 'bind' returns another function object, which
20 holds the arguments of the call to 'bind'. It is, again, implemented
21 in fused form (fused_bound_function) and transformed into unfused
22 form.
23 ==============================================================================*/
24
25
26 #include <boost/fusion/functional/invocation/invoke.hpp>
27 #include <boost/fusion/functional/adapter/unfused.hpp>
28 #include <boost/fusion/support/deduce_sequence.hpp>
29
30 #include <boost/fusion/sequence/intrinsic/at.hpp>
31 #include <boost/fusion/sequence/intrinsic/front.hpp>
32 #include <boost/fusion/sequence/intrinsic/size.hpp>
33 #include <boost/fusion/algorithm/transformation/transform.hpp>
34 #include <boost/fusion/algorithm/transformation/pop_front.hpp>
35 #include <boost/fusion/algorithm/iteration/fold.hpp>
36 #include <boost/fusion/view/filter_view.hpp>
37
38 #include <boost/functional/forward_adapter.hpp>
39 #include <boost/functional/lightweight_forward_adapter.hpp>
40
41 #include <boost/type_traits/remove_reference.hpp>
42
43 #include <boost/mpl/eval_if.hpp>
44 #include <boost/mpl/identity.hpp>
45 #include <boost/mpl/int.hpp>
46 #include <boost/mpl/max.hpp>
47 #include <boost/mpl/next.hpp>
48
49 #include <boost/ref.hpp>
50 #include <iostream>
51 #include <typeinfo>
52
53 namespace impl
54 {
55 namespace fusion = boost::fusion;
56 namespace traits = boost::fusion::traits;
57 namespace result_of = boost::fusion::result_of;
58 namespace mpl = boost::mpl;
59 using mpl::placeholders::_;
60
61 // Placeholders (we inherit from mpl::int_, so we can use placeholders
62 // as indices for fusion::at, later)
63 template <int I> struct placeholder : mpl::int_<I> { };
64
65 // A traits class to find out whether T is a placeholeder
66 template <typename T> struct is_placeholder : mpl::false_ { };
67 template <int I> struct is_placeholder< placeholder<I> > : mpl::true_ { };
68 template <int I> struct is_placeholder< placeholder<I> & > : mpl::true_ { };
69 template <int I> struct is_placeholder< placeholder<I> const > : mpl::true_ { };
70 template <int I> struct is_placeholder< placeholder<I> const & > : mpl::true_ { };
71
72 // This class template provides a Polymorphic Function Object to be used
73 // with fusion::transform. It is applied to the sequence of arguments that
74 // describes the binding and holds a reference to the sequence of arguments
75 // from the final call.
76 template<class FinalArgs> struct argument_transform
77 {
78 FinalArgs const & ref_final_args;
79 public:
80
81 explicit argument_transform(FinalArgs const & final_args)
82 : ref_final_args(final_args)
83 { }
84
85 // A placeholder? Replace it with an argument from the final call...
86 template <int Index>
87 inline typename result_of::at_c<FinalArgs const, Index>::type
88 operator()(placeholder<Index> const &) const
89 {
90 return fusion::at_c<Index>(this->ref_final_args);
91 }
92 // ...just return the bound argument, otherwise.
93 template <typename T> inline T & operator()(T & bound) const
94 {
95 return bound;
96 }
97
98 template <typename Signature>
99 struct result;
100
101 template <class Self, typename T>
102 struct result< Self (T) >
103 : mpl::eval_if< is_placeholder<T>,
104 result_of::at<FinalArgs,typename boost::remove_reference<T>::type>,
105 mpl::identity<T>
106 >
107 { };
108 };
109
110 // Fused implementation of the bound function, the function object
111 // returned by bind
112 template <class BindArgs> class fused_bound_function
113 {
114 // Transform arguments to be held by value
115 typedef typename traits::deduce_sequence<BindArgs>::type bound_args;
116
117 bound_args fsq_bind_args;
118 public:
119
120 fused_bound_function(BindArgs const & bind_args)
121 : fsq_bind_args(bind_args)
122 { }
123
124 template <typename Signature>
125 struct result;
126
127 template <class FinalArgs>
128 struct result_impl
129 : result_of::invoke< typename result_of::front<bound_args>::type,
130 typename result_of::transform<
131 typename result_of::pop_front<bound_args>::type,
132 argument_transform<FinalArgs> const
133 >::type
134 >
135 { };
136
137 template <class Self, class FinalArgs>
138 struct result< Self (FinalArgs) >
139 : result_impl< typename boost::remove_reference<FinalArgs>::type >
140 { };
141
142 template <class FinalArgs>
143 inline typename result_impl<FinalArgs>::type
144 operator()(FinalArgs const & final_args) const
145 {
146 return fusion::invoke( fusion::front(this->fsq_bind_args),
147 fusion::transform( fusion::pop_front(this->fsq_bind_args),
148 argument_transform<FinalArgs>(final_args) ) );
149 }
150 // Could add a non-const variant - omitted for readability
151
152 };
153
154 // Find the number of placeholders in use
155 struct n_placeholders
156 {
157 struct fold_op
158 {
159 template <typename Sig> struct result;
160 template <class S, class A, class B> struct result< S(A &,B &) >
161 : mpl::max<A,B> { };
162 };
163 struct filter_pred
164 {
165 template <class X> struct apply : is_placeholder<X> { };
166 };
167
168 template <typename Seq>
169 struct apply
170 : mpl::next< typename result_of::fold<
171 fusion::filter_view<Seq,filter_pred>, mpl::int_<-1>, fold_op
172 >::type>::type
173 { };
174 };
175
176 // Fused implementation of the 'bind' function
177 struct fused_binder
178 {
179 template <class Signature>
180 struct result;
181
182 template <class BindArgs,
183 int Placeholders = n_placeholders::apply<BindArgs>::value>
184 struct result_impl
185 {
186 typedef boost::forward_adapter<fusion::unfused<
187 fused_bound_function<BindArgs>,!Placeholders>,Placeholders> type;
188 };
189
190 template <class Self, class BindArgs>
191 struct result< Self (BindArgs) >
192 : result_impl< typename boost::remove_reference<BindArgs>::type >
193 { };
194
195 template <class BindArgs>
196 inline typename result_impl< BindArgs >::type
197 operator()(BindArgs & bind_args) const
198 {
199 return typename result< void(BindArgs) >::type(
200 fusion::unfused< fused_bound_function<BindArgs>,
201 ! n_placeholders::apply<BindArgs>::value >(bind_args) );
202 }
203 };
204
205 // The binder's unfused type. We use lightweght_forward_adapter to make
206 // that thing more similar to Boost.Bind. Because of that we have to use
207 // Boost.Ref (below in the sample code)
208 typedef boost::lightweight_forward_adapter< fusion::unfused<fused_binder> > binder;
209 }
210
211 // Placeholder globals
212 impl::placeholder<0> const _1_ = impl::placeholder<0>();
213 impl::placeholder<1> const _2_ = impl::placeholder<1>();
214 impl::placeholder<2> const _3_ = impl::placeholder<2>();
215 impl::placeholder<3> const _4_ = impl::placeholder<3>();
216
217 // The bind function is a global, too
218 impl::binder const bind = impl::binder();
219
220
221 // OK, let's try it out:
222
223 struct func
224 {
225 typedef int result_type;
226
227 inline int operator()() const
228 {
229 std::cout << "operator()" << std::endl;
230 return 0;
231 }
232
233 template <typename A>
234 inline int operator()(A const & a) const
235 {
236 std::cout << "operator()(A const & a)" << std::endl;
237 std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl;
238 return 1;
239 }
240
241 template <typename A, typename B>
242 inline int operator()(A const & a, B & b) const
243 {
244 std::cout << "operator()(A const & a, B & b)" << std::endl;
245 std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl;
246 std::cout << " b = " << b << " B = " << typeid(B).name() << std::endl;
247 return 2;
248 }
249 };
250
251 int main()
252 {
253 func f;
254 int value = 42;
255 using boost::ref;
256
257 int errors = 0;
258
259 errors += !( bind(f)() == 0);
260 errors += !( bind(f,"Hi")() == 1);
261 errors += !( bind(f,_1_)("there.") == 1);
262 errors += !( bind(f,"The answer is",_1_)(12) == 2);
263 errors += !( bind(f,_1_,ref(value))("Really?") == 2);
264 errors += !( bind(f,_1_,_2_)("Dunno. If there is an answer, it's",value) == 2);
265
266 return !! errors;
267 }
268