diff --git a/experimental/bench_segmented_algos.cpp b/experimental/bench_segmented_algos.cpp index 6d5a354..4651ef9 100644 --- a/experimental/bench_segmented_algos.cpp +++ b/experimental/bench_segmented_algos.cpp @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -415,6 +418,32 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred) #endif +template +FwdIt find_last(FwdIt first, FwdIt last, const T& val) +{ + FwdIt result = last; + for (; first != last; ++first) + if (*first == val) result = first; + return result; +} + +template +FwdIt find_last_if(FwdIt first, FwdIt last, Pred pred) +{ + FwdIt result = last; + for (; first != last; ++first) + if (pred(*first)) result = first; + return result; +} + +template +FwdIt find_last_if_not(FwdIt first, FwdIt last, Pred pred) +{ + FwdIt result = last; + for (; first != last; ++first) + if (!pred(*first)) result = first; + return result; +} //Not benchmarked: @@ -425,7 +454,6 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred) //find_end //find_first_of //adjacent_find -//mismatch //copy_backward //move //move_backward @@ -498,10 +526,6 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred) //lexicographical_compare_three_way //range-based? -//find_last -//find_last_if -//find_last_if_not -// //contains //contains_subrange //starts_with @@ -917,6 +941,96 @@ void bench_find_if_not(C c, std::size_t iters, const char* cname, print_ratio(label, cname, r1, r2); } +template +void bench_find_last(C c, std::size_t iters, const char* cname, + const typename C::value_type& val, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t1.resume(); + typename C::iterator it = bench_detail::find_last(c.begin(), c.end(), val); + result = (it == c.end()) ? 0 : 1; + t1.stop(); + escape(&result); + } + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t2.resume(); + typename C::iterator it = bc::segmented_find_last(c.begin(), c.end(), val); + result = (it == c.end()) ? 0 : 1; + t2.stop(); + escape(&result); + } + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_find_last_if(C c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t1.resume(); + typename C::iterator it = bench_detail::find_last_if(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t1.stop(); + escape(&result); + } + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t2.resume(); + typename C::iterator it = bc::segmented_find_last_if(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t2.stop(); + escape(&result); + } + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_find_last_if_not(C c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t1.resume(); + typename C::iterator it = bench_detail::find_last_if_not(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t1.stop(); + escape(&result); + } + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + clobber(); + t2.resume(); + typename C::iterator it = bc::segmented_find_last_if_not(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t2.stop(); + escape(&result); + } + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + template void bench_equal(C c, C& c2, std::size_t iters, const char* cname, const char* label) @@ -1864,6 +1978,18 @@ void run_all(const C& c, std::size_t iters, const char* cname) bench_find_if_not(c, iters, cname, unequal_to_ref(VT(static_cast(c.size() / 2))), "find_if_not(hit)"); bench_find_if_not(c, iters, cname, is_zero_or_positive(), "find_if_not(miss)"); + //find_last + bench_find_last(c, iters, cname, VT(static_cast(c.size() / 2)), "find_last(hit)"); + bench_find_last(c, iters, cname, VT(-1), "find_last(miss)"); + + //find_last_if + bench_find_last_if(c, iters, cname, equal_to_ref(VT(static_cast(c.size() / 2))), "find_last_if(hit)"); + bench_find_last_if(c, iters, cname, is_negative(), "find_last_if(miss)"); + + //find_last_if_not + bench_find_last_if_not(c, iters, cname, unequal_to_ref(VT(static_cast(c.size() / 2))), "find_last_if_not(hit)"); + bench_find_last_if_not(c, iters, cname, is_zero_or_positive(), "find_last_if_not(miss)"); + //for_each bench_for_each(c, iters, cname); @@ -1915,9 +2041,7 @@ void run_all(const C& c, std::size_t iters, const char* cname) { C c2(c); bench_mismatch(c, c2, iters, cname, "mismatch(hit)"); - typename C::iterator last = c2.end(); - --last; - *last = VT(-1); + c2[c2.size()/2] = VT(-1); bench_mismatch(c, c2, iters, cname, "mismatch(miss)"); } diff --git a/experimental/segmented_find_last_if_not_test.cpp b/experimental/segmented_find_last_if_not_test.cpp new file mode 100644 index 0000000..af1d80e --- /dev/null +++ b/experimental/segmented_find_last_if_not_test.cpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "segmented_test_helper.hpp" +#include + +using namespace boost::container; + +struct is_positive +{ + bool operator()(int x) const { return x > 0; } +}; + +void test_find_last_if_not_present() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if_not(sv.begin(), sv.end(), is_positive()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -6); +} + +void test_find_last_if_not_present_first_segment() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {4, 5, 6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if_not(sv.begin(), sv.end(), is_positive()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -2); +} + +void test_find_last_if_not_not_present() +{ + test_detail::seg_vector sv; + sv.add_segment(3, 1); + sv.add_segment(2, 2); + + test_detail::seg_vector::iterator it = + segmented_find_last_if_not(sv.begin(), sv.end(), is_positive()); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_if_not_empty() +{ + test_detail::seg_vector sv; + test_detail::seg_vector::iterator it = + segmented_find_last_if_not(sv.begin(), sv.end(), is_positive()); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_if_not_non_segmented() +{ + std::vector v; + v.push_back(-1); + v.push_back(-2); + v.push_back(3); + + std::vector::iterator it = + segmented_find_last_if_not(v.begin(), v.end(), is_positive()); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, -2); + + v.clear(); + v.push_back(1); + v.push_back(2); + v.push_back(3); + it = segmented_find_last_if_not(v.begin(), v.end(), is_positive()); + BOOST_TEST(it == v.end()); +} + +void test_find_last_if_not_sentinel_segmented() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if_not(sv.begin(), test_detail::make_sentinel(sv.end()), is_positive()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -6); +} + +void test_find_last_if_not_sentinel_non_segmented() +{ + std::vector v; + v.push_back(-1); + v.push_back(-2); + v.push_back(3); + + std::vector::iterator it = + segmented_find_last_if_not(v.begin(), test_detail::make_sentinel(v.end()), is_positive()); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, -2); +} + +void test_find_last_if_not_seg2() +{ + test_detail::seg2_vector sv2; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv2.add_flat_segment_range(a1, a1 + 3); + sv2.add_flat_segment_range(a2, a2 + 3); + + test_detail::seg2_vector::iterator it = + segmented_find_last_if_not(sv2.begin(), sv2.end(), is_positive()); + BOOST_TEST(it != sv2.end()); + BOOST_TEST_EQ(*it, -6); +} + +int main() +{ + test_find_last_if_not_present(); + test_find_last_if_not_present_first_segment(); + test_find_last_if_not_not_present(); + test_find_last_if_not_empty(); + test_find_last_if_not_non_segmented(); + test_find_last_if_not_sentinel_segmented(); + test_find_last_if_not_sentinel_non_segmented(); + test_find_last_if_not_seg2(); + return boost::report_errors(); +} diff --git a/experimental/segmented_find_last_if_test.cpp b/experimental/segmented_find_last_if_test.cpp new file mode 100644 index 0000000..e347c4b --- /dev/null +++ b/experimental/segmented_find_last_if_test.cpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "segmented_test_helper.hpp" +#include + +using namespace boost::container; + +struct is_negative +{ + bool operator()(int x) const { return x < 0; } +}; + +void test_find_last_if_present() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if(sv.begin(), sv.end(), is_negative()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -6); +} + +void test_find_last_if_present_first_segment() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {4, 5, 6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if(sv.begin(), sv.end(), is_negative()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -2); +} + +void test_find_last_if_not_present() +{ + test_detail::seg_vector sv; + sv.add_segment(3, 1); + sv.add_segment(2, 2); + + test_detail::seg_vector::iterator it = + segmented_find_last_if(sv.begin(), sv.end(), is_negative()); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_if_empty() +{ + test_detail::seg_vector sv; + test_detail::seg_vector::iterator it = + segmented_find_last_if(sv.begin(), sv.end(), is_negative()); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_if_non_segmented() +{ + std::vector v; + v.push_back(-1); + v.push_back(-2); + v.push_back(3); + + std::vector::iterator it = + segmented_find_last_if(v.begin(), v.end(), is_negative()); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, -2); + + v.clear(); + v.push_back(1); + v.push_back(2); + v.push_back(3); + it = segmented_find_last_if(v.begin(), v.end(), is_negative()); + BOOST_TEST(it == v.end()); +} + +void test_find_last_if_sentinel_segmented() +{ + test_detail::seg_vector sv; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last_if(sv.begin(), test_detail::make_sentinel(sv.end()), is_negative()); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, -6); +} + +void test_find_last_if_sentinel_non_segmented() +{ + std::vector v; + v.push_back(-1); + v.push_back(-2); + v.push_back(3); + + std::vector::iterator it = + segmented_find_last_if(v.begin(), test_detail::make_sentinel(v.end()), is_negative()); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, -2); +} + +void test_find_last_if_seg2() +{ + test_detail::seg2_vector sv2; + int a1[] = {1, -2, 3}; + int a2[] = {-4, 5, -6}; + sv2.add_flat_segment_range(a1, a1 + 3); + sv2.add_flat_segment_range(a2, a2 + 3); + + test_detail::seg2_vector::iterator it = + segmented_find_last_if(sv2.begin(), sv2.end(), is_negative()); + BOOST_TEST(it != sv2.end()); + BOOST_TEST_EQ(*it, -6); +} + +int main() +{ + test_find_last_if_present(); + test_find_last_if_present_first_segment(); + test_find_last_if_not_present(); + test_find_last_if_empty(); + test_find_last_if_non_segmented(); + test_find_last_if_sentinel_segmented(); + test_find_last_if_sentinel_non_segmented(); + test_find_last_if_seg2(); + return boost::report_errors(); +} diff --git a/experimental/segmented_find_last_test.cpp b/experimental/segmented_find_last_test.cpp new file mode 100644 index 0000000..df2be1f --- /dev/null +++ b/experimental/segmented_find_last_test.cpp @@ -0,0 +1,144 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "segmented_test_helper.hpp" +#include + +using namespace boost::container; + +void test_find_last_present_last_segment() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 2, 6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = segmented_find_last(sv.begin(), sv.end(), 2); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, 2); + test_detail::seg_vector::iterator first_it = segmented_find(sv.begin(), sv.end(), 2); + BOOST_TEST(it != first_it); +} + +void test_find_last_present_first_segment() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 5, 6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = segmented_find_last(sv.begin(), sv.end(), 2); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, 2); +} + +void test_find_last_not_present() +{ + test_detail::seg_vector sv; + sv.add_segment(3, 1); + sv.add_segment(2, 2); + + test_detail::seg_vector::iterator it = segmented_find_last(sv.begin(), sv.end(), 99); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_empty() +{ + test_detail::seg_vector sv; + test_detail::seg_vector::iterator it = segmented_find_last(sv.begin(), sv.end(), 1); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_non_segmented() +{ + std::vector v; + v.push_back(10); + v.push_back(20); + v.push_back(10); + v.push_back(30); + + std::vector::iterator it = segmented_find_last(v.begin(), v.end(), 10); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, 10); + BOOST_TEST(it == v.begin() + 2); + + it = segmented_find_last(v.begin(), v.end(), 99); + BOOST_TEST(it == v.end()); +} + +void test_find_last_sentinel_segmented() +{ + test_detail::seg_vector sv; + int a1[] = {1, 2, 3}; + int a2[] = {4, 2, 6}; + sv.add_segment_range(a1, a1 + 3); + sv.add_segment_range(a2, a2 + 3); + + test_detail::seg_vector::iterator it = + segmented_find_last(sv.begin(), test_detail::make_sentinel(sv.end()), 2); + BOOST_TEST(it != sv.end()); + BOOST_TEST_EQ(*it, 2); + + it = segmented_find_last(sv.begin(), test_detail::make_sentinel(sv.end()), 99); + BOOST_TEST(it == sv.end()); +} + +void test_find_last_sentinel_non_segmented() +{ + std::vector v; + v.push_back(10); + v.push_back(20); + v.push_back(10); + + std::vector::iterator it = + segmented_find_last(v.begin(), test_detail::make_sentinel(v.end()), 10); + BOOST_TEST(it != v.end()); + BOOST_TEST_EQ(*it, 10); + BOOST_TEST(it == v.begin() + 2); + + it = segmented_find_last(v.begin(), test_detail::make_sentinel(v.end()), 99); + BOOST_TEST(it == v.end()); +} + +void test_find_last_seg2() +{ + test_detail::seg2_vector sv2; + int a1[] = {1, 2, 3}; + int a2[] = {4, 2}; + 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::iterator it = segmented_find_last(sv2.begin(), sv2.end(), 2); + BOOST_TEST(it != sv2.end()); + BOOST_TEST_EQ(*it, 2); + + it = segmented_find_last(sv2.begin(), sv2.end(), 99); + BOOST_TEST(it == sv2.end()); +} + +int main() +{ + test_find_last_present_last_segment(); + test_find_last_present_first_segment(); + test_find_last_not_present(); + test_find_last_empty(); + test_find_last_non_segmented(); + test_find_last_sentinel_segmented(); + test_find_last_sentinel_non_segmented(); + test_find_last_seg2(); + return boost::report_errors(); +} diff --git a/include/boost/container/experimental/segmented_find_last.hpp b/include/boost/container/experimental/segmented_find_last.hpp new file mode 100644 index 0000000..44960df --- /dev/null +++ b/include/boost/container/experimental/segmented_find_last.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_HPP +#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace container { + +//! Returns an iterator to the last element equal to \c value +//! in [first, last), or \c last if not found. +template +BOOST_CONTAINER_FORCEINLINE +FwdIt segmented_find_last(FwdIt first, Sent last, const T& value) +{ + return boost::container::segmented_find_last_if(first, last, equal_to_value(value)); +} + +} // namespace container +} // namespace boost + +#include + +#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_HPP diff --git a/include/boost/container/experimental/segmented_find_last_if.hpp b/include/boost/container/experimental/segmented_find_last_if.hpp new file mode 100644 index 0000000..5f69dd3 --- /dev/null +++ b/include/boost/container/experimental/segmented_find_last_if.hpp @@ -0,0 +1,234 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_HPP +#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace container { + +template +FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred); + +namespace detail_algo { + +////////////////////////////////////////////// +// Non-segmented scans +////////////////////////////////////////////// + +template +FwdIt find_last_if_scan(FwdIt first, FwdIt last, Pred pred, + non_segmented_iterator_tag, const std::forward_iterator_tag&) +{ + FwdIt result = last; + for (; first != last; ++first) + if (pred(*first)) result = first; + return result; +} + +template +BidirIt find_last_if_scan(BidirIt first, BidirIt last, Pred pred, + non_segmented_iterator_tag, const std::bidirectional_iterator_tag&) +{ + BidirIt cur = last; + while (cur != first) { + --cur; + if (pred(*cur)) return cur; + } + return last; +} + +////////////////////////////////////////////// +// Segmented forward scan +////////////////////////////////////////////// + +template +SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred, + segmented_iterator_tag, const std::forward_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; + + if (first == last) return last; + + SegIt result = last; + segment_iterator sfirst = traits::segment(first); + const segment_iterator slast = traits::segment(last); + + if (sfirst == slast) { + const local_iterator lf = traits::local(first); + const local_iterator ll = traits::local(last); + const local_iterator r = find_last_if_scan(lf, ll, pred, is_local_seg_t(), cat); + if (r != ll) + return traits::compose(sfirst, r); + return last; + } + + // First segment + { + const local_iterator le = traits::end(sfirst); + const local_iterator r = find_last_if_scan(traits::local(first), le, pred, is_local_seg_t(), cat); + if (r != le) + result = traits::compose(sfirst, r); + } + // Middle segments + for (++sfirst; sfirst != slast; ++sfirst) { + const local_iterator le = traits::end(sfirst); + const local_iterator r = find_last_if_scan(traits::begin(sfirst), le, pred, is_local_seg_t(), cat); + if (r != le) + result = traits::compose(sfirst, r); + } + // Last segment + { + const local_iterator ll = traits::local(last); + const local_iterator r = find_last_if_scan(traits::begin(sfirst), ll, pred, is_local_seg_t(), cat); + if (r != ll) + result = traits::compose(sfirst, r); + } + + return result; +} + +////////////////////////////////////////////// +// Segmented bidirectional scan +////////////////////////////////////////////// + +template +SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred, + segmented_iterator_tag, const std::bidirectional_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; + + if (first == last) return last; + + segment_iterator sfirst = traits::segment(first); + segment_iterator slast = traits::segment(last); + + if (sfirst == slast) { + const local_iterator lf = traits::local(first); + const local_iterator ll = traits::local(last); + const local_iterator r = find_last_if_scan(lf, ll, pred, is_local_seg_t(), cat); + if (r != ll) + return traits::compose(sfirst, r); + return last; + } + + // Last segment (partial): [begin(slast), local(last)) + { + const local_iterator lb = traits::begin(slast); + const local_iterator ll = traits::local(last); + if (lb != ll) { + const local_iterator r = find_last_if_scan(lb, ll, pred, is_local_seg_t(), cat); + if (r != ll) + return traits::compose(slast, r); + } + } + + // Middle segments in reverse + { + segment_iterator scur = slast; + for (--scur; scur != sfirst; --scur) { + const local_iterator lb = traits::begin(scur); + const local_iterator le = traits::end(scur); + const local_iterator r = find_last_if_scan(lb, le, pred, is_local_seg_t(), cat); + if (r != le) + return traits::compose(scur, r); + } + } + + // First segment (partial): [local(first), end(sfirst)) + { + const local_iterator lf = traits::local(first); + const local_iterator le = traits::end(sfirst); + const local_iterator r = find_last_if_scan(lf, le, pred, is_local_seg_t(), cat); + if (r != le) + return traits::compose(sfirst, r); + } + + return last; +} + +////////////////////////////////////////////// +// Sentinel / generic fallback +////////////////////////////////////////////// + +template +FwdIt find_last_if_scan(FwdIt first, Sent last, Pred pred, SegTag, CatTag) +{ + FwdIt result = first; + bool found = false; + for (; first != last; ++first) { + if (pred(*first)) { result = first; found = true; } + } + return found ? result : first; +} + +////////////////////////////////////////////// +// sent_filter: sentinel ⇒ forward + flat +////////////////////////////////////////////// + +template +struct find_last_sent_filter +{ + typedef std::forward_iterator_tag cat_t; + typedef non_segmented_iterator_tag seg_t; +}; + +template +struct find_last_sent_filter +{ + typedef Tag cat_t; + typedef Seg seg_t; +}; + +} // namespace detail_algo + +//! Returns an iterator to the last element satisfying \c pred +//! in [first, last), or \c last if not found. +//! For bidirectional iterators, scans backward for early exit. +//! For forward iterators, scans the entire range and remembers +//! the last match. +template +BOOST_CONTAINER_FORCEINLINE +FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred) +{ + typedef segmented_iterator_traits traits; + typedef typename boost::container::iterator_traits::iterator_category cat_t; + typedef typename traits::is_segmented_iterator seg_t; + typedef detail_algo::find_last_sent_filter sf; + return detail_algo::find_last_if_scan + ( first, last, pred + , typename sf::seg_t() + , typename sf::cat_t()); +} + +} // namespace container +} // namespace boost + +#include + +#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_HPP diff --git a/include/boost/container/experimental/segmented_find_last_if_not.hpp b/include/boost/container/experimental/segmented_find_last_if_not.hpp new file mode 100644 index 0000000..4f7c0fe --- /dev/null +++ b/include/boost/container/experimental/segmented_find_last_if_not.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_HPP +#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace container { + +//! Returns an iterator to the last element for which \c pred +//! returns false in [first, last), or \c last if not found. +template +BOOST_CONTAINER_FORCEINLINE +FwdIt segmented_find_last_if_not(FwdIt first, Sent last, Pred pred) +{ + return (segmented_find_last_if)(first, last, not_pred(pred)); +} + +} // namespace container +} // namespace boost + +#include + +#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_HPP