diff --git a/experimental/segmented_copy_if_test.cpp b/experimental/segmented_copy_if_test.cpp index bea6b36..7dea631 100644 --- a/experimental/segmented_copy_if_test.cpp +++ b/experimental/segmented_copy_if_test.cpp @@ -159,6 +159,98 @@ void test_copy_if_seg2() BOOST_TEST_EQ(out[3], 8); } +void test_copy_if_segmented_output() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + test_detail::seg_vector out; + out.add_segment(3, 0); + out.add_segment(2, 0); + + typedef test_detail::seg_vector::iterator iter_t; + iter_t result = segmented_copy_if(sv.begin(), sv.end(), out.begin(), is_even()); + + std::size_t count = 0; + iter_t it = out.begin(); + for(; it != result; ++it) + ++count; + BOOST_TEST_EQ(count, 4u); + + it = out.begin(); + BOOST_TEST_EQ(*it, 2); ++it; + BOOST_TEST_EQ(*it, 4); ++it; + BOOST_TEST_EQ(*it, 6); ++it; + BOOST_TEST_EQ(*it, 8); +} + +void test_copy_if_seg2_to_seg2() +{ + test_detail::seg2_vector sv2; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv2.add_flat_segment_range(a1, a1 + 3); + sv2.add_flat_segment_range(a2, a2 + 2); + sv2.add_flat_segment_range(a3, a3 + 4); + + test_detail::seg2_vector out; + { + test_detail::seg_vector s1; s1.add_segment(3, 0); + test_detail::seg_vector s2; s2.add_segment(2, 0); + out.add_segment(s1); + out.add_segment(s2); + } + + typedef test_detail::seg2_vector::iterator iter_t; + iter_t result = segmented_copy_if(sv2.begin(), sv2.end(), out.begin(), is_even()); + + std::size_t count = 0; + iter_t it = out.begin(); + for(; it != result; ++it) + ++count; + BOOST_TEST_EQ(count, 4u); + + it = out.begin(); + BOOST_TEST_EQ(*it, 2); ++it; + BOOST_TEST_EQ(*it, 4); ++it; + BOOST_TEST_EQ(*it, 6); ++it; + BOOST_TEST_EQ(*it, 8); +} + +void test_copy_if_seg_to_seg_misaligned() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3, 4, 5}; + int a2[] = {6, 7, 8}; + sv.add_segment_range(a1, a1 + 5); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector out; + out.add_segment(2, 0); + out.add_segment(3, 0); + + typedef test_detail::seg_vector::iterator iter_t; + iter_t result = segmented_copy_if(sv.begin(), sv.end(), out.begin(), is_even()); + + std::size_t count = 0; + iter_t it = out.begin(); + for(; it != result; ++it) + ++count; + BOOST_TEST_EQ(count, 4u); + + it = out.begin(); + BOOST_TEST_EQ(*it, 2); ++it; + BOOST_TEST_EQ(*it, 4); ++it; + BOOST_TEST_EQ(*it, 6); ++it; + BOOST_TEST_EQ(*it, 8); +} + int main() { test_copy_if_full_range(); @@ -169,5 +261,8 @@ int main() test_copy_if_sentinel_segmented(); test_copy_if_sentinel_non_segmented(); test_copy_if_seg2(); + test_copy_if_segmented_output(); + test_copy_if_seg2_to_seg2(); + test_copy_if_seg_to_seg_misaligned(); return boost::report_errors(); } diff --git a/experimental/segmented_copy_n_test.cpp b/experimental/segmented_copy_n_test.cpp index a113ae7..b5962ab 100644 --- a/experimental/segmented_copy_n_test.cpp +++ b/experimental/segmented_copy_n_test.cpp @@ -112,6 +112,107 @@ void test_copy_n_seg2() BOOST_TEST_EQ(out[static_cast(i)], i + 1); } +void test_copy_n_segmented_output() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + test_detail::seg_vector out; + out.add_segment(4, 0); + out.add_segment(3, 0); + out.add_segment(2, 0); + + typedef test_detail::seg_vector::iterator iter_t; + iter_t result = segmented_copy_n(sv.begin(), 9, out.begin()); + + BOOST_TEST(result == out.end()); + iter_t it = out.begin(); + for(int i = 0; i < 9; ++i, ++it) + BOOST_TEST_EQ(*it, i + 1); +} + +void test_copy_n_seg2_to_seg2() +{ + test_detail::seg2_vector sv2; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv2.add_flat_segment_range(a1, a1 + 3); + sv2.add_flat_segment_range(a2, a2 + 2); + sv2.add_flat_segment_range(a3, a3 + 4); + + test_detail::seg2_vector out; + { + test_detail::seg_vector s1; s1.add_segment(5, 0); + test_detail::seg_vector s2; s2.add_segment(4, 0); + out.add_segment(s1); + out.add_segment(s2); + } + + typedef test_detail::seg2_vector::iterator iter_t; + iter_t result = segmented_copy_n(sv2.begin(), 9, out.begin()); + + BOOST_TEST(result == out.end()); + iter_t it = out.begin(); + for(int i = 0; i < 9; ++i, ++it) + BOOST_TEST_EQ(*it, i + 1); +} + +void test_copy_n_seg_to_seg_misaligned() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3, 4, 5}; + int a2[] = {6, 7, 8}; + sv.add_segment_range(a1, a1 + 5); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector out; + out.add_segment(2, 0); + out.add_segment(3, 0); + out.add_segment(3, 0); + + typedef test_detail::seg_vector::iterator iter_t; + iter_t result = segmented_copy_n(sv.begin(), 8, out.begin()); + + BOOST_TEST(result == out.end()); + iter_t it = out.begin(); + for(int i = 0; i < 8; ++i, ++it) + BOOST_TEST_EQ(*it, i + 1); +} + +void test_copy_n_partial_segmented_output() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + test_detail::seg_vector out; + out.add_segment(3, 0); + out.add_segment(3, 0); + + typedef test_detail::seg_vector::iterator iter_t; + iter_t result = segmented_copy_n(sv.begin(), 5, out.begin()); + + std::size_t count = 0; + iter_t it = out.begin(); + for(; it != result; ++it) + ++count; + BOOST_TEST_EQ(count, 5u); + + it = out.begin(); + for(int i = 0; i < 5; ++i, ++it) + BOOST_TEST_EQ(*it, i + 1); +} + int main() { test_copy_n_full(); @@ -120,5 +221,9 @@ int main() test_copy_n_single_segment(); test_copy_n_non_segmented(); test_copy_n_seg2(); + test_copy_n_segmented_output(); + test_copy_n_seg2_to_seg2(); + test_copy_n_seg_to_seg_misaligned(); + test_copy_n_partial_segmented_output(); return boost::report_errors(); } diff --git a/experimental/segmented_mismatch_test.cpp b/experimental/segmented_mismatch_test.cpp index 2c7d692..a9693a1 100644 --- a/experimental/segmented_mismatch_test.cpp +++ b/experimental/segmented_mismatch_test.cpp @@ -232,6 +232,132 @@ void test_mismatch_every_position_seg2() BOOST_TEST(r.first == sv2.end()); } +void test_mismatch_seg_to_seg() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + test_detail::seg_vector sv2; + int b1[] = {1, 2, 3, 4}; + int b2[] = {5, 6, 7, 8}; + int b3[] = {9}; + sv2.add_segment_range(b1, b1 + 4); + sv2.add_segment_range(b2, b2 + 4); + sv2.add_segment_range(b3, b3 + 1); + + typedef test_detail::seg_vector::iterator iter_t; + std::pair r = segmented_mismatch(sv.begin(), sv.end(), sv2.begin()); + BOOST_TEST(r.first == sv.end()); +} + +void test_mismatch_seg_to_seg_mismatch() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + test_detail::seg_vector sv2; + int b1[] = {1, 2, 3, 4}; + int b2[] = {5, 6, 99, 8}; + int b3[] = {9}; + sv2.add_segment_range(b1, b1 + 4); + sv2.add_segment_range(b2, b2 + 4); + sv2.add_segment_range(b3, b3 + 1); + + typedef test_detail::seg_vector::iterator iter_t; + std::pair r = segmented_mismatch(sv.begin(), sv.end(), sv2.begin()); + BOOST_TEST(r.first != sv.end()); + BOOST_TEST_EQ(*r.first, 7); + BOOST_TEST_EQ(*r.second, 99); +} + +void test_mismatch_seg2_to_seg2() +{ + test_detail::seg2_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5}; + int a3[] = {6, 7, 8, 9}; + sv.add_flat_segment_range(a1, a1 + 3); + sv.add_flat_segment_range(a2, a2 + 2); + sv.add_flat_segment_range(a3, a3 + 4); + + test_detail::seg2_vector sv2; + int b1[] = {1, 2, 3, 4, 5}; + int b2[] = {6, 7, 8, 9}; + sv2.add_flat_segment_range(b1, b1 + 5); + sv2.add_flat_segment_range(b2, b2 + 4); + + typedef test_detail::seg2_vector::iterator iter_t; + std::pair r = segmented_mismatch(sv.begin(), sv.end(), sv2.begin()); + BOOST_TEST(r.first == sv.end()); +} + +void test_mismatch_seg_to_seg_misaligned() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3, 4, 5}; + int a2[] = {6, 7, 8}; + sv.add_segment_range(a1, a1 + 5); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector sv2; + int b1[] = {1, 2}; + int b2[] = {3, 4, 5}; + int b3[] = {6, 7, 8}; + sv2.add_segment_range(b1, b1 + 2); + sv2.add_segment_range(b2, b2 + 3); + sv2.add_segment_range(b3, b3 + 3); + + typedef test_detail::seg_vector::iterator iter_t; + std::pair r = segmented_mismatch(sv.begin(), sv.end(), sv2.begin()); + BOOST_TEST(r.first == sv.end()); +} + +void test_mismatch_seg_to_seg_every_position() +{ + test_detail::seg_vector sv; + int a1[] = {10, 20, 30}; + int a2[] = {40, 50}; + int a3[] = {60, 70, 80, 90}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 2); + sv.add_segment_range(a3, a3 + 4); + + int vals[] = {10, 20, 30, 40, 50, 60, 70, 80, 90}; + const int N = 9; + typedef test_detail::seg_vector::iterator iter_t; + + for(int pos = 0; pos < N; ++pos) { + test_detail::seg_vector sv2; + int ref[9]; + for(int j = 0; j < N; ++j) ref[j] = vals[j]; + ref[pos] = -1; + int r1[] = {ref[0], ref[1], ref[2], ref[3]}; + int r2[] = {ref[4], ref[5], ref[6], ref[7]}; + int r3[] = {ref[8]}; + sv2.add_segment_range(r1, r1 + 4); + sv2.add_segment_range(r2, r2 + 4); + sv2.add_segment_range(r3, r3 + 1); + + iter_t expected = sv.begin(); + for(int j = 0; j < pos; ++j) ++expected; + + std::pair r = segmented_mismatch(sv.begin(), sv.end(), sv2.begin()); + BOOST_TEST(r.first == expected); + BOOST_TEST_EQ(*r.first, vals[pos]); + BOOST_TEST_EQ(*r.second, -1); + } +} + int main() { test_mismatch_matching(); @@ -245,5 +371,10 @@ int main() test_mismatch_seg2(); test_mismatch_every_position(); test_mismatch_every_position_seg2(); + test_mismatch_seg_to_seg(); + test_mismatch_seg_to_seg_mismatch(); + test_mismatch_seg2_to_seg2(); + test_mismatch_seg_to_seg_misaligned(); + test_mismatch_seg_to_seg_every_position(); return boost::report_errors(); } diff --git a/include/boost/container/experimental/segmented_copy_if.hpp b/include/boost/container/experimental/segmented_copy_if.hpp index 77cf3fe..8870a36 100644 --- a/include/boost/container/experimental/segmented_copy_if.hpp +++ b/include/boost/container/experimental/segmented_copy_if.hpp @@ -31,88 +31,211 @@ OutIter segmented_copy_if(InIter first, Sent last, OutIter result, Pred pred); namespace detail_algo { +////////////////////////////////////////////////////////////////////////////// +// Bounded destination helper: copies matching elements from source into +// [dst_first, dst_last), stopping when source is exhausted or destination +// is full. Advances first_out (by reference) so the caller knows how far +// we got. Recursively walks destination segments when dst is segmented. +// +// When dst_last is unreachable_sentinel_t the destination-full check +// is optimised away, giving the same code as an unbounded loop. +////////////////////////////////////////////////////////////////////////////// + #if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) -template -OutIter segmented_copy_if_dispatch - (RAIter first, RAIter last, OutIter result, Pred pred, const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) +template +DstIter segmented_copy_if_dst_bounded + (RASrcIter& first_out, RASrcIter last, DstIter dst_first, DstSent dst_last, Pred pred, + const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) { - typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::difference_type difference_type; + RASrcIter first = first_out; + difference_type n = last - first; while(n >= difference_type(4)) { - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } ++first; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; n -= 4; } switch(n) { case 3: - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } - break; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + BOOST_FALLTHROUGH; case 2: - if(pred(*first)) { *result = *first; ++result; } ++first; - if(pred(*first)) { *result = *first; ++result; } - break; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + BOOST_FALLTHROUGH; case 1: - if(pred(*first)) { *result = *first; ++result; } - break; + if(pred(*first)) { if(dst_first == dst_last) goto out_path; *dst_first = *first; ++dst_first; } ++first; + BOOST_FALLTHROUGH; default: break; } - return result; + out_path: + first_out = first; + return dst_first; } #endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING -template -typename algo_enable_if_c< - !Tag::value || is_sentinel::value, OutIter>::type -segmented_copy_if_dispatch - (InIter first, Sent last, OutIter result, Pred pred, Tag, Cat) +template +typename algo_enable_if_c::type +segmented_copy_if_dst_bounded + (SrcIter& first_out, Sent last, DstIter dst_first, DstSent dst_last, Pred pred, DstTag, SrcCat) { - for(; first != last; ++first) + SrcIter first = first_out; + + for(; first != last; ++first) { if(pred(*first)) { - *result = *first; - ++result; + if(dst_first == dst_last) + goto out_path; + *dst_first = *first; + ++dst_first; } - return result; + } + out_path: + first_out = first; + return dst_first; +} + +template +SegDstIter segmented_copy_if_dst_bounded + (SrcIter& first, Sent last, SegDstIter dst_first, SegDstIter dst_last, Pred pred, + segmented_iterator_tag, SrcCat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + dst_segment_iterator sfirst = dst_traits::segment(dst_first); + const dst_segment_iterator slast = dst_traits::segment(dst_last); + + if(sfirst == slast) { + dst_local_iterator r = (segmented_copy_if_dst_bounded) + (first, last, dst_traits::local(dst_first), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, r); + } + else { + dst_local_iterator dst_local = (segmented_copy_if_dst_bounded) + (first, last, dst_traits::local(dst_first), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); + if(first == last) + return dst_traits::compose(sfirst, dst_local); + + for(++sfirst; sfirst != slast; ++sfirst) { + dst_local = (segmented_copy_if_dst_bounded) + (first, last, dst_traits::begin(sfirst), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); + if(first == last) + return dst_traits::compose(sfirst, dst_local); + } + + dst_local = (segmented_copy_if_dst_bounded) + (first, last, dst_traits::begin(slast), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, dst_local); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Destination dispatch: routes to bounded helper. +// Non-segmented destination: single unbounded call (unreachable_sentinel_t). +// Segmented destination: loop over destination segments, bounded per segment. +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE DstIter segmented_copy_if_dst_dispatch + (SrcIter first, Sent last, DstIter result, Pred pred, + const non_segmented_iterator_tag &, Cat) +{ + return (segmented_copy_if_dst_bounded) + (first, last, result, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat()); +} + +template +SegDstIter segmented_copy_if_dst_dispatch + (SrcIter first, Sent last, SegDstIter result, Pred pred, + const segmented_iterator_tag &, Cat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + if(first == last) + return result; + + dst_segment_iterator dst_seg = dst_traits::segment(result); + dst_local_iterator dst_local = dst_traits::local(result); + + while(first != last) { + dst_local_iterator dst_end = dst_traits::end(dst_seg); + dst_local = (segmented_copy_if_dst_bounded) + (first, last, dst_local, dst_end, pred, dst_is_local_seg_t(), Cat()); + if(first != last) { + ++dst_seg; + dst_local = dst_traits::begin(dst_seg); + } + } + return dst_traits::compose(dst_seg, dst_local); +} + +////////////////////////////////////////////////////////////////////////////// +// Source dispatch: walks the source (read pointer) segments +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE +typename algo_enable_if_c< + !Tag::value || is_sentinel::value, OutIter>::type + segmented_copy_if_dispatch(SrcIter first, Sent last, OutIter result, Pred pred, Tag, Cat) +{ +#if !defined(BOOST_CONTAINER_DISABLE_SEGMENTED_OUTPUT) + typedef segmented_iterator_traits dst_traits; + return (segmented_copy_if_dst_dispatch) + (first, last, result, pred, typename dst_traits::is_segmented_iterator(), Cat()); +#else + return (segmented_copy_if_dst_dispatch) + (first, last, result, pred, non_segmented_iterator_tag(), Cat()); +#endif } template OutIter segmented_copy_if_dispatch (SegIter first, SegIter last, OutIter result, Pred pred, segmented_iterator_tag, Cat) { - typedef segmented_iterator_traits traits; - typedef typename traits::local_iterator local_iterator; - typedef typename traits::segment_iterator segment_iterator; - typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; - typedef typename iterator_traits::iterator_category local_cat_t; + typedef segmented_iterator_traits src_traits; + typedef typename src_traits::local_iterator src_local_iterator; + typedef typename src_traits::segment_iterator src_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator src_is_local_seg_t; + typedef typename iterator_traits::iterator_category src_local_cat_t; - segment_iterator sfirst = traits::segment(first); - segment_iterator slast = traits::segment(last); + src_segment_iterator sfirst = src_traits::segment(first); + const src_segment_iterator slast = src_traits::segment(last); if(sfirst == slast) { - return (segmented_copy_if_dispatch)(traits::local(first), traits::local(last), result, pred, is_local_seg_t(), local_cat_t()); + return (segmented_copy_if_dispatch) + (src_traits::local(first), src_traits::local(last), result, pred, src_is_local_seg_t(), src_local_cat_t()); } else { - result = (segmented_copy_if_dispatch)(traits::local(first), traits::end(sfirst), result, pred, is_local_seg_t(), local_cat_t()); + result = (segmented_copy_if_dispatch) + (src_traits::local(first), src_traits::end(sfirst), result, pred, src_is_local_seg_t(), src_local_cat_t()); for(++sfirst; sfirst != slast; ++sfirst) - result = (segmented_copy_if_dispatch)(traits::begin(sfirst), traits::end(sfirst), result, pred, is_local_seg_t(), local_cat_t()); + result = (segmented_copy_if_dispatch) + (src_traits::begin(sfirst), src_traits::end(sfirst), result, pred, src_is_local_seg_t(), src_local_cat_t()); - return (segmented_copy_if_dispatch)(traits::begin(sfirst), traits::local(last), result, pred, is_local_seg_t(), local_cat_t()); + return (segmented_copy_if_dispatch) + (src_traits::begin(slast), src_traits::local(last), result, pred, src_is_local_seg_t(), src_local_cat_t()); } } } // namespace detail_algo //! Copies elements satisfying \c pred from [first, last) to the range -//! beginning at \c result. Segmentation is exploited on the input range. +//! beginning at \c result. Segmentation is exploited on both input and +//! output ranges. template BOOST_CONTAINER_FORCEINLINE OutIter segmented_copy_if(InIter first, Sent last, OutIter result, Pred pred) diff --git a/include/boost/container/experimental/segmented_copy_n.hpp b/include/boost/container/experimental/segmented_copy_n.hpp index c748343..c9c49be 100644 --- a/include/boost/container/experimental/segmented_copy_n.hpp +++ b/include/boost/container/experimental/segmented_copy_n.hpp @@ -32,6 +32,156 @@ OutIter segmented_copy_n(InIter first, Size count, OutIter result); namespace detail_algo { +////////////////////////////////////////////////////////////////////////////// +// Bounded destination helper: copies from source count elements into +// [dst_first, dst_last), stopping when count reaches zero or destination +// is full. Advances first_out and count (by reference) so the caller +// knows how far we got. +// Recursively walks destination segments when dst is segmented. +// +// When dst_last is unreachable_sentinel_t the destination-full check +// is optimised away, giving the same code as an unbounded loop. +////////////////////////////////////////////////////////////////////////////// + +#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) + +template +DstIter segmented_copy_n_dst_bounded + (RASrcIter& first_out, Size& count, DstIter dst_first, DstSent dst_last, + const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) +{ + RASrcIter first = first_out; + + while(count >= Size(4)) { + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + } + + switch(count) { + case 3: + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + BOOST_FALLTHROUGH; + case 2: + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + BOOST_FALLTHROUGH; + case 1: + if(dst_first == dst_last) goto out_path; *dst_first = *first; ++first; ++dst_first; --count; + BOOST_FALLTHROUGH; + default: + break; + } + out_path: + first_out = first; + return dst_first; +} + +#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING + +template +typename algo_enable_if_c::type +segmented_copy_n_dst_bounded + (SrcIter& first_out, Size& count, DstIter dst_first, DstSent dst_last, DstTag, SrcCat) +{ + SrcIter first = first_out; + + for(; count > 0; ++first, --count) { + if(dst_first == dst_last) + goto out_path; + *dst_first = *first; + ++dst_first; + } + out_path: + first_out = first; + return dst_first; +} + +template +SegDstIter segmented_copy_n_dst_bounded + (SrcIter& first, Size& count, SegDstIter dst_first, SegDstIter dst_last, + segmented_iterator_tag, SrcCat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + dst_segment_iterator sfirst = dst_traits::segment(dst_first); + const dst_segment_iterator slast = dst_traits::segment(dst_last); + + if(sfirst == slast) { + dst_local_iterator r = (segmented_copy_n_dst_bounded) + (first, count, dst_traits::local(dst_first), dst_traits::local(dst_last), dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, r); + } + else { + dst_local_iterator dst_local = (segmented_copy_n_dst_bounded) + (first, count, dst_traits::local(dst_first), dst_traits::end(sfirst), dst_is_local_seg_t(), SrcCat()); + if(count == 0) + return dst_traits::compose(sfirst, dst_local); + + for(++sfirst; sfirst != slast; ++sfirst) { + dst_local = (segmented_copy_n_dst_bounded) + (first, count, dst_traits::begin(sfirst), dst_traits::end(sfirst), dst_is_local_seg_t(), SrcCat()); + if(count == 0) + return dst_traits::compose(sfirst, dst_local); + } + + dst_local = (segmented_copy_n_dst_bounded) + (first, count, dst_traits::begin(slast), dst_traits::local(dst_last), dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, dst_local); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Destination dispatch: routes to bounded helper. +// Non-segmented destination: single unbounded call (unreachable_sentinel_t). +// Segmented destination: loop over destination segments, bounded per segment. +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE DstIter segmented_copy_n_dst_dispatch + (SrcIter first, Size& count, DstIter result, + const non_segmented_iterator_tag &, Cat) +{ + return (segmented_copy_n_dst_bounded) + (first, count, result, unreachable_sentinel_t(), non_segmented_iterator_tag(), Cat()); +} + +template +SegDstIter segmented_copy_n_dst_dispatch + (SrcIter first, Size& count, SegDstIter result, + const segmented_iterator_tag &, Cat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + if(count <= 0) + return result; + + dst_segment_iterator dst_seg = dst_traits::segment(result); + dst_local_iterator dst_local = dst_traits::local(result); + + while(count > 0) { + dst_local_iterator dst_end = dst_traits::end(dst_seg); + dst_local = (segmented_copy_n_dst_bounded) + (first, count, dst_local, dst_end, dst_is_local_seg_t(), Cat()); + if(count > 0) { + ++dst_seg; + dst_local = dst_traits::begin(dst_seg); + } + } + return dst_traits::compose(dst_seg, dst_local); +} + +////////////////////////////////////////////////////////////////////////////// +// copy_n_scan: scans through source segments, clipping to both segment +// boundaries and count, then delegates to the destination dispatch layer. +////////////////////////////////////////////////////////////////////////////// + template BOOST_CONTAINER_FORCEINLINE OutIter copy_n_scan_non_segmented @@ -95,6 +245,10 @@ OutIter copy_n_scan(SegIt first, SegIt last, Size& count, OutIter result, segmen } } +////////////////////////////////////////////////////////////////////////////// +// Source dispatch: walks the source (read pointer) segments +////////////////////////////////////////////////////////////////////////////// + template OutIter segmented_copy_n_dispatch (SegIter first, Size count, OutIter result, segmented_iterator_tag, Cat) @@ -123,34 +277,17 @@ OutIter segmented_copy_n_dispatch #if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) template -OutIter segmented_copy_n_dispatch +BOOST_CONTAINER_FORCEINLINE OutIter segmented_copy_n_dispatch (RAIter first, Size count, OutIter result, non_segmented_iterator_tag, const std::random_access_iterator_tag &) { - while(count >= Size(4)) { - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - count -= Size(4); - } - - switch(count) { - case 3: - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - break; - case 2: - *result = *first; ++first; ++result; - *result = *first; ++first; ++result; - break; - case 1: - *result = *first; ++first; ++result; - break; - default: - break; - } - return result; +#if !defined(BOOST_CONTAINER_DISABLE_SEGMENTED_OUTPUT) + typedef segmented_iterator_traits dst_traits; + return (segmented_copy_n_dst_dispatch) + (first, count, result, typename dst_traits::is_segmented_iterator(), std::random_access_iterator_tag()); +#else + return (segmented_copy_n_dst_dispatch) + (first, count, result, non_segmented_iterator_tag(), std::random_access_iterator_tag()); +#endif } #endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING @@ -159,15 +296,21 @@ template OutIter segmented_copy_n_dispatch (InIter first, Size count, OutIter result, non_segmented_iterator_tag, Cat) { - for(; count > 0; ++first, ++result, --count) - *result = *first; - return result; +#if !defined(BOOST_CONTAINER_DISABLE_SEGMENTED_OUTPUT) + typedef segmented_iterator_traits dst_traits; + return (segmented_copy_n_dst_dispatch) + (first, count, result, typename dst_traits::is_segmented_iterator(), Cat()); +#else + return (segmented_copy_n_dst_dispatch) + (first, count, result, non_segmented_iterator_tag(), Cat()); +#endif } } // namespace detail_algo //! Copies \c count elements from the range beginning at \c first to -//! the range beginning at \c result. Exploits segmentation on input. +//! the range beginning at \c result. Exploits segmentation on both +//! input and output. template BOOST_CONTAINER_FORCEINLINE OutIter segmented_copy_n(InIter first, Size count, OutIter result) diff --git a/include/boost/container/experimental/segmented_mismatch.hpp b/include/boost/container/experimental/segmented_mismatch.hpp index 7b404d2..979d124 100644 --- a/include/boost/container/experimental/segmented_mismatch.hpp +++ b/include/boost/container/experimental/segmented_mismatch.hpp @@ -41,86 +41,228 @@ struct mismatch_equal BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const U& b) const { return a == b; } }; +////////////////////////////////////////////////////////////////////////////// +// Bounded iter2 helper: compares source [first1, last1) against +// [iter2_first, iter2_last), stopping when source, iter2, or a mismatch +// is encountered. +// Advances first1_out (by reference) so the caller knows how far we got. +// Advances iter2_first (by reference) for the same reason. +// Recursively walks iter2 segments when iter2 is segmented. +// +// Returns true if no mismatch was found in the bounded region +// (i.e. stopped because first1==last1 or first2==iter2_last). +// Returns false if a mismatch was found. +// +// When iter2_last is unreachable_sentinel_t the segment-boundary check +// is optimised away, giving the same code as an unbounded loop. +////////////////////////////////////////////////////////////////////////////// + #if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) -template -std::pair segmented_mismatch_dispatch - (RAIter1 first1, RAIter1 last1, RAIter2 first2, BinaryPred pred, const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) +template +bool segmented_mismatch_iter2_bounded + (RASrcIter &first1_out, RASrcIter last1, Iter2 &iter2_first, Iter2Sent iter2_last, BinaryPred pred, + const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) { - typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::difference_type difference_type; + RASrcIter first1 = first1_out; + Iter2 first2 = iter2_first; difference_type n = last1 - first1; + while(n >= difference_type(4)) { - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; n -= 4; } switch(n) { case 3: - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - break; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + BOOST_FALLTHROUGH; case 2: - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - break; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + BOOST_FALLTHROUGH; case 1: - if(!pred(*first1, *first2)) - goto final_result; - ++first1; ++first2; - break; + if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto mismatch_path; ++first1; ++first2; + BOOST_FALLTHROUGH; default: break; } - final_result: - return std::pair(first1, first2); + out_path: + first1_out = first1; + iter2_first = first2; + return true; + + mismatch_path: + first1_out = first1; + iter2_first = first2; + return false; } #endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING -template -typename algo_enable_if_c - < !Tag::value || is_sentinel::value - , std::pair - >::type -segmented_mismatch_dispatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred, Tag, Cat) +template +typename algo_enable_if_c::type +segmented_mismatch_iter2_bounded + (SrcIter &first1_out, Sent last1, Iter2 &iter2_first, Iter2Sent iter2_last, BinaryPred pred, Iter2Tag, SrcCat) { - while (first1 != last1 && pred(*first1, *first2)) { - ++first1, ++first2; - } + SrcIter first1 = first1_out; + Iter2 first2 = iter2_first; - return std::pair(first1, first2); + for(; first1 != last1; ++first1) { + if(first2 == iter2_last) + goto out_path; + if(!pred(*first1, *first2)) { + first1_out = first1; + iter2_first = first2; + return false; + } + ++first2; + } + out_path: + first1_out = first1; + iter2_first = first2; + return true; +} + +template +bool segmented_mismatch_iter2_bounded + (SrcIter &first1, Sent last1, SegIter2 &iter2_first_out, SegIter2 iter2_last, BinaryPred pred, + segmented_iterator_tag, SrcCat) +{ + typedef segmented_iterator_traits iter2_traits; + typedef typename iter2_traits::local_iterator iter2_local_iterator; + typedef typename iter2_traits::segment_iterator iter2_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator iter2_is_local_seg_t; + + iter2_segment_iterator sfirst = iter2_traits::segment(iter2_first_out); + const iter2_segment_iterator slast = iter2_traits::segment(iter2_last); + + if(sfirst == slast) { + iter2_local_iterator loc2 = iter2_traits::local(iter2_first_out); + bool r = (segmented_mismatch_iter2_bounded) + (first1, last1, loc2, iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat()); + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return r; + } + else { + iter2_local_iterator loc2 = iter2_traits::local(iter2_first_out); + if(!(segmented_mismatch_iter2_bounded) + (first1, last1, loc2, iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat())) { + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return false; + } + if(first1 == last1) { + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return true; + } + + for(++sfirst; sfirst != slast; ++sfirst) { + loc2 = iter2_traits::begin(sfirst); + if(!(segmented_mismatch_iter2_bounded) + (first1, last1, loc2, iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat())) { + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return false; + } + if(first1 == last1) { + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return true; + } + } + + loc2 = iter2_traits::begin(slast); + bool r = (segmented_mismatch_iter2_bounded) + (first1, last1, loc2, iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat()); + iter2_first_out = iter2_traits::compose(sfirst, loc2); + return r; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Iter2 dispatch: routes to bounded helper. +// Non-segmented iter2: single unbounded call (unreachable_sentinel_t). +// Segmented iter2: loop over iter2 segments, bounded per segment. +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE bool segmented_mismatch_iter2_dispatch + (SrcIter &first1, Sent last1, InpIter2 &first2, BinaryPred pred, + const non_segmented_iterator_tag &, Cat) +{ + return (segmented_mismatch_iter2_bounded) + (first1, last1, first2, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat()); +} + +template +bool segmented_mismatch_iter2_dispatch + (SrcIter &first1, Sent last1, SegIter2 &first2_out, BinaryPred pred, + const segmented_iterator_tag &, Cat) +{ + typedef segmented_iterator_traits iter2_traits; + typedef typename iter2_traits::local_iterator iter2_local_iterator; + typedef typename iter2_traits::segment_iterator iter2_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator iter2_is_local_seg_t; + + if(first1 == last1) + return true; + + iter2_segment_iterator seg2 = iter2_traits::segment(first2_out); + iter2_local_iterator loc2 = iter2_traits::local(first2_out); + + while(first1 != last1) { + iter2_local_iterator end2 = iter2_traits::end(seg2); + if(!(segmented_mismatch_iter2_bounded) + (first1, last1, loc2, end2, pred, iter2_is_local_seg_t(), Cat())) { + first2_out = iter2_traits::compose(seg2, loc2); + return false; + } + if(first1 != last1) { + ++seg2; + loc2 = iter2_traits::begin(seg2); + } + } + first2_out = iter2_traits::compose(seg2, loc2); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// Source dispatch: walks the source (first1) segments. +// Returns std::pair. +// Internally uses the iter2 dispatch which returns bool and updates first2 +// by reference. The source dispatch reconstructs the composed first1 +// position when a mismatch is found. +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE +typename algo_enable_if_c + < !Tag::value || is_sentinel::value + , std::pair + >::type +segmented_mismatch_dispatch(SrcIter first1, Sent last1, InpIter2 first2, BinaryPred pred, Tag, Cat) +{ +#if !defined(BOOST_CONTAINER_DISABLE_SEGMENTED_OUTPUT) + typedef segmented_iterator_traits iter2_traits; + bool ok = (segmented_mismatch_iter2_dispatch) + (first1, last1, first2, pred, typename iter2_traits::is_segmented_iterator(), Cat()); +#else + bool ok = (segmented_mismatch_iter2_dispatch) + (first1, last1, first2, pred, non_segmented_iterator_tag(), Cat()); +#endif + (void)ok; + return std::pair(first1, first2); } template std::pair segmented_mismatch_dispatch (SegIter first1, SegIter last1, InpIter2 first2, BinaryPred pred, segmented_iterator_tag, Cat) { - typedef segmented_iterator_traits traits; - typedef typename traits::local_iterator local_iterator; - typedef typename traits::segment_iterator segment_iterator; + typedef segmented_iterator_traits traits; + typedef typename traits::local_iterator local_iterator; + typedef typename traits::segment_iterator segment_iterator; typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; typedef typename iterator_traits::iterator_category local_cat_t; @@ -136,13 +278,11 @@ std::pair segmented_mismatch_dispatch return return_t((r.first != ll) ? traits::compose(sfirst, r.first) : last1, r.second); } else { - // First segment local_iterator le = traits::end(sfirst); local_return_t r = (segmented_mismatch_dispatch)(traits::local(first1), le, first2, pred, is_local_seg_t(), local_cat_t()); if (r.first != le) return return_t(traits::compose(sfirst, r.first), r.second); - // Middle segments for (++sfirst; sfirst != slast; ++sfirst) { le = traits::end(sfirst); r = (segmented_mismatch_dispatch)(traits::begin(sfirst), le, r.second, pred, is_local_seg_t(), local_cat_t()); @@ -150,7 +290,6 @@ std::pair segmented_mismatch_dispatch return return_t(traits::compose(sfirst, r.first), r.second); } - // Last segment le = traits::local(last1); r = (segmented_mismatch_dispatch)(traits::begin(slast), le, r.second, pred, is_local_seg_t(), local_cat_t()); return return_t((r.first != le) ? traits::compose(sfirst, r.first) : last1, r.second); @@ -162,6 +301,7 @@ std::pair segmented_mismatch_dispatch //! Returns a pair of iterators to the first elements where //! \c pred(*it1, *it2) is false in [first1, last1) and the range //! starting at \c first2, or {last1, first2 + N} if all match. +//! Exploits segmentation on both ranges. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred) @@ -174,6 +314,7 @@ segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred //! Returns a pair of iterators to the first mismatching elements //! in [first1, last1) and the range starting at \c first2, or //! {last1, first2 + N} if all elements match. +//! Exploits segmentation on both ranges. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2)