mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 14:30:45 +02:00
Added segmented_find_last, segmented_find_last_if, segmented_find_last_if_not
This commit is contained in:
@@ -33,6 +33,9 @@
|
||||
#include <boost/container/experimental/segmented_find.hpp>
|
||||
#include <boost/container/experimental/segmented_find_if.hpp>
|
||||
#include <boost/container/experimental/segmented_find_if_not.hpp>
|
||||
#include <boost/container/experimental/segmented_find_last.hpp>
|
||||
#include <boost/container/experimental/segmented_find_last_if.hpp>
|
||||
#include <boost/container/experimental/segmented_find_last_if_not.hpp>
|
||||
#include <boost/container/experimental/segmented_for_each.hpp>
|
||||
#include <boost/container/experimental/segmented_generate.hpp>
|
||||
#include <boost/container/experimental/segmented_generate_n.hpp>
|
||||
@@ -415,6 +418,32 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred)
|
||||
|
||||
#endif
|
||||
|
||||
template<class FwdIt, class T>
|
||||
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<class FwdIt, class Pred>
|
||||
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<class FwdIt, class Pred>
|
||||
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<class C>
|
||||
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<class C, class Pred>
|
||||
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<class C, class Pred>
|
||||
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<class C>
|
||||
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>(VT(static_cast<int>(c.size() / 2))), "find_if_not(hit)");
|
||||
bench_find_if_not(c, iters, cname, is_zero_or_positive<VT>(), "find_if_not(miss)");
|
||||
|
||||
//find_last
|
||||
bench_find_last(c, iters, cname, VT(static_cast<int>(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>(VT(static_cast<int>(c.size() / 2))), "find_last_if(hit)");
|
||||
bench_find_last_if(c, iters, cname, is_negative<VT>(), "find_last_if(miss)");
|
||||
|
||||
//find_last_if_not
|
||||
bench_find_last_if_not(c, iters, cname, unequal_to_ref<VT>(VT(static_cast<int>(c.size() / 2))), "find_last_if_not(hit)");
|
||||
bench_find_last_if_not(c, iters, cname, is_zero_or_positive<VT>(), "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)");
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <boost/container/experimental/segmented_find_last_if_not.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "segmented_test_helper.hpp"
|
||||
#include <vector>
|
||||
|
||||
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<int> 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<int>::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<int> 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<int>::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<int> sv;
|
||||
sv.add_segment(3, 1);
|
||||
sv.add_segment(2, 2);
|
||||
|
||||
test_detail::seg_vector<int>::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<int> sv;
|
||||
test_detail::seg_vector<int>::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<int> v;
|
||||
v.push_back(-1);
|
||||
v.push_back(-2);
|
||||
v.push_back(3);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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<int> v;
|
||||
v.push_back(-1);
|
||||
v.push_back(-2);
|
||||
v.push_back(3);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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();
|
||||
}
|
||||
@@ -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 <boost/container/experimental/segmented_find_last_if.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "segmented_test_helper.hpp"
|
||||
#include <vector>
|
||||
|
||||
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<int> 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<int>::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<int> 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<int>::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<int> sv;
|
||||
sv.add_segment(3, 1);
|
||||
sv.add_segment(2, 2);
|
||||
|
||||
test_detail::seg_vector<int>::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<int> sv;
|
||||
test_detail::seg_vector<int>::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<int> v;
|
||||
v.push_back(-1);
|
||||
v.push_back(-2);
|
||||
v.push_back(3);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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<int> v;
|
||||
v.push_back(-1);
|
||||
v.push_back(-2);
|
||||
v.push_back(3);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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();
|
||||
}
|
||||
@@ -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 <boost/container/experimental/segmented_find_last.hpp>
|
||||
#include <boost/container/experimental/segmented_find.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "segmented_test_helper.hpp"
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::container;
|
||||
|
||||
void test_find_last_present_last_segment()
|
||||
{
|
||||
test_detail::seg_vector<int> 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<int>::iterator it = segmented_find_last(sv.begin(), sv.end(), 2);
|
||||
BOOST_TEST(it != sv.end());
|
||||
BOOST_TEST_EQ(*it, 2);
|
||||
test_detail::seg_vector<int>::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<int> 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<int>::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<int> sv;
|
||||
sv.add_segment(3, 1);
|
||||
sv.add_segment(2, 2);
|
||||
|
||||
test_detail::seg_vector<int>::iterator it = segmented_find_last(sv.begin(), sv.end(), 99);
|
||||
BOOST_TEST(it == sv.end());
|
||||
}
|
||||
|
||||
void test_find_last_empty()
|
||||
{
|
||||
test_detail::seg_vector<int> sv;
|
||||
test_detail::seg_vector<int>::iterator it = segmented_find_last(sv.begin(), sv.end(), 1);
|
||||
BOOST_TEST(it == sv.end());
|
||||
}
|
||||
|
||||
void test_find_last_non_segmented()
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.push_back(10);
|
||||
v.push_back(20);
|
||||
v.push_back(10);
|
||||
v.push_back(30);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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<int> v;
|
||||
v.push_back(10);
|
||||
v.push_back(20);
|
||||
v.push_back(10);
|
||||
|
||||
std::vector<int>::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<int> 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<int>::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();
|
||||
}
|
||||
@@ -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 <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/workaround.hpp>
|
||||
#include <boost/container/detail/compare_functors.hpp>
|
||||
#include <boost/container/experimental/segmented_find_last_if.hpp>
|
||||
|
||||
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 <class FwdIt, class Sent, class T>
|
||||
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<T>(value));
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/container/detail/config_end.hpp>
|
||||
|
||||
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_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 <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/workaround.hpp>
|
||||
#include <boost/container/detail/iterator.hpp>
|
||||
#include <boost/container/experimental/segmented_iterator_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
|
||||
template <class FwdIt, class Sent, class Pred>
|
||||
FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred);
|
||||
|
||||
namespace detail_algo {
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Non-segmented scans
|
||||
//////////////////////////////////////////////
|
||||
|
||||
template <class FwdIt, class Pred>
|
||||
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 <class BidirIt, class Pred>
|
||||
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 <class SegIt, class Pred>
|
||||
SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred,
|
||||
segmented_iterator_tag, const std::forward_iterator_tag& cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIt> traits;
|
||||
typedef typename traits::local_iterator local_iterator;
|
||||
typedef typename traits::segment_iterator segment_iterator;
|
||||
typedef typename segmented_iterator_traits<local_iterator>::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 <class SegIt, class Pred>
|
||||
SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred,
|
||||
segmented_iterator_tag, const std::bidirectional_iterator_tag& cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIt> traits;
|
||||
typedef typename traits::local_iterator local_iterator;
|
||||
typedef typename traits::segment_iterator segment_iterator;
|
||||
typedef typename segmented_iterator_traits<local_iterator>::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 <class FwdIt, class Sent, class Pred, class SegTag, class CatTag>
|
||||
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<class It, class Sent, class Seg, class Tag>
|
||||
struct find_last_sent_filter
|
||||
{
|
||||
typedef std::forward_iterator_tag cat_t;
|
||||
typedef non_segmented_iterator_tag seg_t;
|
||||
};
|
||||
|
||||
template<class It, class Seg, class Tag>
|
||||
struct find_last_sent_filter<It, It, Seg, Tag>
|
||||
{
|
||||
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 <class FwdIt, class Sent, class Pred>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred)
|
||||
{
|
||||
typedef segmented_iterator_traits<FwdIt> traits;
|
||||
typedef typename boost::container::iterator_traits<FwdIt>::iterator_category cat_t;
|
||||
typedef typename traits::is_segmented_iterator seg_t;
|
||||
typedef detail_algo::find_last_sent_filter<FwdIt, Sent, seg_t, cat_t> sf;
|
||||
return detail_algo::find_last_if_scan
|
||||
( first, last, pred
|
||||
, typename sf::seg_t()
|
||||
, typename sf::cat_t());
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/container/detail/config_end.hpp>
|
||||
|
||||
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_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 <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/workaround.hpp>
|
||||
#include <boost/container/detail/compare_functors.hpp>
|
||||
#include <boost/container/experimental/segmented_find_last_if.hpp>
|
||||
|
||||
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 <class FwdIt, class Sent, class Pred>
|
||||
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>(pred));
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/container/detail/config_end.hpp>
|
||||
|
||||
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_HPP
|
||||
Reference in New Issue
Block a user