1 /*=============================================================================
2 Copyright (c) 2011 Eric Niebler
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #if !defined(BOOST_FUSION_SEGMENTED_ITERATOR_RANGE_HPP_INCLUDED)
8 #define BOOST_FUSION_SEGMENTED_ITERATOR_RANGE_HPP_INCLUDED
10 #include <boost/fusion/support/config.hpp>
11 #include <boost/mpl/assert.hpp>
12 #include <boost/type_traits/add_const.hpp>
13 #include <boost/type_traits/remove_reference.hpp>
14 #include <boost/fusion/support/tag_of.hpp>
15 #include <boost/fusion/sequence/intrinsic/begin.hpp>
16 #include <boost/fusion/sequence/intrinsic/end.hpp>
17 #include <boost/fusion/iterator/next.hpp>
18 #include <boost/fusion/iterator/deref.hpp>
19 #include <boost/fusion/sequence/intrinsic/segments.hpp>
20 #include <boost/fusion/algorithm/transformation/push_back.hpp>
21 #include <boost/fusion/algorithm/transformation/push_front.hpp>
22 #include <boost/fusion/iterator/equal_to.hpp>
23 #include <boost/fusion/container/list/detail/reverse_cons.hpp>
24 #include <boost/fusion/iterator/detail/segment_sequence.hpp>
25 #include <boost/fusion/support/is_sequence.hpp>
26 #include <boost/utility/enable_if.hpp>
29 // - Each segmented iterator has a stack
30 // - Each value in the stack is an iterator range
31 // - The range at the top of the stack points to values
32 // - All other ranges point to ranges
33 // - The front of each range in the stack (besides the
34 // topmost) is the range above it
36 namespace boost { namespace fusion
38 template <typename First, typename Last>
39 struct iterator_range;
43 template <typename Sequence, typename T>
46 template <typename Sequence, typename T>
50 template <typename Sequence, typename T>
51 BOOST_FUSION_GPU_ENABLED
54 traits::is_sequence<Sequence>
55 , result_of::push_back<Sequence const, T>
57 push_back(Sequence const& seq, T const& x);
59 template <typename Sequence, typename T>
60 BOOST_FUSION_GPU_ENABLED
63 traits::is_sequence<Sequence>
64 , result_of::push_front<Sequence const, T>
66 push_front(Sequence const& seq, T const& x);
69 namespace boost { namespace fusion { namespace detail
71 //auto make_segment_sequence_front(stack_begin)
73 // switch (size(stack_begin))
78 // // car(cdr(stack_begin)) is a range over values.
79 // assert(end(front(car(stack_begin))) == end(car(cdr(stack_begin))));
80 // return iterator_range(begin(car(cdr(stack_begin))), end(front(car(stack_begin))));
82 // // car(cdr(stack_begin)) is a range over segments. We replace the
83 // // front with a view that is restricted.
84 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
85 // return segment_sequence(
87 // // The following could be a segment_sequence. It then gets wrapped
88 // // in a single_view, and push_front puts it in a join_view with the
89 // // following iterator_range.
90 // iterator_range(next(begin(car(cdr(stack_begin)))), end(segments(front(car(stack_begin))))),
91 // make_segment_sequence_front(cdr(stack_begin))));
95 template <typename Stack, std::size_t Size = Stack::size::value>
96 struct make_segment_sequence_front
98 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
101 typename result_of::end<
102 typename remove_reference<
104 typename result_of::segments<
105 typename remove_reference<
107 typename result_of::deref<
108 typename Stack::car_type::begin_type
116 , typename Stack::cdr_type::car_type::end_type
121 typename result_of::next<
122 typename Stack::cdr_type::car_type::begin_type
124 , typename result_of::end<
125 typename remove_reference<
127 typename result_of::segments<
128 typename remove_reference<
130 typename result_of::deref<
131 typename Stack::car_type::begin_type
143 make_segment_sequence_front<typename Stack::cdr_type>
148 typename result_of::push_front<
150 , typename recurse::type
155 BOOST_FUSION_GPU_ENABLED
156 static type call(Stack const& stack)
158 //return segment_sequence(
160 // iterator_range(next(begin(car(cdr(stack_begin)))), end(segments(front(car(stack_begin))))),
161 // make_segment_sequence_front(cdr(stack_begin))));
164 rest_type(fusion::next(stack.cdr.car.first), fusion::end(fusion::segments(*stack.car.first)))
165 , recurse::call(stack.cdr)));
169 template <typename Stack>
170 struct make_segment_sequence_front<Stack, 2>
172 // assert(end(front(car(stack_begin))) == end(car(cdr(stack_begin))));
175 typename result_of::end<
176 typename remove_reference<
178 typename result_of::deref<
179 typename Stack::car_type::begin_type
184 , typename Stack::cdr_type::car_type::end_type
189 typename Stack::cdr_type::car_type::begin_type
190 , typename result_of::end<
191 typename remove_reference<
193 typename result_of::deref<
194 typename Stack::car_type::begin_type
202 BOOST_FUSION_GPU_ENABLED
203 static type call(Stack const& stack)
205 // return iterator_range(begin(car(cdr(stack_begin))), end(front(car(stack_begin))));
206 return type(stack.cdr.car.first, fusion::end(*stack.car.first));
210 template <typename Stack>
211 struct make_segment_sequence_front<Stack, 1>
213 typedef typename Stack::cdr_type type; // nil_
215 BOOST_FUSION_GPU_ENABLED
216 static type call(Stack const &stack)
222 //auto make_segment_sequence_back(stack_end)
224 // switch (size(stack_end))
229 // // car(cdr(stack_back)) is a range over values.
230 // assert(end(front(car(stack_end))) == end(car(cdr(stack_end))));
231 // return iterator_range(begin(front(car(stack_end))), begin(car(cdr(stack_end))));
233 // // car(cdr(stack_begin)) is a range over segments. We replace the
234 // // back with a view that is restricted.
235 // assert(end(segments(front(car(stack_end)))) == end(car(cdr(stack_end))));
236 // return segment_sequence(
238 // iterator_range(begin(segments(front(car(stack_end)))), begin(car(cdr(stack_end)))),
239 // make_segment_sequence_back(cdr(stack_end))));
243 template <typename Stack, std::size_t Size = Stack::size::value>
244 struct make_segment_sequence_back
246 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
249 typename result_of::end<
250 typename remove_reference<
252 typename result_of::segments<
253 typename remove_reference<
255 typename result_of::deref<
256 typename Stack::car_type::begin_type
264 , typename Stack::cdr_type::car_type::end_type
269 typename result_of::begin<
270 typename remove_reference<
272 typename result_of::segments<
273 typename remove_reference<
275 typename result_of::deref<
276 typename Stack::car_type::begin_type
284 , typename Stack::cdr_type::car_type::begin_type
289 make_segment_sequence_back<typename Stack::cdr_type>
294 typename result_of::push_back<
296 , typename recurse::type
301 BOOST_FUSION_GPU_ENABLED
302 static type call(Stack const& stack)
304 // return segment_sequence(
306 // iterator_range(begin(segments(front(car(stack_end)))), begin(car(cdr(stack_end)))),
307 // make_segment_sequence_back(cdr(stack_end))));
310 rest_type(fusion::begin(fusion::segments(*stack.car.first)), stack.cdr.car.first)
311 , recurse::call(stack.cdr)));
315 template <typename Stack>
316 struct make_segment_sequence_back<Stack, 2>
318 // assert(end(front(car(stack_end))) == end(car(cdr(stack_end))));
321 typename result_of::end<
322 typename remove_reference<
324 typename result_of::deref<
325 typename Stack::car_type::begin_type
330 , typename Stack::cdr_type::car_type::end_type
335 typename result_of::begin<
336 typename remove_reference<
338 typename result_of::deref<
339 typename Stack::car_type::begin_type
344 , typename Stack::cdr_type::car_type::begin_type
348 BOOST_FUSION_GPU_ENABLED
349 static type call(Stack const& stack)
351 // return iterator_range(begin(front(car(stack_end))), begin(car(cdr(stack_end))));
352 return type(fusion::begin(*stack.car.first), stack.cdr.car.first);
356 template <typename Stack>
357 struct make_segment_sequence_back<Stack, 1>
359 typedef typename Stack::cdr_type type; // nil_
361 BOOST_FUSION_GPU_ENABLED
362 static type call(Stack const& stack)
368 //auto make_segmented_range_reduce(stack_begin, stack_end)
370 // if (size(stack_begin) == 1 && size(stack_end) == 1)
372 // return segment_sequence(
374 // iterator_range(begin(car(stack_begin)), begin(car(stack_end)))));
378 // // We are in the case where both begin_stack and/or end_stack have
379 // // more than one element. Throw away any part of the tree where
380 // // begin and end refer to the same segment.
381 // if (begin(car(stack_begin)) == begin(car(stack_end)))
383 // return make_segmented_range_reduce(cdr(stack_begin), cdr(stack_end));
387 // // We are in the case where begin_stack and end_stack (a) have
388 // // more than one element each, and (b) they point to different
389 // // segments. We must construct a segmented sequence.
390 // return segment_sequence(
394 // fusion::next(begin(car(stack_begin))),
395 // begin(car(stack_end))), // a range of (possibly segmented) ranges.
396 // make_segment_sequence_front(stack_begin)), // should be a (possibly segmented) range.
397 // make_segment_sequence_back(stack_end))); // should be a (possibly segmented) range.
405 , int StackBeginSize = StackBegin::size::value
406 , int StackEndSize = StackEnd::size::value>
407 struct make_segmented_range_reduce;
414 typename StackBegin::car_type::begin_type
415 , typename StackEnd::car_type::begin_type
417 struct make_segmented_range_reduce2
421 typename result_of::next<
422 typename StackBegin::car_type::begin_type
424 , typename StackEnd::car_type::begin_type
430 typename result_of::push_back<
431 typename result_of::push_front<
433 , typename make_segment_sequence_front<StackBegin>::type
435 , typename make_segment_sequence_back<StackEnd>::type
440 BOOST_FUSION_GPU_ENABLED
441 static type call(StackBegin stack_begin, StackEnd stack_end)
443 //return segment_sequence(
447 // fusion::next(begin(car(stack_begin))),
448 // begin(car(stack_end))), // a range of (possibly segmented) ranges.
449 // make_segment_sequence_front(stack_begin)), // should be a (possibly segmented) range.
450 // make_segment_sequence_back(stack_end))); // should be a (possibly segmented) range.
454 rest_type(fusion::next(stack_begin.car.first), stack_end.car.first)
455 , make_segment_sequence_front<StackBegin>::call(stack_begin))
456 , make_segment_sequence_back<StackEnd>::call(stack_end)));
460 template <typename StackBegin, typename StackEnd>
461 struct make_segmented_range_reduce2<StackBegin, StackEnd, true>
464 make_segmented_range_reduce<
465 typename StackBegin::cdr_type
466 , typename StackEnd::cdr_type
474 BOOST_FUSION_GPU_ENABLED
475 static type call(StackBegin stack_begin, StackEnd stack_end)
477 return impl::call(stack_begin.cdr, stack_end.cdr);
481 template <typename StackBegin, typename StackEnd, int StackBeginSize, int StackEndSize>
482 struct make_segmented_range_reduce
483 : make_segmented_range_reduce2<StackBegin, StackEnd>
486 template <typename StackBegin, typename StackEnd>
487 struct make_segmented_range_reduce<StackBegin, StackEnd, 1, 1>
491 typename StackBegin::car_type::begin_type
492 , typename StackEnd::car_type::begin_type
497 single_view<range_type>
501 segment_sequence<segment_type>
504 BOOST_FUSION_GPU_ENABLED
505 static type call(StackBegin stack_begin, StackEnd stack_end)
507 //return segment_sequence(
509 // iterator_range(begin(car(stack_begin)), begin(car(stack_end)))));
510 return type(segment_type(range_type(stack_begin.car.first, stack_end.car.first)));
514 //auto make_segmented_range(begin, end)
516 // return make_segmented_range_reduce(reverse(begin.context), reverse(end.context));
519 template <typename Begin, typename End>
520 struct make_segmented_range
522 typedef reverse_cons<typename Begin::context_type> reverse_begin_cons;
523 typedef reverse_cons<typename End::context_type> reverse_end_cons;
526 make_segmented_range_reduce<
527 typename reverse_begin_cons::type
528 , typename reverse_end_cons::type
532 typedef typename impl::type type;
534 BOOST_FUSION_GPU_ENABLED
535 static type call(Begin const& begin, End const& end)
538 reverse_begin_cons::call(begin.context)
539 , reverse_end_cons::call(end.context));