From 114556bbba1d9134c57fb9a3d27bc0565658712d Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 5 Oct 2006 01:25:32 +0000 Subject: [PATCH] experimental segmented Fusion support [SVN r35493] --- .../algorithm/iteration/ext_/for_each_s.hpp | 92 +++ .../fusion/algorithm/query/ext_/find_if_s.hpp | 223 ++++++++ .../fusion/sequence/container/ext_/tree.hpp | 130 +++++ .../sequence/intrinsic/ext_/segments.hpp | 57 ++ .../sequence/view/ext_/multiple_view.hpp | 179 ++++++ .../sequence/view/ext_/segmented_iterator.hpp | 416 ++++++++++++++ .../view/ext_/segmented_iterator_range.hpp | 522 ++++++++++++++++++ .../fusion/support/ext_/is_segmented.hpp | 49 ++ test/Jamfile.v2 | 14 + test/algorithm/ext_/find_if_s.cpp | 110 ++++ test/algorithm/ext_/for_each_s.cpp | 83 +++ test/sequence/ext_/iterator_range_s.cpp | 147 +++++ 12 files changed, 2022 insertions(+) create mode 100755 include/boost/fusion/algorithm/iteration/ext_/for_each_s.hpp create mode 100755 include/boost/fusion/algorithm/query/ext_/find_if_s.hpp create mode 100755 include/boost/fusion/sequence/container/ext_/tree.hpp create mode 100755 include/boost/fusion/sequence/intrinsic/ext_/segments.hpp create mode 100755 include/boost/fusion/sequence/view/ext_/multiple_view.hpp create mode 100755 include/boost/fusion/sequence/view/ext_/segmented_iterator.hpp create mode 100755 include/boost/fusion/sequence/view/ext_/segmented_iterator_range.hpp create mode 100755 include/boost/fusion/support/ext_/is_segmented.hpp create mode 100755 test/algorithm/ext_/find_if_s.cpp create mode 100755 test/algorithm/ext_/for_each_s.cpp create mode 100755 test/sequence/ext_/iterator_range_s.cpp diff --git a/include/boost/fusion/algorithm/iteration/ext_/for_each_s.hpp b/include/boost/fusion/algorithm/iteration/ext_/for_each_s.hpp new file mode 100755 index 00000000..2a0f9a48 --- /dev/null +++ b/include/boost/fusion/algorithm/iteration/ext_/for_each_s.hpp @@ -0,0 +1,92 @@ +/*============================================================================= + 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) +==============================================================================*/ +#if !defined(FUSION_FOR_EACH_S_05022006_1027) +#define FUSION_FOR_EACH_S_05022006_1027 + +#include +#include +#include +#include +#include + +// fwd declarations +namespace boost { namespace fusion +{ + template + void + for_each_s(Sequence& seq, F const& f); + + template + void + for_each_s(Sequence const& seq, F const& f); +}} + +namespace boost { namespace fusion { namespace detail +{ + template + struct for_each_s_bind + { + explicit for_each_s_bind(F const &f) + : f_(f) + {} + + template + void operator ()(Sequence &seq) const + { + fusion::for_each_s(seq, this->f_); + } + + template + void operator ()(Sequence const &seq) const + { + fusion::for_each_s(seq, this->f_); + } + private: + F const &f_; + }; + + template + void for_each_s(Sequence &seq, F const &f, mpl::true_) + { + fusion::for_each_s(fusion::segments(seq), for_each_s_bind(f)); + } + + template + void for_each_s(Sequence &seq, F const &f, mpl::false_) + { + fusion::for_each(seq, f); + } +}}} + +namespace boost { namespace fusion +{ + namespace result_of + { + template + struct for_each_s + { + typedef void type; + }; + } + + template + inline void + for_each_s(Sequence& seq, F const& f) + { + detail::for_each_s(seq, f, traits::is_segmented()); + } + + template + inline void + for_each_s(Sequence const& seq, F const& f) + { + detail::for_each_s(seq, f, traits::is_segmented()); + } +}} + +#endif diff --git a/include/boost/fusion/algorithm/query/ext_/find_if_s.hpp b/include/boost/fusion/algorithm/query/ext_/find_if_s.hpp new file mode 100755 index 00000000..6d2d1ea8 --- /dev/null +++ b/include/boost/fusion/algorithm/query/ext_/find_if_s.hpp @@ -0,0 +1,223 @@ +/*============================================================================= + 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) +==============================================================================*/ +#if !defined(FIND_IF_S_05152006_1027) +#define FIND_IF_S_05152006_1027 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fwd declarations +namespace boost { namespace fusion +{ + namespace detail + { + template::value> + struct static_find_if_s_recurse; + } + + namespace result_of + { + template + struct find_if_s; + } +}} + +namespace boost { namespace fusion { namespace detail +{ + + template::value> + struct is_found + : mpl::not_::type> > + {}; + + template + struct is_found + : mpl::not_ > + {}; + + template< + typename SegmentedRange + , typename Where + , typename Sequence = typename remove_reference< + typename result_of::deref< + typename SegmentedRange::iterator_type + >::type + >::type + , bool IsSegmented = traits::is_segmented::value + > + struct as_segmented_cons + { + typedef cons< + SegmentedRange + , cons > + > type; + + static type call(SegmentedRange const &range, Where const &where) + { + return fusion::make_cons( + range + , fusion::make_cons( + segmented_range(*fusion::begin(range), where) + ) + ); + } + }; + + template< + typename SegmentedRange + , typename Where + , typename Sequence + > + struct as_segmented_cons + { + typedef cons type; + + static type call(SegmentedRange const &range, Where const &where) + { + return fusion::make_cons(range, where); + } + }; + + template< + typename SegmentedRange + , typename Pred + , bool IsEmpty = is_empty::value + > + struct static_find_if_s_seg + { + typedef typename SegmentedRange::iterator_type first; + typedef typename result_of::deref::type segment_ref; + typedef typename remove_reference::type segment; + typedef static_find_if_s_recurse where; + typedef range_next next; + typedef is_found is_found; + typedef as_segmented_cons found; + typedef static_find_if_s_seg not_found; + typedef typename mpl::eval_if::type type; + + static type call(SegmentedRange const &range) + { + return call_(range, is_found()); + } + + private: + static type call_(SegmentedRange const &range, mpl::true_) + { + return found::call(range, where::call(*range.where)); + } + + static type call_(SegmentedRange const &range, mpl::false_) + { + return not_found::call(next::call(range)); + } + }; + + template< + typename SegmentedRange + , typename Pred + > + struct static_find_if_s_seg + { + typedef nil type; + + static type call(SegmentedRange const &) + { + return nil(); + } + }; + + template + struct static_find_if_s_recurse + { + typedef typename as_segmented_range::type range; + typedef static_find_if_s_seg find_if; + typedef typename find_if::type type; + + static type call(Sequence &seq) + { + return find_if::call(range(fusion::segments(seq))); + } + }; + + template + struct static_find_if_s_recurse + { + typedef typename result_of::find_if::type type; + + static type call(Sequence &seq) + { + return fusion::find_if(seq); + } + }; + + template::value> + struct static_find_if_s + : static_find_if_s_recurse + {}; + + template + struct static_find_if_s + { + typedef typename as_segmented_range::type range; + typedef static_find_if_s_recurse find_if; + typedef typename find_if::type found; + + typedef segmented_iterator::type> type; + + static type call(Sequence &seq) + { + return type(reverse_cons::call(find_if::call(seq))); + } + }; +}}} + +namespace boost { namespace fusion +{ + namespace result_of + { + template + struct find_if_s + { + typedef typename + detail::static_find_if_s< + Sequence + , Pred + >::type + type; + }; + } + + template + typename lazy_disable_if< + is_const + , result_of::find_if_s + >::type + find_if_s(Sequence& seq) + { + return detail::static_find_if_s::call(seq); + } + + template + typename result_of::find_if_s::type + find_if_s(Sequence const& seq) + { + return detail::static_find_if_s::call(seq); + } +}} + +#endif diff --git a/include/boost/fusion/sequence/container/ext_/tree.hpp b/include/boost/fusion/sequence/container/ext_/tree.hpp new file mode 100755 index 00000000..c6edc28c --- /dev/null +++ b/include/boost/fusion/sequence/container/ext_/tree.hpp @@ -0,0 +1,130 @@ +/*============================================================================= + 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_BINARY_TREE_EAN_05032006_1027 +#define FUSION_BINARY_TREE_EAN_05032006_1027 + +#include +#include +#include +#include +#include +#include +#include +#include // for nil +#include +#include +#include +#include +#include + +namespace boost { namespace fusion +{ + struct tree_tag; + + namespace detail + { + template + struct reference : add_reference {}; + + template + struct reference : reference::type, false> {}; + + template + struct reference : reference {}; + } + + template + struct tree + : sequence_base > + { + typedef Data data_type; + typedef Left left_type; + typedef Right right_type; + typedef tree_tag fusion_tag; + typedef forward_traversal_tag category; + typedef mpl::false_ is_view; + + typedef typename mpl::if_< + traits::is_sequence + , Data + , single_view + >::type data_view; + + explicit tree( + typename fusion::detail::call_param::type data_ + , typename fusion::detail::call_param::type left_ = Left() + , typename fusion::detail::call_param::type right_ = Right() + ) + : segments(left_, data_view(data_), right_) + {} + + typedef vector3 segments_type; + segments_type segments; + }; + + template + tree make_tree(Data const &data) + { + return tree(data); + } + + template + tree make_tree(Data const &data, Left const &left, Right const &right) + { + return tree(data, left, right); + } + + namespace extension + { + template<> + struct is_segmented_impl + { + template + struct apply : mpl::true_ {}; + }; + + template<> + struct segments_impl + { + template + struct apply + { + typedef typename mpl::if_< + is_const + , typename Sequence::segments_type const & + , typename Sequence::segments_type & + >::type type; + + static type call(Sequence &seq) + { + return seq.segments; + } + }; + }; + + template<> + struct begin_impl + { + template + struct apply + : segmented_begin + {}; + }; + + template<> + struct end_impl + { + template + struct apply + : segmented_end + {}; + }; + } +}} + +#endif diff --git a/include/boost/fusion/sequence/intrinsic/ext_/segments.hpp b/include/boost/fusion/sequence/intrinsic/ext_/segments.hpp new file mode 100755 index 00000000..1d4fd220 --- /dev/null +++ b/include/boost/fusion/sequence/intrinsic/ext_/segments.hpp @@ -0,0 +1,57 @@ +/*============================================================================= + 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) +==============================================================================*/ +#if !defined(FUSION_SEGMENTS_04052005_1141) +#define FUSION_SEGMENTS_04052005_1141 + +#include + +namespace boost { namespace fusion +{ + // segments: returns a sequence of sequences + namespace extension + { + template + struct segments_impl + { + template + struct apply {}; + }; + } + + namespace result_of + { + template + struct segments + { + typedef typename + extension::segments_impl::type>:: + template apply::type + type; + }; + } + + template + typename result_of::segments::type + segments(Sequence & seq) + { + return + extension::segments_impl::type>:: + template apply::call(seq); + } + + template + typename result_of::segments::type + segments(Sequence const& seq) + { + return + extension::segments_impl::type>:: + template apply::call(seq); + } +}} + +#endif diff --git a/include/boost/fusion/sequence/view/ext_/multiple_view.hpp b/include/boost/fusion/sequence/view/ext_/multiple_view.hpp new file mode 100755 index 00000000..2297aa7f --- /dev/null +++ b/include/boost/fusion/sequence/view/ext_/multiple_view.hpp @@ -0,0 +1,179 @@ +/*============================================================================= + Copyright (c) 2001-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_MULTIPLE_VIEW_05052005_0335 +#define FUSION_MULTIPLE_VIEW_05052005_0335 + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace fusion +{ + struct multiple_view_tag; + struct forward_traversal_tag; + struct fusion_sequence_tag; + + template + struct multiple_view + : sequence_base > + { + typedef multiple_view_tag fusion_tag; + typedef fusion_sequence_tag tag; // this gets picked up by MPL + typedef forward_traversal_tag category; + typedef mpl::true_ is_view; + typedef mpl::int_ size; + typedef T value_type; + + multiple_view() + : val() + {} + + explicit multiple_view(typename detail::call_param::type val) + : val(val) + {} + + value_type val; + }; + + template + inline multiple_view::type> + make_multiple_view(T const& v) + { + return multiple_view::type>(v); + } + + struct multiple_view_iterator_tag; + struct forward_traversal_tag; + + template + struct multiple_view_iterator + : iterator_base > + { + typedef multiple_view_iterator_tag fusion_tag; + typedef forward_traversal_tag category; + typedef typename MultipleView::value_type value_type; + typedef MultipleView multiple_view_type; + typedef Index index; + + explicit multiple_view_iterator(multiple_view_type const &view_) + : view(view_) + {} + + multiple_view_type view; + }; + + namespace extension + { + template + struct next_impl; + + template <> + struct next_impl + { + template + struct apply + { + typedef multiple_view_iterator< + typename mpl::next::type + , typename Iterator::multiple_view_type + > type; + + static type + call(Iterator const &where) + { + return type(where.view); + } + }; + }; + + template + struct end_impl; + + template <> + struct end_impl + { + template + struct apply + { + typedef multiple_view_iterator< + typename Sequence::size + , Sequence + > type; + + static type + call(Sequence &seq) + { + return type(seq); + } + }; + }; + + template + struct deref_impl; + + template <> + struct deref_impl + { + template + struct apply + { + typedef typename Iterator::value_type type; + + static type + call(Iterator const& i) + { + return i.view.val; + } + }; + }; + + template + struct begin_impl; + + template <> + struct begin_impl + { + template + struct apply + { + typedef multiple_view_iterator< + mpl::int_<0> + , Sequence + > type; + + static type + call(Sequence &seq) + { + return type(seq); + } + }; + }; + + template + struct value_of_impl; + + template <> + struct value_of_impl + { + template + struct apply + { + typedef typename Iterator::multiple_view_type multiple_view_type; + typedef typename multiple_view_type::value_type type; + }; + }; + } +}} + +#endif + + diff --git a/include/boost/fusion/sequence/view/ext_/segmented_iterator.hpp b/include/boost/fusion/sequence/view/ext_/segmented_iterator.hpp new file mode 100755 index 00000000..f242aa43 --- /dev/null +++ b/include/boost/fusion/sequence/view/ext_/segmented_iterator.hpp @@ -0,0 +1,416 @@ +/*============================================================================= + 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 // for nil +#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 + > + {}; + + struct segmented_range_tag; + + //////////////////////////////////////////////////////////////////////////// + template + struct segmented_range + : sequence_base > + { + 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; + typedef Iterator iterator_type; + + // 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 traits::category_of::type category; + + explicit segmented_range(Sequence &sequence_) + : sequence(sequence_type(sequence_)) + , where(fusion::begin(sequence)) + {} + + segmented_range(sequence_type sequence_, iterator_type const &where_) + : sequence(sequence_) + , where(where_) + {} + + sequence_type sequence; + iterator_type where; + }; + } + + 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 result_of::next::type iterator_type; + typedef segmented_range type; + + static type call(segmented_range const &rng) + { + return type(rng.sequence, fusion::next(rng.where)); + } + }; + + /////////////////////////////////////////////////////////////////////// + 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 typename result_of::begin > > >::type begin; + typedef segmented_range type; + + static type call(Sequence &seq) + { + return type(fusion::segments(seq)); + } + }; + + template + struct as_segmented_range + { + typedef typename remove_reference::type sequence; + typedef typename result_of::begin::type begin; + typedef segmented_range 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)); + return push::call(*fusion::begin(rng), 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 &cons) + : cons_(cons) + {} + + 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 diff --git a/include/boost/fusion/sequence/view/ext_/segmented_iterator_range.hpp b/include/boost/fusion/sequence/view/ext_/segmented_iterator_range.hpp new file mode 100755 index 00000000..7bab8789 --- /dev/null +++ b/include/boost/fusion/sequence/view/ext_/segmented_iterator_range.hpp @@ -0,0 +1,522 @@ +/*============================================================================= + 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_RANGE_EAN_05032006_1027 +#define FUSION_SEGMENTED_ITERATOR_RANGE_EAN_05032006_1027 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace fusion +{ + namespace detail + { + //////////////////////////////////////////////////////////////////////////// + template + struct reverse_cons; + + template + struct reverse_cons, State> + { + typedef reverse_cons > reverse; + typedef typename reverse::type type; + + static type call(cons const &cons, State const &state = State()) + { + return reverse::call(cons.cdr, fusion::make_cons(cons.car, state)); + } + }; + + template + struct reverse_cons + { + typedef State type; + + static State const &call(nil const &, State const &state = State()) + { + return state; + } + }; + + //////////////////////////////////////////////////////////////////////////// + // tags + struct full_view {}; + struct left_view {}; + struct right_view {}; + struct center_view {}; + + template + struct segmented_view_tag; + + //////////////////////////////////////////////////////////////////////////// + // a segmented view of that includes all elements either to the + // right or the left of a segmented iterator. + template + struct segmented_view + : sequence_base > + { + typedef segmented_view_tag fusion_tag; + typedef fusion_sequence_tag tag; // this gets picked up by MPL + typedef mpl::true_ is_view; + typedef forward_traversal_tag category; + + explicit segmented_view(Cons1 const &cons) + : cons(cons) + {} + + typedef Cons1 cons_type; + cons_type const &cons; + }; + + // a segmented view that contains all the elements in between + // two segmented iterators + template + struct segmented_view + : sequence_base > + { + typedef segmented_view_tag fusion_tag; + typedef fusion_sequence_tag tag; // this gets picked up by MPL + typedef mpl::true_ is_view; + typedef forward_traversal_tag category; + + segmented_view(Cons1 const &lcons, Cons2 const &rcons) + : left_cons(lcons) + , right_cons(rcons) + {} + + typedef Cons1 left_cons_type; + typedef Cons2 right_cons_type; + + left_cons_type const &left_cons; + right_cons_type const &right_cons; + }; + + //////////////////////////////////////////////////////////////////////////// + // Used to transform a sequence of segments. The first segment is + // bounded by RightCons, and the last segment is bounded by LeftCons + // and all the others are passed through unchanged. + template + struct segments_transform + { + explicit segments_transform(RightCons const &cons_) + : right_cons(cons_) + , left_cons(cons_) + {} + + segments_transform(RightCons const &right_cons_, LeftCons const &left_cons_) + : right_cons(right_cons_) + , left_cons(left_cons_) + {} + + template + struct result; + + template + struct result + { + typedef segmented_view type; + }; + + template + struct result + { + typedef segmented_view type; + }; + + template + struct result + { + typedef Second type; + }; + + template + segmented_view operator ()(right_view, Second &second) const + { + return segmented_view(this->right_cons); + } + + template + segmented_view operator ()(left_view, Second &second) const + { + return segmented_view(this->left_cons); + } + + template + Second &operator ()(full_view, Second &second) const + { + return second; + } + + private: + RightCons const &right_cons; + LeftCons const &left_cons; + }; + + } // namespace detail + + namespace extension + { + //////////////////////////////////////////////////////////////////////////// + template + struct is_segmented_impl > + { + template + struct apply + : mpl::true_ + {}; + }; + + //////////////////////////////////////////////////////////////////////////// + template<> + struct segments_impl > + { + template< + typename Sequence + , typename Cdr = typename Sequence::cons_type::cdr_type + > + struct apply + { + typedef typename Sequence::cons_type::car_type segmented_range; + typedef typename result_of::size::type size; + typedef typename mpl::prior::type size_minus_1; + typedef detail::segments_transform tfx; + typedef joint_view< + single_view const + , multiple_view const + > mask; + typedef transform_view type; + + static type call(Sequence &seq) + { + return type( + mask( + make_single_view(detail::right_view()) + , make_multiple_view(detail::full_view()) + ) + , seq.cons.car + , tfx(seq.cons.cdr) + ); + } + }; + + template + struct apply + { + typedef typename Sequence::cons_type::car_type segmented_range; + typedef typename segmented_range::iterator_type begin; + typedef typename segmented_range::sequence_non_ref_type sequence_type; + typedef typename result_of::end::type end; + typedef iterator_range range; + typedef single_view type; + + static type call(Sequence &seq) + { + return type(range(seq.cons.car.where, fusion::end(seq.cons.car.sequence))); + } + }; + }; + + //////////////////////////////////////////////////////////////////////////// + template<> + struct segments_impl > + { + template< + typename Sequence + , typename Cdr = typename Sequence::cons_type::cdr_type + > + struct apply + { + typedef typename Sequence::cons_type::car_type right_segmented_range; + typedef typename right_segmented_range::sequence_type sequence_type; + typedef typename right_segmented_range::iterator_type iterator_type; + + typedef iterator_range< + typename result_of::begin::type + , typename result_of::next::type + > segmented_range; + + typedef detail::segments_transform tfx; + typedef typename result_of::size::type size; + typedef typename mpl::prior::type size_minus_1; + typedef joint_view< + multiple_view const + , single_view const + > mask; + typedef transform_view type; + + static type call(Sequence &seq) + { + return type( + mask( + make_multiple_view(detail::full_view()) + , make_single_view(detail::left_view()) + ) + , segmented_range(fusion::begin(seq.cons.car.sequence), fusion::next(seq.cons.car.where)) + , tfx(seq.cons.cdr) + ); + } + }; + + template + struct apply + { + typedef typename Sequence::cons_type::car_type segmented_range; + typedef typename segmented_range::sequence_non_ref_type sequence_type; + typedef typename result_of::begin::type begin; + typedef typename segmented_range::iterator_type end; + typedef iterator_range range; + typedef single_view type; + + static type call(Sequence &seq) + { + return type(range(fusion::begin(seq.cons.car.sequence), seq.cons.car.where)); + } + }; + }; + + //////////////////////////////////////////////////////////////////////////// + template<> + struct segments_impl > + { + template + struct apply + { + typedef typename Sequence::right_cons_type right_cons_type; + typedef typename Sequence::left_cons_type left_cons_type; + typedef typename right_cons_type::car_type right_segmented_range; + typedef typename left_cons_type::car_type left_segmented_range; + + typedef iterator_range< + typename result_of::begin::type + , typename result_of::next::type>::type + > segmented_range; + + typedef typename mpl::minus< + typename result_of::size::type + , mpl::int_<2> + >::type size_minus_2; + + BOOST_MPL_ASSERT_RELATION(0, <=, size_minus_2::value); + + typedef detail::segments_transform< + typename left_cons_type::cdr_type + , typename right_cons_type::cdr_type + > tfx; + + typedef joint_view< + multiple_view const + , single_view const + > left_mask; + + typedef joint_view< + single_view const + , left_mask const + > mask; + + typedef transform_view type; + + static type call(Sequence &seq) + { + left_mask lmask( + make_multiple_view(detail::full_view()) + , make_single_view(detail::left_view()) + ); + return type( + mask(make_single_view(detail::right_view()), lmask) + , segmented_range(fusion::begin(seq.left_cons.car), fusion::next(fusion::begin(seq.right_cons.car))) + , tfx(seq.left_cons.cdr, seq.right_cons.cdr) + ); + } + }; + }; + } + + // specialize iterator_range for use with segmented iterators, so that + // it presents a segmented view of the range. + template + struct iterator_range; + + template + struct iterator_range, segmented_iterator > + : sequence_base, segmented_iterator > > + { + typedef typename convert_iterator >::type begin_type; + typedef typename convert_iterator >::type end_type; + typedef typename detail::reverse_cons::type begin_cons_type; + typedef typename detail::reverse_cons::type end_cons_type; + typedef iterator_range_tag fusion_tag; + typedef fusion_sequence_tag tag; // this gets picked up by MPL + typedef typename traits::category_of::type category; + typedef typename result_of::distance::type size; + typedef mpl::true_ is_view; + + iterator_range(segmented_iterator const& first_, segmented_iterator const& last_) + : first(convert_iterator >::call(first_)) + , last(convert_iterator >::call(last_)) + , first_cons(detail::reverse_cons::call(first_.cons())) + , last_cons(detail::reverse_cons::call(last_.cons())) + {} + + begin_type first; + end_type last; + + begin_cons_type first_cons; + end_cons_type last_cons; + }; + + namespace detail + { + + template + struct same_segment + : mpl::false_ + {}; + + template + struct same_segment, cons > + : mpl::and_< + traits::is_segmented + , is_same + > + {}; + + //////////////////////////////////////////////////////////////////////////// + template + struct segments_gen; + + //////////////////////////////////////////////////////////////////////////// + template + struct segments_gen2 + { + typedef segments_gen gen; + typedef typename gen::type type; + + static type call(Cons1 const &cons1, Cons2 const &cons2) + { + return gen::call(cons1.cdr, cons2.cdr); + } + }; + + template + struct segments_gen2 + { + typedef segmented_view view; + typedef typename result_of::segments::type type; + + static type call(Cons1 const &cons1, Cons2 const &cons2) + { + view v(cons1, cons2); + return fusion::segments(v); + } + }; + + template + struct segments_gen2, cons, false> + { + typedef iterator_range< + typename Car1::iterator_type + , typename Car2::iterator_type + > range; + + typedef single_view type; + + static type call(cons const &cons1, cons const &cons2) + { + return type(range(cons1.car.where, cons2.car.where)); + } + }; + + //////////////////////////////////////////////////////////////////////////// + template + struct segments_gen + : segments_gen2::value> + {}; + + template + struct segments_gen, nil> + { + typedef segmented_view > view; + typedef typename result_of::segments::type type; + + static type call(cons const &cons, nil const &) + { + view v(cons); + return fusion::segments(v); + } + }; + + template<> + struct segments_gen + { + typedef nil type; + + static type call(nil const &, nil const &) + { + return nil(); + } + }; + } // namespace detail + + namespace extension + { + template + struct is_segmented_impl; + + // An iterator_range of segmented_iterators is segmented + template<> + struct is_segmented_impl + { + template + struct is_segmented_iterator : mpl::false_ {}; + + template + struct is_segmented_iterator > : mpl::true_ {}; + + template + struct apply + : mpl::and_< + is_segmented_iterator + , is_segmented_iterator + > + {}; + }; + + template + struct segments_impl; + + template<> + struct segments_impl + { + template + struct apply + { + typedef typename Sequence::begin_cons_type begin_cons; + typedef typename Sequence::end_cons_type end_cons; + + typedef detail::segments_gen gen; + typedef typename gen::type type; + + static type call(Sequence &sequence) + { + return gen::call(sequence.first_cons, sequence.last_cons); + } + }; + }; + } + +}} + +#endif diff --git a/include/boost/fusion/support/ext_/is_segmented.hpp b/include/boost/fusion/support/ext_/is_segmented.hpp new file mode 100755 index 00000000..eb6b9e93 --- /dev/null +++ b/include/boost/fusion/support/ext_/is_segmented.hpp @@ -0,0 +1,49 @@ +/*============================================================================= + 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) +==============================================================================*/ +#if !defined(FUSION_IS_SEGMENTED_03202006_0015) +#define FUSION_IS_SEGMENTED_03202006_0015 + +#include + +namespace boost { namespace fusion +{ + // Special tags: + struct sequence_facade_tag; + struct boost_tuple_tag; // boost::tuples::tuple tag + struct array_tag; // boost::array tag + struct mpl_sequence_tag; // mpl sequence tag + struct std_pair_tag; // std::pair tag + struct iterator_range_tag; + + namespace extension + { + template + struct is_segmented_impl + { + template + struct apply + : mpl::false_ + {}; + }; + + template<> + struct is_segmented_impl; + } + + namespace traits + { + template + struct is_segmented + : extension::is_segmented_impl::type>:: + template apply + { + }; + } +}} + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4b645a16..31bedbc3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -95,3 +95,17 @@ import testing ; ; } +{ + # Text for extension features, must be explicitly specified on the command line to be run + # TODO these are not in a test-suite because currently test-suites cannot be marked "explicit" + + run algorithm/ext_/for_each_s.cpp ; + explicit for_each_s ; + + run algorithm/ext_/find_if_s.cpp ; + explicit find_if_s ; + + run sequence/ext_/iterator_range_s.cpp ; + explicit iterator_range_s ; +} + diff --git a/test/algorithm/ext_/find_if_s.cpp b/test/algorithm/ext_/find_if_s.cpp new file mode 100755 index 00000000..8f5484ad --- /dev/null +++ b/test/algorithm/ext_/find_if_s.cpp @@ -0,0 +1,110 @@ +/*============================================================================= + Copyright (c) 2001-2006 Joel de Guzman + + 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) +==============================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct X +{ + operator int() const + { + return 12345; + } +}; + +template +void +process_tree(Tree const &tree) +{ + using namespace boost; + using mpl::_; + + typedef typename fusion::result_of::find_if_s >::type short_iter; + typedef typename fusion::result_of::find_if_s >::type float_iter; + + // find_if_s of a segmented data structure returns generic + // segmented iterators + short_iter si = fusion::find_if_s >(tree); + float_iter fi = fusion::find_if_s >(tree); + + // they behave like ordinary Fusion iterators ... + BOOST_TEST((*si == short('d'))); + BOOST_TEST((*fi == float(1))); +} + +int +main() +{ + using namespace boost::fusion; + + { + using boost::is_same; + using boost::mpl::_; + + typedef vector vector_type; + vector_type v(12345, 'x', 678910, 3.36); + + std::cout << *find_if_s >(v) << std::endl; + BOOST_TEST((*find_if_s >(v) == 'x')); + + std::cout << *find_if_s >(v) << std::endl; + BOOST_TEST((*find_if_s >(v) == 12345)); + + std::cout << *find_if_s >(v) << std::endl; + BOOST_TEST((*find_if_s >(v) == 3.36)); + } + + { + using boost::mpl::vector; + using boost::is_same; + using boost::mpl::_; + + typedef vector mpl_vec; + BOOST_TEST((*find_if_s >(mpl_vec()) == 12345)); + } + + { + using boost::mpl::vector_c; + using boost::mpl::less; + using boost::mpl::int_; + using boost::is_same; + using boost::mpl::_; + + typedef vector_c mpl_vec; + BOOST_TEST((*find_if_s > >(mpl_vec()) == 1)); + } + + { + process_tree( + make_tree( + make_vector(double(0),'B') + , make_tree( + make_vector(1,2,long(3)) + , make_tree(make_vector('a','b','c')) + , make_tree(make_vector(short('d'),'e','f')) + ) + , make_tree( + make_vector(4,5,6) + , make_tree(make_vector(float(1),'h','i')) + , make_tree(make_vector('j','k','l')) + ) + ) + ); + } + + return boost::report_errors(); +} + diff --git a/test/algorithm/ext_/for_each_s.cpp b/test/algorithm/ext_/for_each_s.cpp new file mode 100755 index 00000000..b0e28f7a --- /dev/null +++ b/test/algorithm/ext_/for_each_s.cpp @@ -0,0 +1,83 @@ +/*============================================================================= + Copyright (c) 2001-2006 Joel de Guzman, 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) +==============================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include + +struct print +{ + template + void operator()(T const& v) const + { + std::cout << "[ " << v << " ] "; + } +}; + +struct increment +{ + template + void operator()(T& v) const + { + ++v; + } +}; + +int +main() +{ + using namespace boost::fusion; + using boost::mpl::vector_c; + namespace fusion = boost::fusion; + + { + typedef vector vector_type; + vector_type v(1, 'x', 3.3, "Ruby"); + for_each_s(v, print()); + std::cout << std::endl; + } + + { + typedef vector vector_type; + vector_type v(1, 'x', 3.3, "Ruby"); + for_each_s(v, increment()); + std::cout << v << std::endl; + } + + { + typedef vector_c mpl_vec; + fusion::for_each_s(mpl_vec(), print()); + std::cout << std::endl; + } + + { + fusion::for_each_s( + make_tree( + make_vector(double(0),'B') + , make_tree( + make_vector(1,2,long(3)) + , make_tree(make_vector('a','b','c')) + , make_tree(make_vector(short('d'),'e','f')) + ) + , make_tree( + make_vector(4,5,6) + , make_tree(make_vector(float(1),'h','i')) + , make_tree(make_vector('j','k','l')) + ) + ) + , print() + ); + } + + return boost::report_errors(); +} + diff --git a/test/sequence/ext_/iterator_range_s.cpp b/test/sequence/ext_/iterator_range_s.cpp new file mode 100755 index 00000000..ddbfd682 --- /dev/null +++ b/test/sequence/ext_/iterator_range_s.cpp @@ -0,0 +1,147 @@ +/*============================================================================= + Copyright (c) 2001-2006 Joel de Guzman + + 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) +==============================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ostream_fun +{ + ostream_fun(std::ostream &sout) + : sout_(sout) + {} + template + void operator ()(T const &t) const + { + sout_ << t << ' '; + } +private: + std::ostream & sout_; +}; + +template +void +process_tree(Tree const &tree) +{ + using namespace boost; + using namespace fusion; + using mpl::_; + + typedef typename result_of::find_if_s >::type short_iter; + typedef typename result_of::find_if_s >::type float_iter; + + typedef iterator_range slice_t; + BOOST_STATIC_ASSERT(traits::is_segmented::value); + + // find_if_s of a segmented data structure returns generic + // segmented iterators + short_iter si = find_if_s >(tree); + float_iter fi = find_if_s >(tree); + + // If you put them in an iterator range, the range + // is automatically a segmented data structure. + slice_t slice(si, fi); + + std::stringstream sout; + fusion::for_each_s(slice, ostream_fun(sout)); + BOOST_TEST((sout.str() == "100 e f 0 B ")); +} + +int +main() +{ + using namespace boost::fusion; + + std::cout << tuple_open('['); + std::cout << tuple_close(']'); + std::cout << tuple_delimiter(", "); + + { + char const* s = "Ruby"; + typedef vector vector_type; + vector_type vec(1, 'x', 3.3, s); + + { + typedef vector_iterator i1t; + typedef vector_iterator i3t; + + i1t i1(vec); + i3t i3(vec); + + typedef iterator_range slice_t; + slice_t slice(i1, i3); + std::cout << slice << std::endl; + BOOST_TEST((slice == make_vector('x', 3.3))); + BOOST_STATIC_ASSERT(result_of::size::value == 2); + } + + { + typedef vector_iterator i1t; + typedef vector_iterator i3t; + + i1t i1(vec); + i3t i3(vec); + + typedef iterator_range slice_t; + slice_t slice(i1, i3); + std::cout << slice << std::endl; + BOOST_TEST(slice == make_vector()); + BOOST_STATIC_ASSERT(result_of::size::value == 0); + } + } + + { + typedef boost::mpl::vector_c mpl_vec; + typedef boost::mpl::begin::type it0; + typedef boost::mpl::next::type it1; + typedef boost::mpl::next::type it2; + typedef boost::mpl::next::type it3; + + it1 f; + it3 l; + + typedef iterator_range slice_t; + slice_t slice(f, l); + std::cout << slice << std::endl; + BOOST_TEST((slice == make_vector(3, 4))); + BOOST_STATIC_ASSERT(result_of::size::value == 2); + } + + { + process_tree( + make_tree( + make_vector(double(0),'B') + , make_tree( + make_vector(1,2,long(3)) + , make_tree(make_vector('a','b','c')) + , make_tree(make_vector(short('d'),'e','f')) + ) + , make_tree( + make_vector(4,5,6) + , make_tree(make_vector(float(1),'h','i')) + , make_tree(make_vector('j','k','l')) + ) + ) + ); + } + + return boost::report_errors(); +} +