mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 17:00:46 +02:00
Implemented first recursive search_n implementation. Add random-access iterator overloads
This commit is contained in:
@@ -32,17 +32,221 @@ FwdIt segmented_search_n
|
||||
|
||||
namespace detail_algo {
|
||||
|
||||
template <class RAIter, class Size, class T>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
RAIter segmented_search_n_dispatch
|
||||
(RAIter first, RAIter last, Size count, const T& value,
|
||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
|
||||
{
|
||||
typedef typename iterator_traits<RAIter>::difference_type difference_type;
|
||||
|
||||
const difference_type len = last - first;
|
||||
const difference_type dcount = static_cast<difference_type>(count);
|
||||
if (dcount > len)
|
||||
return last;
|
||||
|
||||
const RAIter scan_end = last - (dcount - 1);
|
||||
|
||||
for (; first < scan_end; ++first) {
|
||||
if (*first == value) {
|
||||
RAIter candidate = first;
|
||||
const RAIter run_end = first + dcount;
|
||||
++first;
|
||||
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||
for (; first != run_end; ++first) {
|
||||
if (!(*first == value))
|
||||
goto continue_scan;
|
||||
}
|
||||
return candidate;
|
||||
continue_scan:;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
template <class FwdIt, class Sent, class Size, class T, class Tag, class Cat>
|
||||
typename algo_enable_if_c<
|
||||
!Tag::value || is_sentinel<Sent, FwdIt>::value, FwdIt>::type
|
||||
segmented_search_n_dispatch
|
||||
(FwdIt first, Sent last, Size count, const T& value, Tag, Cat)
|
||||
{
|
||||
for(; first != last; ++first) {
|
||||
if(*first == value) {
|
||||
FwdIt candidate = first;
|
||||
Size matched = 1;
|
||||
++first;
|
||||
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
|
||||
for(; matched < count; ++matched, ++first) {
|
||||
if(first == last)
|
||||
return last;
|
||||
if(!(*first == value))
|
||||
goto continue_scan;
|
||||
}
|
||||
return candidate;
|
||||
continue_scan:;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
// Scans local range [lcur, lend) for search_n, updating cross-segment state.
|
||||
// Returns true if a run of 'count' consecutive matches has been completed.
|
||||
// On return, lcur is past the last element processed, consecutive/match_start
|
||||
// are updated to reflect any partial match at the segment tail.
|
||||
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter>
|
||||
bool search_n_scan_segment
|
||||
(LocalIter& lcur, LocalIter lend,
|
||||
Size& consecutive, Size count, const T& value,
|
||||
SegIter& match_start, SegmentIter scur,
|
||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter> seg_traits;
|
||||
typedef typename iterator_traits<LocalIter>::difference_type difference_type;
|
||||
|
||||
while(lcur != lend) {
|
||||
if(consecutive == 0) {
|
||||
// Use find to skip non-matching elements (benefits from RA/vectorization)
|
||||
lcur = (segmented_find_dispatch)(lcur, lend, value, non_segmented_iterator_tag(), src_tag);
|
||||
if(lcur == lend)
|
||||
return false;
|
||||
|
||||
match_start = seg_traits::compose(scur, lcur);
|
||||
consecutive = 1;
|
||||
if(consecutive == count)
|
||||
return true;
|
||||
++lcur;
|
||||
}
|
||||
else {
|
||||
// Verify consecutive matches; we know exactly how many to check
|
||||
const difference_type need = static_cast<difference_type>(count - consecutive);
|
||||
const difference_type avail = lend - lcur;
|
||||
const difference_type ncheck = need < avail ? need : avail;
|
||||
const LocalIter check_end = lcur + ncheck;
|
||||
|
||||
for(; lcur != check_end; ++lcur) {
|
||||
if(!(*lcur == value)) {
|
||||
consecutive = 0;
|
||||
++lcur;
|
||||
break;
|
||||
}
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter, class Tag, class Cat>
|
||||
typename algo_enable_if_c<!Tag::value, bool>::type
|
||||
search_n_scan_segment
|
||||
(LocalIter& lcur, LocalIter lend,
|
||||
Size& consecutive, Size count, const T& value,
|
||||
SegIter& match_start, SegmentIter scur, Tag, Cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter> seg_traits;
|
||||
|
||||
for(; lcur != lend; ++lcur) {
|
||||
if(*lcur == value) {
|
||||
if(consecutive == 0)
|
||||
match_start = seg_traits::compose(scur, lcur);
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
consecutive = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recursively segmented local iterators: decompose into sub-segments
|
||||
// so that the innermost (non-segmented) level gets RA optimization.
|
||||
// Uses lend as sentinel to detect whether local_match was set by inner calls
|
||||
// (a match position is always before lend).
|
||||
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter, class Cat>
|
||||
bool search_n_scan_segment
|
||||
(LocalIter& lcur, LocalIter lend,
|
||||
Size& consecutive, Size count, const T& value,
|
||||
SegIter& match_start, SegmentIter scur,
|
||||
segmented_iterator_tag, Cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter> outer_traits;
|
||||
typedef segmented_iterator_traits<LocalIter> local_traits;
|
||||
typedef typename local_traits::segment_iterator sub_seg_iter;
|
||||
typedef typename local_traits::local_iterator sub_local_iter;
|
||||
typedef typename segmented_iterator_traits<sub_local_iter>::is_segmented_iterator sub_is_seg_t;
|
||||
typedef typename iterator_traits<sub_local_iter>::iterator_category sub_cat_t;
|
||||
|
||||
sub_seg_iter sub_scur = local_traits::segment(lcur);
|
||||
sub_seg_iter sub_slast = local_traits::segment(lend);
|
||||
sub_local_iter sub_lcur = local_traits::local(lcur);
|
||||
|
||||
LocalIter local_match = lend;
|
||||
|
||||
if(sub_scur == sub_slast) {
|
||||
sub_local_iter sub_lend = local_traits::local(lend);
|
||||
if(search_n_scan_segment(sub_lcur, sub_lend, consecutive, count, value,
|
||||
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
|
||||
if(local_match != lend)
|
||||
match_start = outer_traits::compose(scur, local_match);
|
||||
lcur = lend;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
{
|
||||
sub_local_iter sub_lend = local_traits::end(sub_scur);
|
||||
if(search_n_scan_segment(sub_lcur, sub_lend, consecutive, count, value,
|
||||
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
|
||||
if(local_match != lend)
|
||||
match_start = outer_traits::compose(scur, local_match);
|
||||
lcur = lend;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(++sub_scur; sub_scur != sub_slast; ++sub_scur) {
|
||||
sub_lcur = local_traits::begin(sub_scur);
|
||||
sub_local_iter sub_le = local_traits::end(sub_scur);
|
||||
if(search_n_scan_segment(sub_lcur, sub_le, consecutive, count, value,
|
||||
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
|
||||
if(local_match != lend)
|
||||
match_start = outer_traits::compose(scur, local_match);
|
||||
lcur = lend;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
sub_lcur = local_traits::begin(sub_scur);
|
||||
sub_local_iter sub_ll = local_traits::local(lend);
|
||||
if(search_n_scan_segment(sub_lcur, sub_ll, consecutive, count, value,
|
||||
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
|
||||
if(local_match != lend)
|
||||
match_start = outer_traits::compose(scur, local_match);
|
||||
lcur = lend;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(local_match != lend)
|
||||
match_start = outer_traits::compose(scur, local_match);
|
||||
lcur = lend;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Non-recursive: must carry cross-segment state (consecutive count,
|
||||
// match_start) to track runs that span segment boundaries.
|
||||
template <class SegIter, class Size, class T>
|
||||
template <class SegIter, class Size, class T, class Cat>
|
||||
SegIter segmented_search_n_dispatch
|
||||
(SegIter first, SegIter last, Size count, const T& value, segmented_iterator_tag)
|
||||
(SegIter first, SegIter last, Size count, const T& value, segmented_iterator_tag, Cat)
|
||||
{
|
||||
if(count <= 0) return first;
|
||||
|
||||
typedef segmented_iterator_traits<SegIter> traits;
|
||||
typedef typename traits::segment_iterator segment_iterator;
|
||||
typedef typename traits::local_iterator local_iterator;
|
||||
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
|
||||
typedef typename iterator_traits<local_iterator>::iterator_category local_cat_t;
|
||||
|
||||
Size consecutive = 0;
|
||||
SegIter match_start = first;
|
||||
@@ -54,94 +258,30 @@ SegIter segmented_search_n_dispatch
|
||||
|
||||
if(scur == slast) {
|
||||
local_iterator lend = traits::local(last);
|
||||
for(; lcur != lend; ++lcur) {
|
||||
if(*lcur == value) {
|
||||
if(consecutive == 0)
|
||||
match_start = traits::compose(scur, lcur);
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return match_start;
|
||||
}
|
||||
else {
|
||||
consecutive = 0;
|
||||
}
|
||||
}
|
||||
if(search_n_scan_segment(lcur, lend, consecutive, count, value,
|
||||
match_start, scur, is_local_seg_t(), local_cat_t()))
|
||||
return match_start;
|
||||
}
|
||||
else {
|
||||
{
|
||||
local_iterator lend = traits::end(scur);
|
||||
for(; lcur != lend; ++lcur) {
|
||||
if(*lcur == value) {
|
||||
if(consecutive == 0)
|
||||
match_start = traits::compose(scur, lcur);
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return match_start;
|
||||
}
|
||||
else {
|
||||
consecutive = 0;
|
||||
}
|
||||
}
|
||||
if(search_n_scan_segment(lcur, lend, consecutive, count, value,
|
||||
match_start, scur, is_local_seg_t(), local_cat_t()))
|
||||
return match_start;
|
||||
}
|
||||
for(++scur; scur != slast; ++scur) {
|
||||
local_iterator lb = traits::begin(scur);
|
||||
lcur = traits::begin(scur);
|
||||
local_iterator le = traits::end(scur);
|
||||
for(lcur = lb; lcur != le; ++lcur) {
|
||||
if(*lcur == value) {
|
||||
if(consecutive == 0)
|
||||
match_start = traits::compose(scur, lcur);
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return match_start;
|
||||
}
|
||||
else {
|
||||
consecutive = 0;
|
||||
}
|
||||
}
|
||||
if(search_n_scan_segment(lcur, le, consecutive, count, value,
|
||||
match_start, scur, is_local_seg_t(), local_cat_t()))
|
||||
return match_start;
|
||||
}
|
||||
{
|
||||
local_iterator lb = traits::begin(scur);
|
||||
lcur = traits::begin(scur);
|
||||
local_iterator ll = traits::local(last);
|
||||
for(lcur = lb; lcur != ll; ++lcur) {
|
||||
if(*lcur == value) {
|
||||
if(consecutive == 0)
|
||||
match_start = traits::compose(scur, lcur);
|
||||
++consecutive;
|
||||
if(consecutive == count)
|
||||
return match_start;
|
||||
}
|
||||
else {
|
||||
consecutive = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
template <class FwdIt, class Sent, class Size, class T, class Tag>
|
||||
typename algo_enable_if_c<
|
||||
!Tag::value || is_sentinel<Sent, FwdIt>::value, FwdIt>::type
|
||||
segmented_search_n_dispatch
|
||||
(FwdIt first, Sent last, Size count, const T& value, Tag)
|
||||
{
|
||||
if(count <= 0)
|
||||
return first;
|
||||
|
||||
for(; first != last; ++first) {
|
||||
if(*first == value) {
|
||||
FwdIt candidate = first;
|
||||
Size matched = 1;
|
||||
FwdIt it = first;
|
||||
++it;
|
||||
for(; matched < count; ++matched, ++it) {
|
||||
if(it == last)
|
||||
return last;
|
||||
if(!(*it == value))
|
||||
break;
|
||||
}
|
||||
if(matched == count)
|
||||
return candidate;
|
||||
if(search_n_scan_segment(lcur, ll, consecutive, count, value,
|
||||
match_start, scur, is_local_seg_t(), local_cat_t()))
|
||||
return match_start;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
@@ -155,12 +295,15 @@ template <class FwdIt, class Sent, class Size, class T>
|
||||
inline FwdIt segmented_search_n
|
||||
(FwdIt first, Sent last, Size count, const T& value)
|
||||
{
|
||||
if(count == 1)
|
||||
if (BOOST_UNLIKELY(count <= 0))
|
||||
return first;
|
||||
else if(BOOST_UNLIKELY(count == 1))
|
||||
return (segmented_find)(first, last, value);
|
||||
|
||||
typedef segmented_iterator_traits<FwdIt> traits;
|
||||
return detail_algo::segmented_search_n_dispatch
|
||||
(first, last, count, value, typename traits::is_segmented_iterator());
|
||||
(first, last, count, value, typename traits::is_segmented_iterator(),
|
||||
typename iterator_traits<FwdIt>::iterator_category());
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
|
||||
Reference in New Issue
Block a user