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/mpl/assert.hpp>
11 #include <boost/type_traits/add_const.hpp>
12 #include <boost/type_traits/remove_reference.hpp>
13 #include <boost/fusion/support/tag_of.hpp>
14 #include <boost/fusion/sequence/intrinsic/begin.hpp>
15 #include <boost/fusion/sequence/intrinsic/end.hpp>
16 #include <boost/fusion/iterator/next.hpp>
17 #include <boost/fusion/iterator/deref.hpp>
18 #include <boost/fusion/sequence/intrinsic/segments.hpp>
19 #include <boost/fusion/algorithm/transformation/push_back.hpp>
20 #include <boost/fusion/algorithm/transformation/push_front.hpp>
21 #include <boost/fusion/iterator/equal_to.hpp>
22 #include <boost/fusion/container/list/detail/reverse_cons.hpp>
23 #include <boost/fusion/iterator/detail/segment_sequence.hpp>
26 // - Each segmented iterator has a stack
27 // - Each value in the stack is an iterator range
28 // - The range at the top of the stack points to values
29 // - All other ranges point to ranges
30 // - The front of each range in the stack (besides the
31 // topmost) is the range above it
33 namespace boost { namespace fusion
35 template <typename First, typename Last>
36 struct iterator_range;
40 template <typename Sequence, typename T>
43 template <typename Sequence, typename T>
47 template <typename Sequence, typename T>
48 typename result_of::push_back<Sequence const, T>::type
49 push_back(Sequence const& seq, T const& x);
51 template <typename Sequence, typename T>
52 typename result_of::push_front<Sequence const, T>::type
53 push_front(Sequence const& seq, T const& x);
56 namespace boost { namespace fusion { namespace detail
58 //auto make_segment_sequence_front(stack_begin)
60 // switch (size(stack_begin))
65 // // car(cdr(stack_begin)) is a range over values.
66 // assert(end(front(car(stack_begin))) == end(car(cdr(stack_begin))));
67 // return iterator_range(begin(car(cdr(stack_begin))), end(front(car(stack_begin))));
69 // // car(cdr(stack_begin)) is a range over segments. We replace the
70 // // front with a view that is restricted.
71 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
72 // return segment_sequence(
74 // // The following could be a segment_sequence. It then gets wrapped
75 // // in a single_view, and push_front puts it in a join_view with the
76 // // following iterator_range.
77 // iterator_range(next(begin(car(cdr(stack_begin)))), end(segments(front(car(stack_begin))))),
78 // make_segment_sequence_front(cdr(stack_begin))));
82 template <typename Stack, std::size_t Size = Stack::size::value>
83 struct make_segment_sequence_front
85 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
88 typename result_of::end<
89 typename remove_reference<
91 typename result_of::segments<
92 typename remove_reference<
94 typename result_of::deref<
95 typename Stack::car_type::begin_type
103 , typename Stack::cdr_type::car_type::end_type
108 typename result_of::next<
109 typename Stack::cdr_type::car_type::begin_type
111 , typename result_of::end<
112 typename remove_reference<
114 typename result_of::segments<
115 typename remove_reference<
117 typename result_of::deref<
118 typename Stack::car_type::begin_type
130 make_segment_sequence_front<typename Stack::cdr_type>
135 typename result_of::push_front<
137 , typename recurse::type
142 static type call(Stack const& stack)
144 //return segment_sequence(
146 // iterator_range(next(begin(car(cdr(stack_begin)))), end(segments(front(car(stack_begin))))),
147 // make_segment_sequence_front(cdr(stack_begin))));
150 rest_type(fusion::next(stack.cdr.car.first), fusion::end(fusion::segments(*stack.car.first)))
151 , recurse::call(stack.cdr)));
155 template <typename Stack>
156 struct make_segment_sequence_front<Stack, 2>
158 // assert(end(front(car(stack_begin))) == end(car(cdr(stack_begin))));
161 typename result_of::end<
162 typename remove_reference<
164 typename result_of::deref<
165 typename Stack::car_type::begin_type
170 , typename Stack::cdr_type::car_type::end_type
175 typename Stack::cdr_type::car_type::begin_type
176 , typename result_of::end<
177 typename remove_reference<
179 typename result_of::deref<
180 typename Stack::car_type::begin_type
188 static type call(Stack const& stack)
190 // return iterator_range(begin(car(cdr(stack_begin))), end(front(car(stack_begin))));
191 return type(stack.cdr.car.first, fusion::end(*stack.car.first));
195 template <typename Stack>
196 struct make_segment_sequence_front<Stack, 1>
198 typedef typename Stack::cdr_type type; // nil
200 static type call(Stack const &stack)
206 //auto make_segment_sequence_back(stack_end)
208 // switch (size(stack_end))
213 // // car(cdr(stack_back)) is a range over values.
214 // assert(end(front(car(stack_end))) == end(car(cdr(stack_end))));
215 // return iterator_range(begin(front(car(stack_end))), begin(car(cdr(stack_end))));
217 // // car(cdr(stack_begin)) is a range over segments. We replace the
218 // // back with a view that is restricted.
219 // assert(end(segments(front(car(stack_end)))) == end(car(cdr(stack_end))));
220 // return segment_sequence(
222 // iterator_range(begin(segments(front(car(stack_end)))), begin(car(cdr(stack_end)))),
223 // make_segment_sequence_back(cdr(stack_end))));
227 template <typename Stack, std::size_t Size = Stack::size::value>
228 struct make_segment_sequence_back
230 // assert(end(segments(front(car(stack_begin)))) == end(car(cdr(stack_begin))));
233 typename result_of::end<
234 typename remove_reference<
236 typename result_of::segments<
237 typename remove_reference<
239 typename result_of::deref<
240 typename Stack::car_type::begin_type
248 , typename Stack::cdr_type::car_type::end_type
253 typename result_of::begin<
254 typename remove_reference<
256 typename result_of::segments<
257 typename remove_reference<
259 typename result_of::deref<
260 typename Stack::car_type::begin_type
268 , typename Stack::cdr_type::car_type::begin_type
273 make_segment_sequence_back<typename Stack::cdr_type>
278 typename result_of::push_back<
280 , typename recurse::type
285 static type call(Stack const& stack)
287 // return segment_sequence(
289 // iterator_range(begin(segments(front(car(stack_end)))), begin(car(cdr(stack_end)))),
290 // make_segment_sequence_back(cdr(stack_end))));
293 rest_type(fusion::begin(fusion::segments(*stack.car.first)), stack.cdr.car.first)
294 , recurse::call(stack.cdr)));
298 template <typename Stack>
299 struct make_segment_sequence_back<Stack, 2>
301 // assert(end(front(car(stack_end))) == end(car(cdr(stack_end))));
304 typename result_of::end<
305 typename remove_reference<
307 typename result_of::deref<
308 typename Stack::car_type::begin_type
313 , typename Stack::cdr_type::car_type::end_type
318 typename result_of::begin<
319 typename remove_reference<
321 typename result_of::deref<
322 typename Stack::car_type::begin_type
327 , typename Stack::cdr_type::car_type::begin_type
331 static type call(Stack const& stack)
333 // return iterator_range(begin(front(car(stack_end))), begin(car(cdr(stack_end))));
334 return type(fusion::begin(*stack.car.first), stack.cdr.car.first);
338 template <typename Stack>
339 struct make_segment_sequence_back<Stack, 1>
341 typedef typename Stack::cdr_type type; // nil
343 static type call(Stack const& stack)
349 //auto make_segmented_range_reduce(stack_begin, stack_end)
351 // if (size(stack_begin) == 1 && size(stack_end) == 1)
353 // return segment_sequence(
355 // iterator_range(begin(car(stack_begin)), begin(car(stack_end)))));
359 // // We are in the case where both begin_stack and/or end_stack have
360 // // more than one element. Throw away any part of the tree where
361 // // begin and end refer to the same segment.
362 // if (begin(car(stack_begin)) == begin(car(stack_end)))
364 // return make_segmented_range_reduce(cdr(stack_begin), cdr(stack_end));
368 // // We are in the case where begin_stack and end_stack (a) have
369 // // more than one element each, and (b) they point to different
370 // // segments. We must construct a segmented sequence.
371 // return segment_sequence(
375 // fusion::next(begin(car(stack_begin))),
376 // begin(car(stack_end))), // a range of (possibly segmented) ranges.
377 // make_segment_sequence_front(stack_begin)), // should be a (possibly segmented) range.
378 // make_segment_sequence_back(stack_end))); // should be a (possibly segmented) range.
386 , int StackBeginSize = StackBegin::size::value
387 , int StackEndSize = StackEnd::size::value>
388 struct make_segmented_range_reduce;
395 typename StackBegin::car_type::begin_type
396 , typename StackEnd::car_type::begin_type
398 struct make_segmented_range_reduce2
402 typename result_of::next<
403 typename StackBegin::car_type::begin_type
405 , typename StackEnd::car_type::begin_type
411 typename result_of::push_back<
412 typename result_of::push_front<
414 , typename make_segment_sequence_front<StackBegin>::type
416 , typename make_segment_sequence_back<StackEnd>::type
421 static type call(StackBegin stack_begin, StackEnd stack_end)
423 //return segment_sequence(
427 // fusion::next(begin(car(stack_begin))),
428 // begin(car(stack_end))), // a range of (possibly segmented) ranges.
429 // make_segment_sequence_front(stack_begin)), // should be a (possibly segmented) range.
430 // make_segment_sequence_back(stack_end))); // should be a (possibly segmented) range.
434 rest_type(fusion::next(stack_begin.car.first), stack_end.car.first)
435 , make_segment_sequence_front<StackBegin>::call(stack_begin))
436 , make_segment_sequence_back<StackEnd>::call(stack_end)));
440 template <typename StackBegin, typename StackEnd>
441 struct make_segmented_range_reduce2<StackBegin, StackEnd, true>
444 make_segmented_range_reduce<
445 typename StackBegin::cdr_type
446 , typename StackEnd::cdr_type
454 static type call(StackBegin stack_begin, StackEnd stack_end)
456 return impl::call(stack_begin.cdr, stack_end.cdr);
460 template <typename StackBegin, typename StackEnd, int StackBeginSize, int StackEndSize>
461 struct make_segmented_range_reduce
462 : make_segmented_range_reduce2<StackBegin, StackEnd>
465 template <typename StackBegin, typename StackEnd>
466 struct make_segmented_range_reduce<StackBegin, StackEnd, 1, 1>
470 typename StackBegin::car_type::begin_type
471 , typename StackEnd::car_type::begin_type
476 single_view<range_type>
480 segment_sequence<segment_type>
483 static type call(StackBegin stack_begin, StackEnd stack_end)
485 //return segment_sequence(
487 // iterator_range(begin(car(stack_begin)), begin(car(stack_end)))));
488 return type(segment_type(range_type(stack_begin.car.first, stack_end.car.first)));
492 //auto make_segmented_range(begin, end)
494 // return make_segmented_range_reduce(reverse(begin.context), reverse(end.context));
497 template <typename Begin, typename End>
498 struct make_segmented_range
500 typedef reverse_cons<typename Begin::context_type> reverse_begin_cons;
501 typedef reverse_cons<typename End::context_type> reverse_end_cons;
504 make_segmented_range_reduce<
505 typename reverse_begin_cons::type
506 , typename reverse_end_cons::type
510 typedef typename impl::type type;
512 static type call(Begin const& begin, End const& end)
515 reverse_begin_cons::call(begin.context)
516 , reverse_end_cons::call(end.context));