Skip to content

Commit 57ae7a8

Browse files
committed
Added segmented_find_last, segmented_find_last_if, segmented_find_last_if_not
1 parent 60761d2 commit 57ae7a8

7 files changed

Lines changed: 880 additions & 8 deletions

experimental/bench_segmented_algos.cpp

Lines changed: 132 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
#include <boost/container/experimental/segmented_find.hpp>
3434
#include <boost/container/experimental/segmented_find_if.hpp>
3535
#include <boost/container/experimental/segmented_find_if_not.hpp>
36+
#include <boost/container/experimental/segmented_find_last.hpp>
37+
#include <boost/container/experimental/segmented_find_last_if.hpp>
38+
#include <boost/container/experimental/segmented_find_last_if_not.hpp>
3639
#include <boost/container/experimental/segmented_for_each.hpp>
3740
#include <boost/container/experimental/segmented_generate.hpp>
3841
#include <boost/container/experimental/segmented_generate_n.hpp>
@@ -415,6 +418,32 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred)
415418

416419
#endif
417420

421+
template<class FwdIt, class T>
422+
FwdIt find_last(FwdIt first, FwdIt last, const T& val)
423+
{
424+
FwdIt result = last;
425+
for (; first != last; ++first)
426+
if (*first == val) result = first;
427+
return result;
428+
}
429+
430+
template<class FwdIt, class Pred>
431+
FwdIt find_last_if(FwdIt first, FwdIt last, Pred pred)
432+
{
433+
FwdIt result = last;
434+
for (; first != last; ++first)
435+
if (pred(*first)) result = first;
436+
return result;
437+
}
438+
439+
template<class FwdIt, class Pred>
440+
FwdIt find_last_if_not(FwdIt first, FwdIt last, Pred pred)
441+
{
442+
FwdIt result = last;
443+
for (; first != last; ++first)
444+
if (!pred(*first)) result = first;
445+
return result;
446+
}
418447

419448

420449
//Not benchmarked:
@@ -425,7 +454,6 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred)
425454
//find_end
426455
//find_first_of
427456
//adjacent_find
428-
//mismatch
429457
//copy_backward
430458
//move
431459
//move_backward
@@ -498,10 +526,6 @@ FwdIt partition_point(FwdIt first, FwdIt last, Pred pred)
498526
//lexicographical_compare_three_way
499527

500528
//range-based?
501-
//find_last
502-
//find_last_if
503-
//find_last_if_not
504-
//
505529
//contains
506530
//contains_subrange
507531
//starts_with
@@ -917,6 +941,96 @@ void bench_find_if_not(C c, std::size_t iters, const char* cname,
917941
print_ratio(label, cname, r1, r2);
918942
}
919943

