mirror of
https://github.com/boostorg/container.git
synced 2026-08-04 03:04:13 +02:00
Manualy inline and optimize algorithms using the cleanup_blocks strategy.
This commit is contained in:
@@ -58,7 +58,7 @@ segmented_copy_if_dst_bounded
|
|||||||
//element. With an unreachable_sentinel_t destination both checks fold away,
|
//element. With an unreachable_sentinel_t destination both checks fold away,
|
||||||
//so the flat path is unchanged.
|
//so the flat path is unchanged.
|
||||||
if(BOOST_UNLIKELY(dst_first == dst_last))
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
return segduo<SrcIter, DstIter>(first, dst_first);
|
goto out_path;
|
||||||
|
|
||||||
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
for(; first != last; ++first) {
|
for(; first != last; ++first) {
|
||||||
@@ -75,46 +75,58 @@ segmented_copy_if_dst_bounded
|
|||||||
return segduo<SrcIter, DstIter>(first, dst_first);
|
return segduo<SrcIter, DstIter>(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t BlockSize, class RASrcIter, class RADstIter,
|
|
||||||
class Pred, class Diff>
|
|
||||||
BOOST_CONTAINER_FORCEINLINE segtrio<RASrcIter, RADstIter, Diff>
|
|
||||||
copy_if_cleanup_blocks
|
|
||||||
(RASrcIter cur, RADstIter dst_cur, RADstIter dst_last,
|
|
||||||
Pred pred, Diff avail)
|
|
||||||
{
|
|
||||||
const Diff block_size = static_cast<Diff>(BlockSize);
|
|
||||||
while(avail >= block_size &&
|
|
||||||
static_cast<Diff>(dst_last - dst_cur) >= block_size) {
|
|
||||||
avail -= block_size;
|
|
||||||
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
|
||||||
for(Diff chunk = block_size; chunk; ) {
|
|
||||||
--chunk;
|
|
||||||
if(pred(*cur)) {
|
|
||||||
*dst_cur = *cur;
|
|
||||||
++dst_cur;
|
|
||||||
}
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return segtrio<RASrcIter, RADstIter, Diff>(cur, dst_cur, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class RASrcIter, class RADstIter, class Pred>
|
template <class RASrcIter, class RADstIter, class Pred>
|
||||||
BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag
|
BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag
|
||||||
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
||||||
segmented_copy_if_dst_bounded
|
segmented_copy_if_dst_bounded
|
||||||
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, Pred pred,
|
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, Pred pred,
|
||||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag)
|
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
|
||||||
{
|
{
|
||||||
|
//[alg.copy] same dest-after-write contract as the generic leaf. Dest capacity
|
||||||
|
//is tested only after a write, so a miss scan never touches the destination
|
||||||
|
//bound. The old blocked helper rechecked (dst_last - dst) every 32 source
|
||||||
|
//elements even when nothing was written.
|
||||||
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
||||||
|
typedef segduo<RASrcIter, RADstIter> result_t;
|
||||||
|
const difference_type block_size = 16;
|
||||||
|
difference_type n = last - first;
|
||||||
|
|
||||||
(void)src_tag;
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
segtrio<RASrcIter, RADstIter, difference_type> r =
|
goto out_ret;
|
||||||
(copy_if_cleanup_blocks<32>)
|
|
||||||
(first, dst_first, dst_last, pred, last - first);
|
|
||||||
|
|
||||||
return (segmented_copy_if_dst_bounded)
|
// Avoid destination check if both input and output ranges are big enough
|
||||||
(r.first, last, r.second, dst_last, pred, non_segmented_iterator_tag(), int());
|
while(n >= block_size &&
|
||||||
|
static_cast<difference_type>(dst_last - dst_first) >= block_size) {
|
||||||
|
n -= block_size;
|
||||||
|
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
||||||
|
for(difference_type chunk = block_size; chunk; ) {
|
||||||
|
--chunk;
|
||||||
|
if(pred(*first)) {
|
||||||
|
*dst_first = *first;
|
||||||
|
++dst_first;
|
||||||
|
}
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loop 1 may exhaust the destination exactly; do not write past the end.
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
|
goto out_ret;
|
||||||
|
|
||||||
|
// Remaining elements
|
||||||
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
|
for(; n; --n, ++first) {
|
||||||
|
if(pred(*first)) {
|
||||||
|
*dst_first = *first;
|
||||||
|
++dst_first;
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last)) {
|
||||||
|
++first;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ret:
|
||||||
|
return result_t(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class SrcIter, class Sent, class SegDstIter, class Pred, class SrcCat>
|
template <class SrcIter, class Sent, class SegDstIter, class Pred, class SrcCat>
|
||||||
|
|||||||
@@ -68,46 +68,6 @@ BOOST_CONTAINER_FORCEINLINE bool partition_copy_room_enough
|
|||||||
(TIter, unreachable_sentinel_t, FIter, unreachable_sentinel_t, Diff avail)
|
(TIter, unreachable_sentinel_t, FIter, unreachable_sentinel_t, Diff avail)
|
||||||
{ return avail >= static_cast<Diff>(BlockSize); }
|
{ return avail >= static_cast<Diff>(BlockSize); }
|
||||||
|
|
||||||
template <std::size_t BlockSize, class RASrcIter, class TIter, class TSent,
|
|
||||||
class FIter, class FSent, class Pred, class Diff>
|
|
||||||
BOOST_CONTAINER_FORCEINLINE segquartet<RASrcIter, TIter, FIter, Diff>
|
|
||||||
partition_copy_cleanup_blocks
|
|
||||||
(RASrcIter cur, TIter t_first, TSent t_last, FIter f_first, FSent f_last,
|
|
||||||
Pred pred, Diff avail, dtl::true_type)
|
|
||||||
{
|
|
||||||
const Diff block_size = static_cast<Diff>(BlockSize);
|
|
||||||
while((partition_copy_room_enough<BlockSize>)
|
|
||||||
(t_first, t_last, f_first, f_last, avail)) {
|
|
||||||
avail -= block_size;
|
|
||||||
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
|
||||||
for(Diff chunk = block_size; chunk; ) {
|
|
||||||
--chunk;
|
|
||||||
if(pred(*cur)) {
|
|
||||||
*t_first = *cur;
|
|
||||||
++t_first;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*f_first = *cur;
|
|
||||||
++f_first;
|
|
||||||
}
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return segquartet<RASrcIter, TIter, FIter, Diff>
|
|
||||||
(cur, t_first, f_first, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t BlockSize, class RASrcIter, class TIter, class TSent,
|
|
||||||
class FIter, class FSent, class Pred, class Diff>
|
|
||||||
BOOST_CONTAINER_FORCEINLINE segquartet<RASrcIter, TIter, FIter, Diff>
|
|
||||||
partition_copy_cleanup_blocks
|
|
||||||
(RASrcIter cur, TIter t_first, TSent, FIter f_first, FSent, Pred, Diff avail,
|
|
||||||
dtl::false_type)
|
|
||||||
{
|
|
||||||
return segquartet<RASrcIter, TIter, FIter, Diff>
|
|
||||||
(cur, t_first, f_first, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class It>
|
template <class It>
|
||||||
struct pc_output_is_ra
|
struct pc_output_is_ra
|
||||||
{
|
{
|
||||||
@@ -140,10 +100,12 @@ partition_copy_leaf
|
|||||||
// untested element, and the loop body can take for granted that both outputs
|
// untested element, and the loop body can take for granted that both outputs
|
||||||
// have room. With unreachable_sentinel_t outputs the tests fold away, so the
|
// have room. With unreachable_sentinel_t outputs the tests fold away, so the
|
||||||
// flat path is unchanged.
|
// flat path is unchanged.
|
||||||
|
typedef segquartet<SrcIter, TIter, FIter, bool> result_t;
|
||||||
|
|
||||||
if(BOOST_UNLIKELY(t_first == t_last))
|
if(BOOST_UNLIKELY(t_first == t_last))
|
||||||
return segquartet<SrcIter, TIter, FIter, bool>(first, t_first, f_first, false);
|
return result_t(first, t_first, f_first, false);
|
||||||
if(BOOST_UNLIKELY(f_first == f_last))
|
if(BOOST_UNLIKELY(f_first == f_last))
|
||||||
return segquartet<SrcIter, TIter, FIter, bool>(first, t_first, f_first, first != last);
|
return result_t(first, t_first, f_first, first != last);
|
||||||
|
|
||||||
bool false_output_full = false;
|
bool false_output_full = false;
|
||||||
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
@@ -166,15 +128,13 @@ partition_copy_leaf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return segquartet<SrcIter, TIter, FIter, bool>
|
return result_t(first, t_first, f_first, false_output_full);
|
||||||
(first, t_first, f_first, false_output_full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Random-access-source fast path (needs random-access outputs too). Process
|
// Random-access-source fast path (needs random-access outputs too).
|
||||||
// fixed 32-element source blocks while both outputs have room for the worst
|
// Three loops: both outputs have room for a full block; source-only blocks
|
||||||
// case (all 32 elements routed to either output), use 8-element cleanup blocks
|
// with per-write checks; residual. An unbounded output folds its capacity
|
||||||
// when an output is bounded, then finish with the generic checked loop. An
|
// tests away via unreachable_sentinel_t.
|
||||||
// unbounded output reports the available source count as its room.
|
|
||||||
template <class RASrcIter, class TIter, class TSent, class FIter, class FSent, class Pred>
|
template <class RASrcIter, class TIter, class TSent, class FIter, class FSent, class Pred>
|
||||||
BOOST_CONTAINER_FORCEINLINE
|
BOOST_CONTAINER_FORCEINLINE
|
||||||
typename algo_enable_if_c
|
typename algo_enable_if_c
|
||||||
@@ -185,24 +145,66 @@ partition_copy_leaf
|
|||||||
Pred pred, const std::random_access_iterator_tag &)
|
Pred pred, const std::random_access_iterator_tag &)
|
||||||
{
|
{
|
||||||
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
||||||
typedef segquartet<RASrcIter, TIter, FIter, difference_type> cleanup_result;
|
typedef segquartet<RASrcIter, TIter, FIter, bool> result_t;
|
||||||
|
const difference_type block_size = 16;
|
||||||
|
difference_type n = last - first;
|
||||||
|
bool false_output_full = false;
|
||||||
|
|
||||||
const cleanup_result r32 = (partition_copy_cleanup_blocks<32>)
|
if(BOOST_UNLIKELY(t_first == t_last))
|
||||||
(first, t_first, t_last, f_first, f_last, pred, last - first,
|
return result_t(first, t_first, f_first, false);
|
||||||
dtl::true_type());
|
if(BOOST_UNLIKELY(f_first == f_last))
|
||||||
|
return result_t(first, t_first, f_first, first != last);
|
||||||
|
|
||||||
typedef dtl::integral_constant
|
//Avoid output checks if source and both outputs are big enough
|
||||||
< bool
|
while((partition_copy_room_enough<16>)
|
||||||
, !dtl::is_same<TSent, unreachable_sentinel_t>::value ||
|
(t_first, t_last, f_first, f_last, n)) {
|
||||||
!dtl::is_same<FSent, unreachable_sentinel_t>::value
|
n -= block_size;
|
||||||
> has_bounded_output_t;
|
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
||||||
const cleanup_result r8 = (partition_copy_cleanup_blocks<8>)
|
for(difference_type chunk = block_size; chunk; ) {
|
||||||
(r32.first, r32.second, t_last, r32.third, f_last, pred, r32.fourth,
|
--chunk;
|
||||||
has_bounded_output_t());
|
if(pred(*first)) {
|
||||||
|
*t_first = *first;
|
||||||
|
++t_first;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*f_first = *first;
|
||||||
|
++f_first;
|
||||||
|
}
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (partition_copy_leaf)
|
//Loop 1 may exhaust an output exactly; do not write past the end.
|
||||||
(r8.first, last, r8.second, t_last, r8.third, f_last, pred,
|
if(BOOST_UNLIKELY(t_first == t_last))
|
||||||
int());
|
goto out_ret;
|
||||||
|
if(BOOST_UNLIKELY(f_first == f_last)) {
|
||||||
|
false_output_full = first != last;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remaining elements
|
||||||
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
|
for(; n; --n, ++first) {
|
||||||
|
if(pred(*first)) {
|
||||||
|
*t_first = *first;
|
||||||
|
++t_first;
|
||||||
|
if(BOOST_UNLIKELY(t_first == t_last)) {
|
||||||
|
++first;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*f_first = *first;
|
||||||
|
++f_first;
|
||||||
|
if(BOOST_UNLIKELY(f_first == f_last)) {
|
||||||
|
++first;
|
||||||
|
false_output_full = first != last;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ret:
|
||||||
|
return result_t(first, t_first, f_first, false_output_full);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -64,46 +64,55 @@ segmented_remove_copy_dst_bounded
|
|||||||
return segduo<SrcIter, DstIter>(first, dst_first);
|
return segduo<SrcIter, DstIter>(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t BlockSize, bool Move, class RASrcIter, class RADstIter,
|
|
||||||
class T, class Diff>
|
|
||||||
BOOST_CONTAINER_FORCEINLINE segtrio<RASrcIter, RADstIter, Diff>
|
|
||||||
remove_copy_cleanup_blocks
|
|
||||||
(RASrcIter cur, RADstIter dst_cur, RADstIter dst_last,
|
|
||||||
const T &value, Diff avail)
|
|
||||||
{
|
|
||||||
const Diff block_size = static_cast<Diff>(BlockSize);
|
|
||||||
while(avail >= block_size &&
|
|
||||||
static_cast<Diff>(dst_last - dst_cur) >= block_size) {
|
|
||||||
avail -= block_size;
|
|
||||||
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
|
||||||
for(Diff chunk = block_size; chunk; ) {
|
|
||||||
--chunk;
|
|
||||||
if(!(*cur == value)) {
|
|
||||||
transfer_op<Move>::apply(*dst_cur, *cur);
|
|
||||||
++dst_cur;
|
|
||||||
}
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return segtrio<RASrcIter, RADstIter, Diff>(cur, dst_cur, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool Move, class RASrcIter, class RADstIter, class T>
|
template <bool Move, class RASrcIter, class RADstIter, class T>
|
||||||
BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag
|
BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag
|
||||||
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
||||||
segmented_remove_copy_dst_bounded
|
segmented_remove_copy_dst_bounded
|
||||||
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, const T& value,
|
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, const T& value,
|
||||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag)
|
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
|
||||||
{
|
{
|
||||||
|
//[alg.remove] same dest-after-write contract as the generic leaf.
|
||||||
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
||||||
|
typedef segduo<RASrcIter, RADstIter> result_t;
|
||||||
|
const difference_type block_size = 16;
|
||||||
|
difference_type n = last - first;
|
||||||
|
|
||||||
(void)src_tag;
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
segtrio<RASrcIter, RADstIter, difference_type> r =
|
goto out_ret;
|
||||||
(remove_copy_cleanup_blocks<32, Move>)
|
|
||||||
(first, dst_first, dst_last, value, last - first);
|
|
||||||
|
|
||||||
return (segmented_remove_copy_dst_bounded<Move>)
|
//Avoid destination check if both input and output ranges are big enough
|
||||||
(r.first, last, r.second, dst_last, value, non_segmented_iterator_tag(), int());
|
while(n >= block_size &&
|
||||||
|
static_cast<difference_type>(dst_last - dst_first) >= block_size) {
|
||||||
|
n -= block_size;
|
||||||
|
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
||||||
|
for(difference_type chunk = block_size; chunk; ) {
|
||||||
|
--chunk;
|
||||||
|
if(!(*first == value)) {
|
||||||
|
transfer_op<Move>::apply(*dst_first, *first);
|
||||||
|
++dst_first;
|
||||||
|
}
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loop 1 may exhaust the destination exactly; do not write past the end.
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
|
goto out_ret;
|
||||||
|
|
||||||
|
//Remaining elements
|
||||||
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
|
for(; n; --n, ++first) {
|
||||||
|
if(!(*first == value)) {
|
||||||
|
transfer_op<Move>::apply(*dst_first, *first);
|
||||||
|
++dst_first;
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last)) {
|
||||||
|
++first;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ret:
|
||||||
|
return result_t(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool Move, class SrcIter, class Sent, class SegDstIter, class T, class SrcCat>
|
template <bool Move, class SrcIter, class Sent, class SegDstIter, class T, class SrcCat>
|
||||||
|
|||||||
@@ -77,46 +77,55 @@ segmented_remove_copy_if_dst_bounded
|
|||||||
return segduo<SrcIter, DstIter>(first, dst_first);
|
return segduo<SrcIter, DstIter>(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t BlockSize, bool Move, class RASrcIter, class RADstIter,
|
|
||||||
class Pred, class Diff>
|
|
||||||
BOOST_CONTAINER_FORCEINLINE segtrio<RASrcIter, RADstIter, Diff>
|
|
||||||
remove_copy_if_cleanup_blocks
|
|
||||||
(RASrcIter cur, RADstIter dst_cur, RADstIter dst_last,
|
|
||||||
Pred pred, Diff avail)
|
|
||||||
{
|
|
||||||
const Diff block_size = static_cast<Diff>(BlockSize);
|
|
||||||
while(avail >= block_size &&
|
|
||||||
static_cast<Diff>(dst_last - dst_cur) >= block_size) {
|
|
||||||
avail -= block_size;
|
|
||||||
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
|
||||||
for(Diff chunk = block_size; chunk; ) {
|
|
||||||
--chunk;
|
|
||||||
if(!pred(*cur)) {
|
|
||||||
transfer_op<Move>::apply(*dst_cur, *cur);
|
|
||||||
++dst_cur;
|
|
||||||
}
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return segtrio<RASrcIter, RADstIter, Diff>(cur, dst_cur, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool Move, class RASrcIter, class RADstIter, class Pred>
|
template <bool Move, class RASrcIter, class RADstIter, class Pred>
|
||||||
typename iterator_enable_if_tag
|
BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag
|
||||||
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
<RADstIter, std::random_access_iterator_tag, segduo<RASrcIter, RADstIter> >::type
|
||||||
segmented_remove_copy_if_dst_bounded
|
segmented_remove_copy_if_dst_bounded
|
||||||
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, Pred pred,
|
(RASrcIter first, RASrcIter last, RADstIter dst_first, RADstIter dst_last, Pred pred,
|
||||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag)
|
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
|
||||||
{
|
{
|
||||||
|
//[alg.remove] same dest-after-write contract as the generic leaf.
|
||||||
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
||||||
|
typedef segduo<RASrcIter, RADstIter> result_t;
|
||||||
|
const difference_type block_size = 16;
|
||||||
|
difference_type n = last - first;
|
||||||
|
|
||||||
(void)src_tag;
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
segtrio<RASrcIter, RADstIter, difference_type> r =
|
goto out_ret;
|
||||||
(remove_copy_if_cleanup_blocks<32, Move>)
|
|
||||||
(first, dst_first, dst_last, pred, last - first);
|
|
||||||
|
|
||||||
return (segmented_remove_copy_if_dst_bounded<Move>)
|
//Avoid destination check if both input and output ranges are big enough
|
||||||
(r.first, last, r.second, dst_last, pred, non_segmented_iterator_tag(), int());
|
while(n >= block_size &&
|
||||||
|
static_cast<difference_type>(dst_last - dst_first) >= block_size) {
|
||||||
|
n -= block_size;
|
||||||
|
BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL
|
||||||
|
for(difference_type chunk = block_size; chunk; ) {
|
||||||
|
--chunk;
|
||||||
|
if(!pred(*first)) {
|
||||||
|
transfer_op<Move>::apply(*dst_first, *first);
|
||||||
|
++dst_first;
|
||||||
|
}
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loop 1 may exhaust the destination exactly; do not write past the end.
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last))
|
||||||
|
goto out_ret;
|
||||||
|
|
||||||
|
//Remaining elements
|
||||||
|
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||||
|
for(; n; --n, ++first) {
|
||||||
|
if(!pred(*first)) {
|
||||||
|
transfer_op<Move>::apply(*dst_first, *first);
|
||||||
|
++dst_first;
|
||||||
|
if(BOOST_UNLIKELY(dst_first == dst_last)) {
|
||||||
|
++first;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ret:
|
||||||
|
return result_t(first, dst_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool Move, class SrcIter, class Sent, class SegDstIter, class Pred, class SrcCat>
|
template <bool Move, class SrcIter, class Sent, class SegDstIter, class Pred, class SrcCat>
|
||||||
|
|||||||
Reference in New Issue
Block a user