blob: 86feddd24fa987329066ffdeba9f33e2bf360cf3 [file] [log] [blame]
/*=============================================================================
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 <boost/mpl/bool.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/and.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/fusion/iterator/mpl/convert_iterator.hpp>
#include <boost/fusion/container/list/cons.hpp>
#include <boost/fusion/view/joint_view.hpp>
#include <boost/fusion/view/single_view.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/view/iterator_range.hpp>
#include <boost/fusion/view/ext_/multiple_view.hpp>
#include <boost/fusion/view/ext_/segmented_iterator.hpp>
#include <boost/fusion/adapted/mpl/mpl_iterator.hpp>
namespace boost { namespace fusion
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////
template<typename Cons, typename State = nil>
struct reverse_cons;
template<typename Car, typename Cdr, typename State>
struct reverse_cons<cons<Car, Cdr>, State>
{
typedef reverse_cons<Cdr, cons<Car, State> > reverse;
typedef typename reverse::type type;
static type call(cons<Car, Cdr> const &cons, State const &state = State())
{
return reverse::call(cons.cdr, fusion::make_cons(cons.car, state));
}
};
template<typename State>
struct reverse_cons<nil, State>
{
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<typename Tag>
struct segmented_view_tag;
////////////////////////////////////////////////////////////////////////////
// a segmented view of that includes all elements either to the
// right or the left of a segmented iterator.
template<typename Tag, typename Cons1, typename Cons2 = void_>
struct segmented_view
: sequence_base<segmented_view<Tag, Cons1, Cons2> >
{
typedef segmented_view_tag<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<typename Cons1, typename Cons2>
struct segmented_view<center_view, Cons1, Cons2>
: sequence_base<segmented_view<center_view, Cons1, Cons2> >
{
typedef segmented_view_tag<center_view> 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<typename RightCons, typename LeftCons = RightCons>
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<typename First, typename Second>
struct result_;
template<typename Second>
struct result_<right_view, Second>
{
typedef segmented_view<right_view, RightCons> type;
};
template<typename Second>
struct result_<left_view, Second>
{
typedef segmented_view<left_view, LeftCons> type;
};
template<typename Second>
struct result_<full_view, Second>
{
typedef Second type;
};
template<typename Sig>
struct result;
template<typename This, typename First, typename Second>
struct result<This(First, Second)>
: result_<
typename remove_cv<typename remove_reference<First>::type>::type
, typename remove_cv<typename remove_reference<Second>::type>::type
>
{};
template<typename Second>
segmented_view<right_view, RightCons> operator ()(right_view, Second &second) const
{
return segmented_view<right_view, RightCons>(this->right_cons);
}
template<typename Second>
segmented_view<left_view, LeftCons> operator ()(left_view, Second &second) const
{
return segmented_view<left_view, LeftCons>(this->left_cons);
}
template<typename Second>
Second &operator ()(full_view, Second &second) const
{
return second;
}
private:
RightCons const &right_cons;
LeftCons const &left_cons;
};
} // namespace detail
namespace extension
{
////////////////////////////////////////////////////////////////////////////
template<typename Tag>
struct is_segmented_impl<detail::segmented_view_tag<Tag> >
{
template<typename Sequence>
struct apply
: mpl::true_
{};
};
////////////////////////////////////////////////////////////////////////////
template<>
struct segments_impl<detail::segmented_view_tag<detail::right_view> >
{
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<segmented_range>::type size;
typedef typename mpl::prior<size>::type size_minus_1;
typedef detail::segments_transform<Cdr> tfx;
typedef joint_view<
single_view<detail::right_view> const
, multiple_view<size_minus_1, detail::full_view> const
> mask;
typedef transform_view<mask const, segmented_range const, tfx> type;
static type call(Sequence &seq)
{
return type(
mask(
make_single_view(detail::right_view())
, make_multiple_view<size_minus_1>(detail::full_view())
)
, seq.cons.car
, tfx(seq.cons.cdr)
);
}
};
template<typename Sequence>
struct apply<Sequence, nil>
{
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<sequence_type>::type end;
typedef iterator_range<begin, end> range;
typedef single_view<range> type;
static type call(Sequence &seq)
{
return type(range(seq.cons.car.where_, fusion::end(seq.cons.car.sequence)));
}
};
};
////////////////////////////////////////////////////////////////////////////
template<>
struct segments_impl<detail::segmented_view_tag<detail::left_view> >
{
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<sequence_type>::type
, typename result_of::next<iterator_type>::type
> segmented_range;
typedef detail::segments_transform<Cdr> tfx;
typedef typename result_of::size<segmented_range>::type size;
typedef typename mpl::prior<size>::type size_minus_1;
typedef joint_view<
multiple_view<size_minus_1, detail::full_view> const
, single_view<detail::left_view> const
> mask;
typedef transform_view<mask const, segmented_range const, tfx> type;
static type call(Sequence &seq)
{
return type(
mask(
make_multiple_view<size_minus_1>(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<typename Sequence>
struct apply<Sequence, nil>
{
typedef typename Sequence::cons_type::car_type segmented_range;
typedef typename segmented_range::sequence_non_ref_type sequence_type;
typedef typename result_of::begin<sequence_type>::type begin;
typedef typename segmented_range::iterator_type end;
typedef iterator_range<begin, end> range;
typedef single_view<range> type;
static type call(Sequence &seq)
{
return type(range(fusion::begin(seq.cons.car.sequence), seq.cons.car.where_));
}
};
};
////////////////////////////////////////////////////////////////////////////
template<>
struct segments_impl<detail::segmented_view_tag<detail::center_view> >
{
template<typename Sequence>
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<left_segmented_range>::type
, typename result_of::next<typename result_of::begin<right_segmented_range>::type>::type
> segmented_range;
typedef typename mpl::minus<
typename result_of::size<segmented_range>::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<size_minus_2, detail::full_view> const
, single_view<detail::left_view> const
> left_mask;
typedef joint_view<
single_view<detail::right_view> const
, left_mask const
> mask;
typedef transform_view<mask const, segmented_range const, tfx> type;
static type call(Sequence &seq)
{
left_mask lmask(
make_multiple_view<size_minus_2>(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<typename First, typename Last>
struct iterator_range;
template<typename First, typename Last>
struct iterator_range<segmented_iterator<First>, segmented_iterator<Last> >
: sequence_base<iterator_range<segmented_iterator<First>, segmented_iterator<Last> > >
{
typedef typename convert_iterator<segmented_iterator<First> >::type begin_type;
typedef typename convert_iterator<segmented_iterator<Last> >::type end_type;
typedef typename detail::reverse_cons<First>::type begin_cons_type;
typedef typename detail::reverse_cons<Last>::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<begin_type>::type category;
typedef typename result_of::distance<begin_type, end_type>::type size;
typedef mpl::true_ is_view;
iterator_range(segmented_iterator<First> const& first_, segmented_iterator<Last> const& last_)
: first(convert_iterator<segmented_iterator<First> >::call(first_))
, last(convert_iterator<segmented_iterator<Last> >::call(last_))
, first_cons(detail::reverse_cons<First>::call(first_.cons()))
, last_cons(detail::reverse_cons<Last>::call(last_.cons()))
{}
begin_type first;
end_type last;
begin_cons_type first_cons;
end_cons_type last_cons;
};
namespace detail
{
template<typename Cons1, typename Cons2>
struct same_segment
: mpl::false_
{};
template<typename Car1, typename Cdr1, typename Car2, typename Cdr2>
struct same_segment<cons<Car1, Cdr1>, cons<Car2, Cdr2> >
: mpl::and_<
traits::is_segmented<Car1>
, is_same<Car1, Car2>
>
{};
////////////////////////////////////////////////////////////////////////////
template<typename Cons1, typename Cons2>
struct segments_gen;
////////////////////////////////////////////////////////////////////////////
template<typename Cons1, typename Cons2, bool SameSegment>
struct segments_gen2
{
typedef segments_gen<typename Cons1::cdr_type, typename Cons2::cdr_type> gen;
typedef typename gen::type type;
static type call(Cons1 const &cons1, Cons2 const &cons2)
{
return gen::call(cons1.cdr, cons2.cdr);
}
};
template<typename Cons1, typename Cons2>
struct segments_gen2<Cons1, Cons2, false>
{
typedef segmented_view<center_view, Cons1, Cons2> view;
typedef typename result_of::segments<view>::type type;
static type call(Cons1 const &cons1, Cons2 const &cons2)
{
view v(cons1, cons2);
return fusion::segments(v);
}
};
template<typename Car1, typename Car2>
struct segments_gen2<cons<Car1>, cons<Car2>, false>
{
typedef iterator_range<
typename Car1::iterator_type
, typename Car2::iterator_type
> range;
typedef single_view<range> type;
static type call(cons<Car1> const &cons1, cons<Car2> const &cons2)
{
return type(range(cons1.car.where_, cons2.car.where_));
}
};
////////////////////////////////////////////////////////////////////////////
template<typename Cons1, typename Cons2>
struct segments_gen
: segments_gen2<Cons1, Cons2, same_segment<Cons1, Cons2>::value>
{};
template<typename Car, typename Cdr>
struct segments_gen<cons<Car, Cdr>, nil>
{
typedef segmented_view<right_view, cons<Car, Cdr> > view;
typedef typename result_of::segments<view>::type type;
static type call(cons<Car, Cdr> const &cons, nil const &)
{
view v(cons);
return fusion::segments(v);
}
};
template<>
struct segments_gen<nil, nil>
{
typedef nil type;
static type call(nil const &, nil const &)
{
return nil();
}
};
} // namespace detail
namespace extension
{
template<typename Tag>
struct is_segmented_impl;
// An iterator_range of segmented_iterators is segmented
template<>
struct is_segmented_impl<iterator_range_tag>
{
template<typename Iterator>
struct is_segmented_iterator : mpl::false_ {};
template<typename Cons>
struct is_segmented_iterator<segmented_iterator<Cons> > : mpl::true_ {};
template<typename Sequence>
struct apply
: mpl::and_<
is_segmented_iterator<typename Sequence::begin_type>
, is_segmented_iterator<typename Sequence::end_type>
>
{};
};
template<typename Sequence>
struct segments_impl;
template<>
struct segments_impl<iterator_range_tag>
{
template<typename Sequence>
struct apply
{
typedef typename Sequence::begin_cons_type begin_cons;
typedef typename Sequence::end_cons_type end_cons;
typedef detail::segments_gen<begin_cons, end_cons> gen;
typedef typename gen::type type;
static type call(Sequence &sequence)
{
return gen::call(sequence.first_cons, sequence.last_cons);
}
};
};
}
}}
#endif