/*============================================================================= Copyright (c) 2006 Eric Niebler Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #ifndef FUSION_SEGMENTED_ITERATOR_EAN_05032006_1027 #define FUSION_SEGMENTED_ITERATOR_EAN_05032006_1027 #include #include #include #include #include #include #include #include #include #include #include #include #include // for nil #include #include #include #include #include namespace boost { namespace fusion { struct fusion_sequence_tag; namespace detail { using mpl::_; using mpl::not_; //////////////////////////////////////////////////////////////////////////// template struct is_empty : result_of::equal_to< typename result_of::begin::type , typename result_of::end::type > {}; template struct is_empty : is_empty {}; //////////////////////////////////////////////////////////////////////////// struct not_is_empty_pred { template struct apply : not_ > {}; }; struct segmented_range_tag; //////////////////////////////////////////////////////////////////////////// template struct segmented_range : sequence_base > { BOOST_MPL_ASSERT_NOT((is_reference)); typedef mpl::bool_ is_segmented; typedef segmented_range_tag fusion_tag; typedef fusion_sequence_tag tag; // this gets picked up by MPL typedef mpl::true_ is_view; // If this is a range of segments, skip over the empty ones typedef typename mpl::if_< is_segmented , filter_view , Sequence >::type sequence_non_ref_type; typedef typename mpl::if_< traits::is_view , sequence_non_ref_type , sequence_non_ref_type & >::type sequence_type; typedef typename fusion::result_of::advance< typename fusion::result_of::begin::type , Index >::type iterator_type; typedef typename traits::category_of::type category; explicit segmented_range(Sequence &sequence_) : sequence(sequence_type(sequence_)) {} segmented_range(sequence_type sequence_, int) : sequence(sequence_) {} iterator_type where_() const { return fusion::advance( fusion::begin(const_cast(this->sequence)) ); } sequence_type sequence; private: segmented_range &operator =(segmented_range const &); }; } namespace extension { template<> struct is_segmented_impl { template struct apply : Sequence::is_segmented {}; }; template<> struct size_impl { template struct apply : mpl::int_< result_of::distance< typename Sequence::iterator_type , typename result_of::end::type >::value > {}; }; template<> struct segments_impl { template struct apply { typedef Sequence &type; static type call(Sequence &seq) { return seq; } }; }; template<> struct begin_impl { template struct apply { typedef typename Sequence::iterator_type type; static type call(Sequence &seq) { return seq.where_(); } }; }; template<> struct end_impl { template struct apply { typedef typename Sequence::sequence_non_ref_type sequence; typedef typename result_of::end::type type; static type call(Sequence &seq) { return fusion::end(seq.sequence); } }; }; } namespace detail { /////////////////////////////////////////////////////////////////////// template struct range_next; template struct range_next > { typedef typename mpl::next::type index_type; typedef segmented_range type; static type call(segmented_range const &rng) { return type(rng.sequence, 0); } }; /////////////////////////////////////////////////////////////////////// template struct is_range_next_empty : is_empty::type> {}; template<> struct is_range_next_empty : mpl::true_ {}; /////////////////////////////////////////////////////////////////////// template::value> struct as_segmented_range { typedef typename result_of::segments::type segments; typedef typename remove_reference::type sequence; typedef segmented_range, true> type; static type call(Sequence &seq) { segments segs(fusion::segments(seq)); return type(segs); } }; template struct as_segmented_range { typedef typename remove_reference::type sequence; typedef segmented_range, false> type; static type call(Sequence &seq) { return type(seq); } }; template struct as_segmented_range, IsSegmented> { typedef segmented_range type; static type &call(type &seq) { return seq; } }; /////////////////////////////////////////////////////////////////////// template< typename Sequence , typename State = nil , bool IsSegmented = traits::is_segmented::value > struct push_segments { typedef typename as_segmented_range::type range; typedef typename result_of::begin::type begin; typedef typename result_of::deref::type next_ref; typedef typename remove_reference::type next; typedef push_segments > push; typedef typename push::type type; static type call(Sequence &seq, State const &state) { range rng(as_segmented_range::call(seq)); next_ref nxt(*fusion::begin(rng)); return push::call(nxt, fusion::make_cons(rng, state)); } }; template struct push_segments { typedef typename as_segmented_range::type range; typedef cons type; static type call(Sequence &seq, State const &state) { range rng(as_segmented_range::call(seq)); return fusion::make_cons(rng, state); } }; /////////////////////////////////////////////////////////////////////// template::value> struct pop_segments { typedef range_next next; typedef push_segments push; typedef typename push::type type; static type call(State const &state) { typename next::type rng(next::call(state.car)); return push::call(rng, state.cdr); } }; template struct pop_segments { typedef pop_segments pop; typedef typename pop::type type; static type call(State const &state) { return pop::call(state.cdr); } }; template<> struct pop_segments { typedef nil type; static type call(nil const &) { return nil(); } }; } // namespace detail struct segmented_iterator_tag; //////////////////////////////////////////////////////////////////////////// template struct segmented_iterator : fusion::iterator_base > { typedef segmented_iterator_tag fusion_tag; typedef fusion::forward_traversal_tag category; typedef Cons cons_type; typedef typename Cons::car_type car_type; typedef typename Cons::cdr_type cdr_type; explicit segmented_iterator(Cons const &c) : cons_(c) {} cons_type const &cons() const { return this->cons_; }; car_type const &car() const { return this->cons_.car; }; cdr_type const &cdr() const { return this->cons_.cdr; }; private: Cons cons_; }; /////////////////////////////////////////////////////////////////////////// template struct segmented_begin { typedef typename detail::push_segments push; typedef segmented_iterator type; static type call(Sequence &seq) { return type(push::call(seq, nil())); } }; /////////////////////////////////////////////////////////////////////////// template struct segmented_end { typedef segmented_iterator type; static type call(Sequence &) { return type(nil()); } }; namespace extension { template<> struct value_of_impl { template struct apply { typedef typename result_of::begin::type begin; typedef typename result_of::value_of::type type; }; }; template<> struct deref_impl { template struct apply { typedef typename result_of::begin::type begin; typedef typename result_of::deref::type type; static type call(Iterator const &it) { return *fusion::begin(it.car()); } }; }; // discards the old head, expands the right child of the new head // and pushes the result to the head of the list. template<> struct next_impl { template< typename Iterator , bool IsSegmentDone = detail::is_range_next_empty::value > struct apply { typedef typename Iterator::cdr_type cdr_type; typedef detail::range_next next; typedef segmented_iterator > type; static type call(Iterator const &it) { return type(fusion::make_cons(next::call(it.car()), it.cdr())); } }; template struct apply // segment done, move to next segment { typedef typename Iterator::cdr_type cdr_type; typedef typename detail::pop_segments pop; typedef segmented_iterator type; static type call(Iterator const &it) { return type(pop::call(it.cdr())); } }; }; } }} // namespace boost::fusion #endif