Skip to content

Commit 18edb76

Browse files
committed
Add segmented_mismatch algorithm
1 parent cdfda03 commit 18edb76

3 files changed

Lines changed: 377 additions & 0 deletions

File tree

experimental/bench_segmented_algos.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <boost/container/experimental/segmented_is_partitioned.hpp>
3838
#include <boost/container/experimental/segmented_is_sorted.hpp>
3939
#include <boost/container/experimental/segmented_merge.hpp>
40+
#include <boost/container/experimental/segmented_mismatch.hpp>
4041
#include <boost/container/experimental/segmented_is_sorted_until.hpp>
4142
#include <boost/container/experimental/segmented_partition.hpp>
4243
#include <boost/container/experimental/segmented_partition_copy.hpp>
@@ -1254,6 +1255,32 @@ void bench_merge(C c, C& c2, std::size_t iters, const char* cname)
12541255
print_ratio("merge", cname, r1, r2);
12551256
}
12561257

1258+
template<class C>
1259+
void bench_mismatch(C c, C& c2, std::size_t iters, const char* cname,
1260+
const char* label)
1261+
{
1262+
int result = 0;
1263+
1264+
cpu_timer t1;
1265+
for (std::size_t i = 0; i < iters; ++i) {
1266+
t1.resume();
1267+
result = (std::mismatch(c.begin(), c.end(), c2.begin()).first == c.end()) ? 1 : 0;
1268+
t1.stop();
1269+
escape(&result);
1270+
}
1271+
double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size());
1272+
1273+
cpu_timer t2;
1274+
for (std::size_t i = 0; i < iters; ++i) {
1275+
t2.resume();
1276+
result = (bc::segmented_mismatch(c.begin(), c.end(), c2.begin()).first == c.end()) ? 1 : 0;
1277+
t2.stop();
1278+
escape(&result);
1279+
}
1280+
double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size());
1281+
print_ratio(label, cname, r1, r2);
1282+
}
1283+
12571284
template<class C>
12581285
void bench_swap_ranges(C c, std::size_t iters, const char* cname)
12591286
{
@@ -1663,6 +1690,16 @@ void run_all(const C& c, std::size_t iters, const char* cname)
16631690
bench_merge(c, c2, iters, cname);
16641691
}
16651692

