1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2011 Nathan Ridge
4 Copyright (c) 2006 Dan Marsden
5
6 Distributed under the Boost Software License, Version 1.0. (See accompanying
7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 ==============================================================================*/
9
10 /*=============================================================================
11 An implementation of a std::pair like triple<T0, T1, T2>
12 We use fusion::sequence_facade and fusion::iterator_facade
13 to make our triple a fully conforming Boost.Fusion random
14 traversal sequence.
15 ==============================================================================*/
16
17 #include <boost/detail/lightweight_test.hpp>
18
19 #include <boost/fusion/sequence/sequence_facade.hpp>
20 #include <boost/fusion/iterator/iterator_facade.hpp>
21 #include <boost/fusion/sequence/intrinsic.hpp>
22 #include <boost/fusion/iterator.hpp>
23 #include <boost/fusion/support/category_of.hpp>
24 #include <boost/fusion/algorithm/iteration/fold.hpp>
25
26 #include <boost/mpl/int.hpp>
27 #include <boost/mpl/identity.hpp>
28 #include <boost/mpl/minus.hpp>
29 #include <boost/mpl/assert.hpp>
30
31 #include <boost/type_traits/is_const.hpp>
32 #include <boost/type_traits/is_same.hpp>
33
34 #include <string>
35
36 namespace mpl = boost::mpl;
37 namespace fusion = boost::fusion;
38
39 namespace demo
40 {
41 template<typename Seq, int N>
42 struct triple_iterator
43 : fusion::iterator_facade<triple_iterator<Seq, N>,
44 fusion::random_access_traversal_tag>
45 {
46 typedef mpl::int_<N> index;
47 typedef Seq sequence_type;
48
triple_iteratordemo::triple_iterator49 triple_iterator(Seq& seq)
50 : seq_(seq) {}
51
52 Seq& seq_;
53
54 template<typename T>
55 struct value_of;
56
57 template<typename Sq>
58 struct value_of<triple_iterator<Sq, 0> >
59 : mpl::identity<typename Sq::t0_type>
60 {};
61
62 template<typename Sq>
63 struct value_of<triple_iterator<Sq, 1> >
64 : mpl::identity<typename Sq::t1_type>
65 {};
66
67 template<typename Sq>
68 struct value_of<triple_iterator<Sq, 2> >
69 : mpl::identity<typename Sq::t2_type>
70 {};
71
72 template<typename T>
73 struct deref;
74
75 template <typename Sq>
76 struct deref<triple_iterator<Sq, 0> >
77 {
78 typedef typename Sq::t0_type& type;
79
80 static type
calldemo::triple_iterator::deref81 call(triple_iterator<Sq, 0> const& iter)
82 {
83 return iter.seq_.t0;
84 }
85 };
86
87 template <typename Sq>
88 struct deref<triple_iterator<Sq, 0> const>
89 {
90 typedef typename Sq::t0_type const& type;
91
92 static type
calldemo::triple_iterator::deref93 call(triple_iterator<Sq, 0> const& iter)
94 {
95 return iter.seq_.t0;
96 }
97 };
98
99 template <typename Sq>
100 struct deref<triple_iterator<Sq, 1> >
101 {
102 typedef typename Sq::t1_type& type;
103
104 static type
calldemo::triple_iterator::deref105 call(triple_iterator<Sq, 1> const& iter)
106 {
107 return iter.seq_.t1;
108 }
109 };
110
111 template <typename Sq>
112 struct deref<triple_iterator<Sq, 1> const>
113 {
114 typedef typename Sq::t1_type const& type;
115
116 static type
calldemo::triple_iterator::deref117 call(triple_iterator<Sq, 1> const& iter)
118 {
119 return iter.seq_.t1;
120 }
121 };
122
123 template <typename Sq>
124 struct deref<triple_iterator<Sq, 2> >
125 {
126 typedef typename Sq::t2_type& type;
127
128 static type
calldemo::triple_iterator::deref129 call(triple_iterator<Sq, 2> const& iter)
130 {
131 return iter.seq_.t2;
132 }
133 };
134
135 template <typename Sq>
136 struct deref<triple_iterator<Sq, 2> const>
137 {
138 typedef typename Sq::t2_type const& type;
139
140 static type
calldemo::triple_iterator::deref141 call(triple_iterator<Sq, 2> const& iter)
142 {
143 return iter.seq_.t2;
144 }
145 };
146
147 template<typename It>
148 struct next
149 {
150 typedef triple_iterator<
151 typename It::sequence_type, It::index::value + 1>
152 type;
153
calldemo::triple_iterator::next154 static type call(It const& it)
155 {
156 return type(it.seq_);
157 }
158 };
159
160 template<typename It>
161 struct prior
162 {
163 typedef triple_iterator<
164 typename It::sequence_type, It::index::value - 1>
165 type;
166
calldemo::triple_iterator::prior167 static type call(It const& it)
168 {
169 return type(it.seq_);
170 }
171 };
172
173 template<typename It1, typename It2>
174 struct distance
175 {
176 typedef typename mpl::minus<
177 typename It2::index, typename It1::index>::type
178 type;
179
calldemo::triple_iterator::distance180 static type call(It1 const& it1, It2 const& it2)
181 {
182 return type();
183 }
184 };
185
186 template<typename It, typename M>
187 struct advance
188 {
189 typedef triple_iterator<
190 typename It::sequence_type,
191 It::index::value + M::value>
192 type;
193
calldemo::triple_iterator::advance194 static type call(It const& it)
195 {
196 return type(it.seq_);
197 }
198 };
199 };
200
201 template<typename T0, typename T1, typename T2>
202 struct triple
203 : fusion::sequence_facade<triple<T0, T1, T2>,
204 fusion::random_access_traversal_tag>
205 {
tripledemo::triple206 triple(T0 const& t0, T1 const& t1, T2 const& t2)
207 : t0(t0), t1(t1), t2(t2)
208 {}
209
210 template<typename Sq>
211 struct begin
212 {
213 typedef demo::triple_iterator<Sq, 0> type;
214
calldemo::triple::begin215 static type call(Sq& sq)
216 {
217 return type(sq);
218 }
219 };
220
221 template<typename Sq>
222 struct end
223 {
224 typedef demo::triple_iterator<Sq, 3> type;
225
calldemo::triple::end226 static type call(Sq& sq)
227 {
228 return type(sq);
229 }
230 };
231
232 template<typename Sq>
233 struct size
234 : mpl::int_<3>
235 {};
236
237 template<typename Sq, typename N>
238 struct value_at
239 : value_at<Sq, mpl::int_<N::value> >
240 {};
241
242 template<typename Sq>
243 struct value_at<Sq, mpl::int_<0> >
244 {
245 typedef typename Sq::t0_type type;
246 };
247
248 template<typename Sq>
249 struct value_at<Sq, mpl::int_<1> >
250 {
251 typedef typename Sq::t1_type type;
252 };
253
254 template<typename Sq>
255 struct value_at<Sq, mpl::int_<2> >
256 {
257 typedef typename Sq::t2_type type;
258 };
259
260 template<typename Sq, typename N>
261 struct at
262 : at<Sq, mpl::int_<N::value> >
263 {};
264
265 template<typename Sq>
266 struct at<Sq, mpl::int_<0> >
267 {
268 typedef typename
269 mpl::if_<
270 boost::is_const<Sq>
271 , typename Sq::t0_type const&
272 , typename Sq::t0_type&
273 >::type
274 type;
275
calldemo::triple::at276 static type call(Sq& sq)
277 {
278 return sq.t0;
279 }
280 };
281
282 template<typename Sq>
283 struct at<Sq, mpl::int_<1> >
284 {
285 typedef typename
286 mpl::if_<
287 boost::is_const<Sq>
288 , typename Sq::t1_type const&
289 , typename Sq::t1_type&
290 >::type
291 type;
292
calldemo::triple::at293 static type call(Sq& sq)
294 {
295 return sq.t1;
296 }
297 };
298
299 template<typename Sq>
300 struct at<Sq, mpl::int_<2> >
301 {
302 typedef typename
303 mpl::if_<
304 boost::is_const<Sq>
305 , typename Sq::t2_type const&
306 , typename Sq::t2_type&
307 >::type
308 type;
309
calldemo::triple::at310 static type call(Sq& sq)
311 {
312 return sq.t2;
313 }
314 };
315
316 typedef T0 t0_type;
317 typedef T1 t1_type;
318 typedef T2 t2_type;
319
320 T0 t0;
321 T1 t1;
322 T2 t2;
323 };
324 }
325
326 struct modifying_fold_functor
327 {
328 template <typename T>
329 struct result
330 {
331 typedef bool type;
332 };
333
334 template <typename T>
operator ()modifying_fold_functor335 bool operator()(bool b, T&)
336 {
337 return b;
338 }
339 };
340
341 struct nonmodifying_fold_functor
342 {
343 template <typename T>
344 struct result
345 {
346 typedef bool type;
347 };
348
349 template <typename T>
operator ()nonmodifying_fold_functor350 bool operator()(bool b, const T&)
351 {
352 return b;
353 }
354 };
355
main()356 int main()
357 {
358 typedef demo::triple<int, char, std::string> my_triple;
359 my_triple t(101, 'a', "hello");
360 BOOST_TEST(*fusion::begin(t) == 101);
361 BOOST_TEST(*fusion::next(fusion::begin(t)) == 'a');
362 BOOST_TEST(*fusion::prior(fusion::end(t)) == "hello");
363 BOOST_TEST(fusion::distance(fusion::begin(t), fusion::end(t)) == 3);
364 BOOST_TEST(fusion::size(t) == 3);
365 BOOST_MPL_ASSERT((boost::is_same<
366 int, fusion::result_of::value_at_c<my_triple, 0>::type>));
367 BOOST_MPL_ASSERT((boost::is_same<
368 char, fusion::result_of::value_at_c<my_triple, 1>::type>));
369 BOOST_MPL_ASSERT((boost::is_same<
370 std::string, fusion::result_of::value_at_c<my_triple, 2>::type>));
371 BOOST_TEST(fusion::at_c<0>(t) == 101);
372 BOOST_TEST(fusion::at_c<1>(t) == 'a');
373 BOOST_TEST(fusion::at_c<2>(t) == "hello");
374 BOOST_TEST(fusion::fold(t, true, modifying_fold_functor()) == true);
375 BOOST_TEST(fusion::fold(t, true, nonmodifying_fold_functor()) == true);
376 return boost::report_errors();
377 }
378