mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 15:10:45 +02:00
Add bidirectional iterator support
This commit is contained in:
@@ -32,8 +32,12 @@ FwdIt segmented_partition(FwdIt first, Sent last, Pred pred);
|
||||
|
||||
namespace detail_algo {
|
||||
|
||||
template <class FwdIt, class OutIter, class Pred>
|
||||
OutIter partition_scan(FwdIt first, FwdIt last, OutIter result, Pred pred, non_segmented_iterator_tag)
|
||||
//////////////////////////////////////////////
|
||||
// Forward (Lomuto-style) partition
|
||||
//////////////////////////////////////////////
|
||||
|
||||
template <class FwdIt, class Sent, class OutIter, class Pred>
|
||||
OutIter partition_scan(FwdIt first, Sent last, OutIter result, Pred pred, non_segmented_iterator_tag, const std::forward_iterator_tag &)
|
||||
{
|
||||
for(; first != last; ++first) {
|
||||
if(pred(*first)) {
|
||||
@@ -45,7 +49,7 @@ OutIter partition_scan(FwdIt first, FwdIt last, OutIter result, Pred pred, non_s
|
||||
}
|
||||
|
||||
template <class SegIt, class OutIter, class Pred>
|
||||
OutIter partition_scan(SegIt first, SegIt last, OutIter result, Pred pred, segmented_iterator_tag)
|
||||
OutIter partition_scan(SegIt first, SegIt last, OutIter result, Pred pred, segmented_iterator_tag, const std::forward_iterator_tag &)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIt> traits;
|
||||
typedef typename traits::local_iterator local_iterator;
|
||||
@@ -69,40 +73,140 @@ OutIter partition_scan(SegIt first, SegIt last, OutIter result, Pred pred, segme
|
||||
}
|
||||
}
|
||||
|
||||
template <class SegIter, class Pred>
|
||||
BOOST_CONTAINER_FORCEINLINE SegIter segmented_partition_dispatch
|
||||
(SegIter first, SegIter last, Pred pred, segmented_iterator_tag)
|
||||
//////////////////////////////////////////////
|
||||
// Bidirectional (Hoare-style) partition
|
||||
//////////////////////////////////////////////
|
||||
|
||||
template <class BidirIt, class Pred>
|
||||
BidirIt partition_scan(BidirIt first, BidirIt last, Pred pred, non_segmented_iterator_tag, const std::bidirectional_iterator_tag&)
|
||||
{
|
||||
return partition_scan(first, last, first, pred, segmented_iterator_tag());
|
||||
while(true) {
|
||||
while(first != last && pred(*first))
|
||||
++first;
|
||||
if(first == last)
|
||||
return first;
|
||||
--last;
|
||||
while(first != last && !pred(*last))
|
||||
--last;
|
||||
if(first == last)
|
||||
return first;
|
||||
boost::adl_move_swap(*first, *last);
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
template <class SegIt, class Pred>
|
||||
SegIt partition_scan(SegIt first, SegIt last, Pred pred, segmented_iterator_tag, const std::bidirectional_iterator_tag& cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIt> traits;
|
||||
typedef typename traits::local_iterator local_iterator;
|
||||
typedef typename traits::segment_iterator segment_iterator;
|
||||
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
|
||||
|
||||
if(first == last) return first;
|
||||
|
||||
segment_iterator sf = traits::segment(first);
|
||||
segment_iterator sl = traits::segment(last);
|
||||
|
||||
if(sf == sl) {
|
||||
local_iterator r = partition_scan(traits::local(first), traits::local(last), pred, is_local_seg_t(), cat);
|
||||
return traits::compose(sf, r);
|
||||
}
|
||||
|
||||
local_iterator f_loc = traits::local(first);
|
||||
local_iterator f_end = traits::end(sf);
|
||||
local_iterator l_loc = traits::local(last);
|
||||
local_iterator l_beg = traits::begin(sl);
|
||||
|
||||
for(;;) {
|
||||
// Phase 1: advance front to find element NOT satisfying pred
|
||||
while(f_loc != f_end && pred(*f_loc))
|
||||
++f_loc;
|
||||
|
||||
if(f_loc == f_end) {
|
||||
++sf;
|
||||
if(sf == sl) {
|
||||
local_iterator r = partition_scan(l_beg, l_loc, pred, is_local_seg_t(), cat);
|
||||
return traits::compose(sf, r);
|
||||
}
|
||||
f_loc = traits::begin(sf);
|
||||
f_end = traits::end(sf);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Phase 2: retreat back to find element satisfying pred
|
||||
for(;;) {
|
||||
if(l_loc == l_beg) {
|
||||
--sl;
|
||||
if(sf == sl) {
|
||||
local_iterator r = partition_scan(f_loc, f_end, pred, is_local_seg_t(), cat);
|
||||
return traits::compose(sf, r);
|
||||
}
|
||||
l_beg = traits::begin(sl);
|
||||
l_loc = traits::end(sl);
|
||||
}
|
||||
--l_loc;
|
||||
if(pred(*l_loc)) break;
|
||||
}
|
||||
|
||||
boost::adl_move_swap(*f_loc, *l_loc);
|
||||
++f_loc;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Top-level dispatch
|
||||
//////////////////////////////////////////////
|
||||
|
||||
template <class FwdIt, class Sent, class Pred, class Tag>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
FwdIt segmented_partition_dispatch(FwdIt first, Sent last, Pred pred, Tag tag, const std::bidirectional_iterator_tag& cat)
|
||||
{
|
||||
return (partition_scan)(first, last, pred, tag, cat);
|
||||
}
|
||||
|
||||
template <class FwdIt, class Sent, class Pred, class Tag>
|
||||
typename algo_enable_if_c<
|
||||
!Tag::value || is_sentinel<Sent, FwdIt>::value, FwdIt>::type
|
||||
segmented_partition_dispatch(FwdIt first, Sent last, Pred pred, Tag)
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
FwdIt segmented_partition_dispatch(FwdIt first, Sent last, Pred pred, Tag tag, const std::forward_iterator_tag &cat)
|
||||
{
|
||||
FwdIt result = first;
|
||||
for(; first != last; ++first) {
|
||||
if(pred(*first)) {
|
||||
boost::adl_move_swap(*result, *first);
|
||||
++result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return (partition_scan)(first, last, first, pred, tag, cat);
|
||||
}
|
||||
|
||||
template<class It, class Sent, class Seg, class Tag>
|
||||
struct sent_filter
|
||||
{
|
||||
typedef std::forward_iterator_tag cat_t;
|
||||
typedef non_segmented_iterator_tag seg_t;
|
||||
};
|
||||
|
||||
template<class It, class Seg, class Tag>
|
||||
struct sent_filter<It, It, Seg, Tag>
|
||||
{
|
||||
typedef Tag cat_t;
|
||||
typedef Seg seg_t;
|
||||
};
|
||||
|
||||
} // namespace detail_algo
|
||||
|
||||
//! Reorders elements in [first, last) so that elements satisfying
|
||||
//! \c pred come before those that do not (Lomuto-style partition).
|
||||
//! \c pred come before those that do not.
|
||||
//! For forward iterators, uses a Lomuto-style scan.
|
||||
//! For bidirectional (or stronger) iterators, uses a Hoare-style
|
||||
//! partition that swaps from both ends, reducing the number of swaps.
|
||||
//! Returns an iterator to the partition point.
|
||||
template <class FwdIt, class Sent, class Pred>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
FwdIt segmented_partition(FwdIt first, Sent last, Pred pred)
|
||||
{
|
||||
typedef segmented_iterator_traits<FwdIt> traits;
|
||||
typedef typename boost::container::iterator_traits<FwdIt>::iterator_category cat_t;
|
||||
typedef typename traits::is_segmented_iterator seg_t;
|
||||
|
||||
typedef detail_algo::sent_filter<FwdIt, Sent, seg_t, cat_t> sent_filter_t;
|
||||
return detail_algo::segmented_partition_dispatch
|
||||
(first, last, pred, typename traits::is_segmented_iterator());
|
||||
( first, last, pred
|
||||
, typename sent_filter_t::seg_t()
|
||||
, typename sent_filter_t::cat_t());
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
|
||||
Reference in New Issue
Block a user