944+
template<class C>
945+
void bench_find_last(C c, std::size_t iters, const char* cname,
946+
const typename C::value_type& val, const char* label)
947+
{
948+
int result = 0;
949+
950+
cpu_timer t1;
951+
for (std::size_t i = 0; i < iters; ++i) {
952+
clobber();
953+
t1.resume();
954+
typename C::iterator it = bench_detail::find_last(c.begin(), c.end(), val);
955+
result = (it == c.end()) ? 0 : 1;
956+
t1.stop();
957+
escape(&result);
958+
}
959+
double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size());
960+
961+
cpu_timer t2;
962+
for (std::size_t i = 0; i < iters; ++i) {
963+
clobber();
964+
t2.resume();
965+
typename C::iterator it = bc::segmented_find_last(c.begin(), c.end(), val);
966+
result = (it == c.end()) ? 0 : 1;
967+
t2.stop();
968+
escape(&result);
969+
}
970+
double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size());
971+
print_ratio(label, cname, r1, r2);
972+
}
973+
974+
template<class C, class Pred>
975+
void bench_find_last_if(C c, std::size_t iters, const char* cname,
976+
Pred pred, const char* label)
977+
{
978+
int result = 0;
979+
980+
cpu_timer t1;
981+
for (std::size_t i = 0; i < iters; ++i) {
982+
clobber();
983+
t1.resume();
984+
typename C::iterator it = bench_detail::find_last_if(c.begin(), c.end(), pred);
985+
result = (it != c.end()) ? int_value(*it) : -1;
986+
t1.stop();
987+
escape(&result);
988+
}
989+
double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size());
990+
991+
cpu_timer t2;
992+
for (std::size_t i = 0; i < iters; ++i) {
993+
clobber();
994+
t2.resume();
995+
typename C::iterator it = bc::segmented_find_last_if(c.begin(), c.end(), pred);
996+
result = (it != c.end()) ? int_value(*it) : -1;
997+
t2.stop();
998+
escape(&result);
999+
}
1000+
double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size());
1001+
print_ratio(label, cname, r1, r2);
1002+
}
1003+
1004+
template<class C, class Pred>
1005+
void bench_find_last_if_not(C c, std::size_t iters, const char* cname,
1006+
Pred pred, const char* label)
1007+
{
1008+
int result = 0;
1009+
1010+
cpu_timer t1;
1011+
for (std::size_t i = 0; i < iters; ++i) {
1012+
clobber();
1013+
t1.resume();
1014+
typename C::iterator it = bench_detail::find_last_if_not(c.begin(), c.end(), pred);
1015+
result = (it != c.end()) ? int_value(*it) : -1;
1016+
t1.stop();
1017+
escape(&result);
1018+
}
1019+
double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size());
1020+
1021+
cpu_timer t2;
1022+
for (std::size_t i = 0; i < iters; ++i) {
1023+
clobber();
1024+
t2.resume();
1025+
typename C::iterator it = bc::segmented_find_last_if_not(c.begin(), c.end(), pred);
1026+
result = (it != c.end()) ? int_value(*it) : -1;
1027+
t2.stop();
1028+
escape(&result);
1029+
}
1030+
double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size());
1031+
print_ratio(label, cname, r1, r2);
1032+
}
1033+
9201034
template<class C>
9211035
void bench_equal(C c, C& c2, std::size_t iters, const char* cname,
9221036
const char* label)
@@ -1864,6 +1978,18 @@ void run_all(const C& c, std::size_t iters, const char* cname)
18641978
bench_find_if_not(c, iters, cname, unequal_to_ref<VT>(VT(static_cast<int>(c.size() / 2))), "find_if_not(hit)");
18651979
bench_find_if_not(c, iters, cname, is_zero_or_positive<VT>(), "find_if_not(miss)");
18661980

1981+
//find_last
1982+
bench_find_last(c, iters, cname, VT(static_cast<int>(c.size() / 2)), "find_last(hit)");
1983+
bench_find_last(c, iters, cname, VT(-1), "find_last(miss)");
1984+
1985+
//find_last_if
1986+
bench_find_last_if(c, iters, cname, equal_to_ref<VT>(VT(static_cast<int>(c.size() / 2))), "find_last_if(hit)");
1987+
bench_find_last_if(c, iters, cname, is_negative<VT>(), "find_last_if(miss)");
1988+
1989+
//find_last_if_not
1990+
bench_find_last_if_not(c, iters, cname, unequal_to_ref<VT>(VT(static_cast<int>(c.size() / 2))), "find_last_if_not(hit)");
1991+
bench_find_last_if_not(c, iters, cname, is_zero_or_positive<VT>(), "find_last_if_not(miss)");
1992+
18671993
//for_each
18681994
bench_for_each(c, iters, cname);
18691995

