diff --git a/include/boost/container/experimental/segmented_search_n.hpp b/include/boost/container/experimental/segmented_search_n.hpp index 2d5ecde..15b5a9c 100644 --- a/include/boost/container/experimental/segmented_search_n.hpp +++ b/include/boost/container/experimental/segmented_search_n.hpp @@ -32,17 +32,221 @@ FwdIt segmented_search_n namespace detail_algo { +template +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::difference_type difference_type; + + const difference_type len = last - first; + const difference_type dcount = static_cast(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 +typename algo_enable_if_c< + !Tag::value || is_sentinel::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 +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 seg_traits; + typedef typename iterator_traits::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(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 +typename algo_enable_if_c::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 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 +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 outer_traits; + typedef segmented_iterator_traits 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::is_segmented_iterator sub_is_seg_t; + typedef typename iterator_traits::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 +template 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 traits; typedef typename traits::segment_iterator segment_iterator; typedef typename traits::local_iterator local_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; + typedef typename iterator_traits::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 -typename algo_enable_if_c< - !Tag::value || is_sentinel::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 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 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::iterator_category()); } } // namespace container