1693+
//mismatch
1694+
{
1695+
C c2(c);
1696+
bench_mismatch(c, c2, iters, cname, "mismatch(hit)");
1697+
typename C::iterator last = c2.end();
1698+
--last;
1699+
*last = VT(-1);
1700+
bench_mismatch(c, c2, iters, cname, "mismatch(miss)");
1701+
}
1702+
16661703
//partition
16671704
bench_partition(c, iters, cname, is_odd<VT>(), "partition(hit)");
16681705
bench_partition(c, iters, cname, is_negative<VT>(), "partition(miss)");
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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_mismatch.hpp>
12+
#include <boost/core/lightweight_test.hpp>
13+
#include "segmented_test_helper.hpp"
14+
#include <vector>
15+
#include <utility>
16+
17+
using namespace boost::container;
18+
19+
void test_mismatch_matching()
20+
{
21+
test_detail::seg_vector<int> sv;
22+
int a1[] = {1, 2, 3};
23+
int a2[] = {4, 5};
24+
int a3[] = {6, 7, 8, 9};
25+
sv.add_segment_range(a1, a1 + 3);
26+
sv.add_segment_range(a2, a2 + 2);
27+
sv.add_segment_range(a3, a3 + 4);
28+
29+
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
30+
typedef test_detail::seg_vector<int>::iterator seg_it;
31+
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
32+
BOOST_TEST(r.first == sv.end());
33+
BOOST_TEST(r.second == ref + 9);
34+
}
35+
36+
void test_mismatch_found()
37+
{
38+
test_detail::seg_vector<int> sv;
39+
int a1[] = {1, 2, 3};
40+
int a2[] = {4, 5};
41+
sv.add_segment_range(a1, a1 + 3);
42+
sv.add_segment_range(a2, a2 + 2);
43+
44+
int ref[] = {1, 2, 3, 4, 99};
45+
typedef test_detail::seg_vector<int>::iterator seg_it;
46+
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
47+
BOOST_TEST(r.first != sv.end());
48+
BOOST_TEST_EQ(*r.first, 5);
49+
BOOST_TEST_EQ(*r.second, 99);
50+
}
51+
52+
void test_mismatch_first_segment()
53+
{
54+
test_detail::seg_vector<int> sv;
55+
int a1[] = {1, 2, 3};
56+
int a2[] = {4, 5};
57+
sv.add_segment_range(a1, a1 + 3);
58+
sv.add_segment_range(a2, a2 + 2);
59+
60+
int ref[] = {1, 99, 3, 4, 5};
61+
typedef test_detail::seg_vector<int>::iterator seg_it;
62+
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
63+
BOOST_TEST(r.first != sv.end());
64+
BOOST_TEST_EQ(*r.first, 2);
65+
BOOST_TEST_EQ(*r.second, 99);
66+
}
67+
68+
void test_mismatch_empty()
69+
{
70+
test_detail::seg_vector<int> sv;
71+
int dummy = 0;
72+
typedef test_detail::seg_vector<int>::iterator seg_it;
73+
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), &dummy);
74+
BOOST_TEST(r.first == sv.end());
75+
BOOST_TEST(r.second == &dummy);
76+
}
77+
78+
void test_mismatch_single_segment()
79+
{
80+
test_detail::seg_vector<int> sv;
81+
int a[] = {10, 20, 30};
82+
sv.add_segment_range(a, a + 3);
83+
84+
int ref_match[] = {10, 20, 30};
85+
typedef test_detail::seg_vector<int>::iterator seg_it;
86+
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref_match);
87+
BOOST_TEST(r.first == sv.end());
88+
89+
int ref_fail[] = {10, 20, 99};
90+
r = segmented_mismatch(sv.begin(), sv.end(), ref_fail);
91+
BOOST_TEST(r.first != sv.end());
92+
BOOST_TEST_EQ(*r.first, 30);
93+
BOOST_TEST_EQ(*r.second, 99);
94+
}
95+
96+
void test_mismatch_non_segmented()
97+
{
98+
std::vector<int> v;
99+
v.push_back(1); v.push_back(2); v.push_back(3);
100+
101+
int ref_match[] = {1, 2, 3};
102+
typedef std::vector<int>::iterator vec_it;
103+
std::pair<vec_it, int*> r = segmented_mismatch(v.begin(), v.end(), ref_match);
104+
BOOST_TEST(r.first == v.end());
105+
106+
int ref_fail[] = {1, 2, 99};
107+
r = segmented_mismatch(v.begin(), v.end(), ref_fail);
108+
BOOST_TEST(r.first != v.end());
109+
BOOST_TEST_EQ(*r.first, 3);
110+
BOOST_TEST_EQ(*r.second, 99);
111+
}
112+
113+
void test_mismatch_sentinel_segmented()
114+
{
115+
test_detail::seg_vector<int> sv;
116+
int a1[] = {1, 2, 3};
117+
int a2[] = {4, 5};
118+
int a3[] = {6, 7, 8, 9};
119+
sv.add_segment_range(a1, a1 + 3);
120+
sv.add_segment_range(a2, a2 + 2);
121+
sv.add_segment_range(a3, a3 + 4);
122+
123+
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
124+
typedef test_detail::seg_vector<int>::iterator seg_it;
125+
std::pair<seg_it, int*> r =
126+
segmented_mismatch(sv.begin(), test_detail::make_sentinel(sv.end()), ref);
127+
BOOST_TEST(r.first == sv.end());
128+
BOOST_TEST(r.second == ref + 9);
129+
}
130+
131+
void test_mismatch_sentinel_non_segmented()
132+
{
133+
std::vector<int> v;
134+
v.push_back(1); v.push_back(2); v.push_back(3);
135+
136+
int ref_match[] = {1, 2, 3};
137+
typedef std::vector<int>::iterator vec_it;
138+
std::pair<vec_it, int*> r =
139+
segmented_mismatch(v.begin(), test_detail::make_sentinel(v.end()), ref_match);
140+
BOOST_TEST(r.first == v.end());
141+
142+
int ref_fail[] = {1, 2, 99};
143+
r = segmented_mismatch(v.begin(), test_detail::make_sentinel(v.end()), ref_fail);
144+
BOOST_TEST(r.first != v.end());
145+
BOOST_TEST_EQ(*r.first, 3);
146+
BOOST_TEST_EQ(*r.second, 99);
147+
}
148+
149+
void test_mismatch_seg2()
150+
{
151+
test_detail::seg2_vector<int> sv2;
152+
int a1[] = {1, 2, 3};
153+
int a2[] = {4, 5};
154+
int a3[] = {6, 7, 8, 9};
155+
sv2.add_flat_segment_range(a1, a1 + 3);
156+
sv2.add_flat_segment_range(a2, a2 + 2);
157+
sv2.add_flat_segment_range(a3, a3 + 4);
158+
159+
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
160+
typedef test_detail::seg2_vector<int>::iterator seg2_it;
161+
std::pair<seg2_it, int*> r = segmented_mismatch(sv2.begin(), sv2.end(), ref);
162+
BOOST_TEST(r.first == sv2.end());
163+
164+
int ref_bad[] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
165+
r = segmented_mismatch(sv2.begin(), sv2.end(), ref_bad);
166+
BOOST_TEST(r.first != sv2.end());
167+
BOOST_TEST_EQ(*r.first, 9);
168+
BOOST_TEST_EQ(*r.second, 0);
169+
}
170+
171+
int main()
172+
{
173+
test_mismatch_matching();
174+
test_mismatch_found();
175+
test_mismatch_first_segment();
176+
test_mismatch_empty();
177+
test_mismatch_single_segment();
178+
test_mismatch_non_segmented();
179+
test_mismatch_sentinel_segmented();
180+
test_mismatch_sentinel_non_segmented();
181+
test_mismatch_seg2();
182+
return boost::report_errors();
183+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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+
#ifndef BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_HPP
11+
#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_HPP
12+
13+
#ifndef BOOST_CONFIG_HPP
14+
# include <boost/config.hpp>
15+
#endif
16+
17+
#if defined(BOOST_HAS_PRAGMA_ONCE)
18+
# pragma once
19+
#endif
20+
21+
#include <boost/container/detail/config_begin.hpp>
22+
#include <boost/container/detail/workaround.hpp>
23+
#include <boost/container/experimental/segmented_iterator_traits.hpp>
24+
#include <utility>
25+
26+
namespace boost {
27+
namespace container {
28+
29+
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
30+
std::pair<InpIter1, InpIter2> segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred);
31+
32+
template <class InpIter1, class Sent, class InpIter2>
33+
std::pair<InpIter1, InpIter2> segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2);
34+
35+
namespace detail_algo {
36+
37+
struct mismatch_equal
38+
{
39+
template <class T, class U>
40+
BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const U& b) const { return a == b; }
41+
};
42+
43+
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
44+
bool mismatch_scan(InpIter1& first1_out, Sent last1, InpIter2& first2_out, BinaryPred pred)
45+
{
46+
InpIter1 first1 = first1_out;
47+
InpIter2 first2 = first2_out;
48+
bool all_match = true;
49+
50+
for (; first1 != last1; ++first1, ++first2) {
51+
if (!pred(*first1, *first2)) {
52+
all_match = false;
53+
break;
54+
}
55+
}
56+
57+
first1_out = first1;
58+
first2_out = first2;
59+
return all_match;
60+
}
61+
62+
template <class SegIter, class InpIter2, class OutIter1, class BinaryPred>
63+
bool segmented_mismatch_ref
64+
(SegIter first1, SegIter last1, InpIter2& first2, OutIter1& mismatch1, BinaryPred pred, segmented_iterator_tag)
65+
{
66+
typedef segmented_iterator_traits<SegIter> traits;
67+
typedef typename traits::local_iterator local_iterator;
68+
typedef typename traits::segment_iterator segment_iterator;
69+
70+
segment_iterator sfirst = traits::segment(first1);
71+
segment_iterator slast = traits::segment(last1);
72+
73+
if(sfirst == slast) {
74+
local_iterator lf = traits::local(first1);
75+
if(!(mismatch_scan)(lf, traits::local(last1), first2, pred)) {
76+
mismatch1 = traits::compose(sfirst, lf);
77+
return false;
78+
}
79+
}
80+
else {
81+
{
82+
local_iterator lf = traits::local(first1);
83+
if(!(mismatch_scan)(lf, traits::end(sfirst), first2, pred)) {
84+
mismatch1 = traits::compose(sfirst, lf);
85+
return false;
86+
}
87+
}
88+
for(++sfirst; sfirst != slast; ++sfirst) {
89+
local_iterator lb = traits::begin(sfirst);
90+
if(!(mismatch_scan)(lb, traits::end(sfirst), first2, pred)) {
91+
mismatch1 = traits::compose(sfirst, lb);
92+
return false;
93+
}
94+
}
95+
{
96+
local_iterator lb = traits::begin(sfirst);
97+
if(!(mismatch_scan)(lb, traits::local(last1), first2, pred)) {
98+
mismatch1 = traits::compose(sfirst, lb);
99+
return false;
100+
}
101+
}
102+
}
103+
return true;
104+
}
105+
106+
template <class InpIter1, class Sent, class InpIter2, class OutIter1, class BinaryPred, class Tag>
107+
typename algo_enable_if_c<
108+
!Tag::value || is_sentinel<Sent, InpIter1>::value, bool>::type
109+
segmented_mismatch_ref(InpIter1 first1, Sent last1, InpIter2& first2_out, OutIter1& mismatch1, BinaryPred pred, Tag)
110+
{
111+
InpIter2 first2 = first2_out;
112+
bool all_match = true;
113+
114+
for (; first1 != last1; ++first1, ++first2) {
115+
if (!pred(*first1, *first2)) {
116+
mismatch1 = first1;
117+
all_match = false;
118+
break;
119+
}
120+
}
121+
mismatch1 = first1;
122+
first2_out = first2;
123+
return all_match;
124+
}
125+
126+
} // namespace detail_algo
127+
128+
//! Returns a pair of iterators to the first elements where
129+
//! \c pred(*it1, *it2) is false in [first1, last1) and the range
130+
//! starting at \c first2, or {last1, first2 + N} if all match.
131+
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
132+
BOOST_CONTAINER_FORCEINLINE std::pair<InpIter1, InpIter2>
133+
segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred)
134+
{
135+
typedef segmented_iterator_traits<InpIter1> traits;
136+
InpIter1 mismatch1(last1);
137+
detail_algo::segmented_mismatch_ref
138+
(first1, last1, first2, mismatch1, pred, typename traits::is_segmented_iterator());
139+
return std::pair<InpIter1, InpIter2>(mismatch1, first2);
140+
}
141+
142+
//! Returns a pair of iterators to the first mismatching elements
143+
//! in [first1, last1) and the range starting at \c first2, or
144+
//! {last1, first2 + N} if all elements match.
145+
template <class InpIter1, class Sent, class InpIter2>
146+
BOOST_CONTAINER_FORCEINLINE std::pair<InpIter1, InpIter2>
147+
segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2)
148+
{
149+
return boost::container::segmented_mismatch(first1, last1, first2, detail_algo::mismatch_equal());
150+
}
151+
152+
} // namespace container
153+
} // namespace boost
154+
155+
#include <boost/container/detail/config_end.hpp>
156+
157+
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_HPP

0 commit comments

Comments
 (0)