@@ -1915,9 +2041,7 @@ void run_all(const C& c, std::size_t iters, const char* cname)
19152041
{
19162042
C c2(c);
19172043
bench_mismatch(c, c2, iters, cname, "mismatch(hit)");
1918-
typename C::iterator last = c2.end();
1919-
--last;
1920-
*last = VT(-1);
2044+
c2[c2.size()/2] = VT(-1);
19212045
bench_mismatch(c, c2, iters, cname, "mismatch(miss)");
19222046
}
19232047

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//////////////////////////////////////////////////////////////////////////////
2+
//
3+
// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost
4+
// Software License, Version 1.0. (See accompanying file
5+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
// See http://www.boost.org/libs/container for documentation.
8+
//
9+
//////////////////////////////////////////////////////////////////////////////
10+
11+
#include <boost/container/experimental/segmented_find_last_if_not.hpp>
12+
#include <boost/core/lightweight_test.hpp>
13+
#include "segmented_test_helper.hpp"
14+
#include <vector>
15+
16+
using namespace boost::container;
17+
18+
struct is_positive
19+
{
20+
bool operator()(int x) const { return x > 0; }
21+
};
22+
23+
void test_find_last_if_not_present()
24+
{
25+
test_detail::seg_vector<int> sv;
26+
int a1[] = {1, -2, 3};
27+
int a2[] = {-4, 5, -6};
28+
sv.add_segment_range(a1, a1 + 3);
29+
sv.add_segment_range(a2, a2 + 3);
30+
31+
test_detail::seg_vector<int>::iterator it =
32+
segmented_find_last_if_not(sv.begin(), sv.end(), is_positive());
33+
BOOST_TEST(it != sv.end());
34+
BOOST_TEST_EQ(*it, -6);
35+
}
36+
37+
void test_find_last_if_not_present_first_segment()
38+
{
39+
test_detail::seg_vector<int> sv;
40+
int a1[] = {1, -2, 3};
41+
int a2[] = {4, 5, 6};
42+
sv.add_segment_range(a1, a1 + 3);
43+
sv.add_segment_range(a2, a2 + 3);
44+
45+
test_detail::seg_vector<int>::iterator it =
46+
segmented_find_last_if_not(sv.begin(), sv.end(), is_positive());
47+
BOOST_TEST(it != sv.end());
48+
BOOST_TEST_EQ(*it, -2);
49+
}
50+
51+
void test_find_last_if_not_not_present()
52+
{
53+
test_detail::seg_vector<int> sv;
54+
sv.add_segment(3, 1);
55+
sv.add_segment(2, 2);
56+
57+
test_detail::seg_vector<int>::iterator it =
58+
segmented_find_last_if_not(sv.begin(), sv.end(), is_positive());
59+
BOOST_TEST(it == sv.end());
60+
}
61+
62+
void test_find_last_if_not_empty()
63+
{
64+
test_detail::seg_vector<int> sv;
65+
test_detail::seg_vector<int>::iterator it =
66+
segmented_find_last_if_not(sv.begin(), sv.end(), is_positive());
67+
BOOST_TEST(it == sv.end());
68+
}
69+
70+
void test_find_last_if_not_non_segmented()
71+
{
72+
std::vector<int> v;
73+
v.push_back(-1);
74+
v.push_back(-2);
75+
v.push_back(3);
76+
77+
std::vector<int>::iterator it =
78+
segmented_find_last_if_not(v.begin(), v.end(), is_positive());
79+
BOOST_TEST(it != v.end());
80+
BOOST_TEST_EQ(*it, -2);
81+
82+
v.clear();
83+
v.push_back(1);
84+
v.push_back(2);
85+
v.push_back(3);
86+
it = segmented_find_last_if_not(v.begin(), v.end(), is_positive());
87+
BOOST_TEST(it == v.end());
88+
}
89+
90+
void test_find_last_if_not_sentinel_segmented()
91+
{
92+
test_detail::seg_vector<int> sv;
93+
int a1[] = {1, -2, 3};
94+
int a2[] = {-4, 5, -6};
95+
sv.add_segment_range(a1, a1 + 3);
96+
sv.add_segment_range(a2, a2 + 3);
97+
98+
test_detail::seg_vector<int>::iterator it =
99+
segmented_find_last_if_not(sv.begin(), test_detail::make_sentinel(sv.end()), is_positive());
100+
BOOST_TEST(it != sv.end());
101+
BOOST_TEST_EQ(*it, -6);
102+
}
103+
104+
void test_find_last_if_not_sentinel_non_segmented()
105+
{
106+
std::vector<int> v;
107+
v.push_back(-1);
108+
v.push_back(-2);
109+
v.push_back(3);
110+
111+
std::vector<int>::iterator it =
112+
segmented_find_last_if_not(v.begin(), test_detail::make_sentinel(v.end()), is_positive());
113+
BOOST_TEST(it != v.end());
114+
BOOST_TEST_EQ(*it, -2);
115+
}
116+
117+
void test_find_last_if_not_seg2()
118+
{
119+
test_detail::seg2_vector<int> sv2;
120+
int a1[] = {1, -2, 3};
121+
int a2[] = {-4, 5, -6};
122+
sv2.add_flat_segment_range(a1, a1 + 3);
123+
sv2.add_flat_segment_range(a2, a2 + 3);
124+
125+
test_detail::seg2_vector<int>::iterator it =
126+
segmented_find_last_if_not(sv2.begin(), sv2.end(), is_positive());
127+
BOOST_TEST(it != sv2.end());
128+
BOOST_TEST_EQ(*it, -6);
129+
}
130+
131+
int main()
132+
{
133+
test_find_last_if_not_present();
134+
test_find_last_if_not_present_first_segment();
135+
test_find_last_if_not_not_present();
136+
test_find_last_if_not_empty();
137+
test_find_last_if_not_non_segmented();
138+
test_find_last_if_not_sentinel_segmented();
139+
test_find_last_if_not_sentinel_non_segmented();
140+
test_find_last_if_not_seg2();
141+
return boost::report_errors();
142+
}

0 commit comments

Comments
 (0)