Add segmented_mismatch algorithm

This commit is contained in:
Ion Gaztañaga
2026-03-17 21:48:13 +01:00
parent cdfda037a6
commit 18edb763fb
3 changed files with 377 additions and 0 deletions
+37
View File
@@ -37,6 +37,7 @@
#include <boost/container/experimental/segmented_is_partitioned.hpp>
#include <boost/container/experimental/segmented_is_sorted.hpp>
#include <boost/container/experimental/segmented_merge.hpp>
#include <boost/container/experimental/segmented_mismatch.hpp>
#include <boost/container/experimental/segmented_is_sorted_until.hpp>
#include <boost/container/experimental/segmented_partition.hpp>
#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)
print_ratio("merge", cname, r1, r2);
}
template<class C>
void bench_mismatch(C c, C& c2, std::size_t iters, const char* cname,
const char* label)
{
int result = 0;
cpu_timer t1;
for (std::size_t i = 0; i < iters; ++i) {
t1.resume();
result = (std::mismatch(c.begin(), c.end(), c2.begin()).first == c.end()) ? 1 : 0;
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) {
t2.resume();
result = (bc::segmented_mismatch(c.begin(), c.end(), c2.begin()).first == c.end()) ? 1 : 0;
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_swap_ranges(C c, std::size_t iters, const char* cname)
{
@@ -1663,6 +1690,16 @@ void run_all(const C& c, std::size_t iters, const char* cname)
bench_merge(c, c2, iters, cname);
}
//mismatch
{
C c2(c);
bench_mismatch(c, c2, iters, cname, "mismatch(hit)");
typename C::iterator last = c2.end();
--last;
*last = VT(-1);
bench_mismatch(c, c2, iters, cname, "mismatch(miss)");
}
//partition
bench_partition(c, iters, cname, is_odd<VT>(), "partition(hit)");
bench_partition(c, iters, cname, is_negative<VT>(), "partition(miss)");
+183
View File
@@ -0,0 +1,183 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_mismatch.hpp>
#include <boost/core/lightweight_test.hpp>
#include "segmented_test_helper.hpp"
#include <vector>
#include <utility>
using namespace boost::container;
void test_mismatch_matching()
{
test_detail::seg_vector<int> 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);
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
BOOST_TEST(r.first == sv.end());
BOOST_TEST(r.second == ref + 9);
}
void test_mismatch_found()
{
test_detail::seg_vector<int> sv;
int a1[] = {1, 2, 3};
int a2[] = {4, 5};
sv.add_segment_range(a1, a1 + 3);
sv.add_segment_range(a2, a2 + 2);
int ref[] = {1, 2, 3, 4, 99};
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
BOOST_TEST(r.first != sv.end());
BOOST_TEST_EQ(*r.first, 5);
BOOST_TEST_EQ(*r.second, 99);
}
void test_mismatch_first_segment()
{
test_detail::seg_vector<int> sv;
int a1[] = {1, 2, 3};
int a2[] = {4, 5};
sv.add_segment_range(a1, a1 + 3);
sv.add_segment_range(a2, a2 + 2);
int ref[] = {1, 99, 3, 4, 5};
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref);
BOOST_TEST(r.first != sv.end());
BOOST_TEST_EQ(*r.first, 2);
BOOST_TEST_EQ(*r.second, 99);
}
void test_mismatch_empty()
{
test_detail::seg_vector<int> sv;
int dummy = 0;
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), &dummy);
BOOST_TEST(r.first == sv.end());
BOOST_TEST(r.second == &dummy);
}
void test_mismatch_single_segment()
{
test_detail::seg_vector<int> sv;
int a[] = {10, 20, 30};
sv.add_segment_range(a, a + 3);
int ref_match[] = {10, 20, 30};
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r = segmented_mismatch(sv.begin(), sv.end(), ref_match);
BOOST_TEST(r.first == sv.end());
int ref_fail[] = {10, 20, 99};
r = segmented_mismatch(sv.begin(), sv.end(), ref_fail);
BOOST_TEST(r.first != sv.end());
BOOST_TEST_EQ(*r.first, 30);
BOOST_TEST_EQ(*r.second, 99);
}
void test_mismatch_non_segmented()
{
std::vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3);
int ref_match[] = {1, 2, 3};
typedef std::vector<int>::iterator vec_it;
std::pair<vec_it, int*> r = segmented_mismatch(v.begin(), v.end(), ref_match);
BOOST_TEST(r.first == v.end());
int ref_fail[] = {1, 2, 99};
r = segmented_mismatch(v.begin(), v.end(), ref_fail);
BOOST_TEST(r.first != v.end());
BOOST_TEST_EQ(*r.first, 3);
BOOST_TEST_EQ(*r.second, 99);
}
void test_mismatch_sentinel_segmented()
{
test_detail::seg_vector<int> 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);
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
typedef test_detail::seg_vector<int>::iterator seg_it;
std::pair<seg_it, int*> r =
segmented_mismatch(sv.begin(), test_detail::make_sentinel(sv.end()), ref);
BOOST_TEST(r.first == sv.end());
BOOST_TEST(r.second == ref + 9);
}
void test_mismatch_sentinel_non_segmented()
{
std::vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3);
int ref_match[] = {1, 2, 3};
typedef std::vector<int>::iterator vec_it;
std::pair<vec_it, int*> r =
segmented_mismatch(v.begin(), test_detail::make_sentinel(v.end()), ref_match);
BOOST_TEST(r.first == v.end());
int ref_fail[] = {1, 2, 99};
r = segmented_mismatch(v.begin(), test_detail::make_sentinel(v.end()), ref_fail);
BOOST_TEST(r.first != v.end());
BOOST_TEST_EQ(*r.first, 3);
BOOST_TEST_EQ(*r.second, 99);
}
void test_mismatch_seg2()
{
test_detail::seg2_vector<int> 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);
int ref[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
typedef test_detail::seg2_vector<int>::iterator seg2_it;
std::pair<seg2_it, int*> r = segmented_mismatch(sv2.begin(), sv2.end(), ref);
BOOST_TEST(r.first == sv2.end());
int ref_bad[] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
r = segmented_mismatch(sv2.begin(), sv2.end(), ref_bad);
BOOST_TEST(r.first != sv2.end());
BOOST_TEST_EQ(*r.first, 9);
BOOST_TEST_EQ(*r.second, 0);
}
int main()
{
test_mismatch_matching();
test_mismatch_found();
test_mismatch_first_segment();
test_mismatch_empty();
test_mismatch_single_segment();
test_mismatch_non_segmented();
test_mismatch_sentinel_segmented();
test_mismatch_sentinel_non_segmented();
test_mismatch_seg2();
return boost::report_errors();
}
@@ -0,0 +1,157 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_MISMATCH_HPP
#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_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/experimental/segmented_iterator_traits.hpp>
#include <utility>
namespace boost {
namespace container {
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
std::pair<InpIter1, InpIter2> segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred);
template <class InpIter1, class Sent, class InpIter2>
std::pair<InpIter1, InpIter2> segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2);
namespace detail_algo {
struct mismatch_equal
{
template <class T, class U>
BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const U& b) const { return a == b; }
};
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
bool mismatch_scan(InpIter1& first1_out, Sent last1, InpIter2& first2_out, BinaryPred pred)
{
InpIter1 first1 = first1_out;
InpIter2 first2 = first2_out;
bool all_match = true;
for (; first1 != last1; ++first1, ++first2) {
if (!pred(*first1, *first2)) {
all_match = false;
break;
}
}
first1_out = first1;
first2_out = first2;
return all_match;
}
template <class SegIter, class InpIter2, class OutIter1, class BinaryPred>
bool segmented_mismatch_ref
(SegIter first1, SegIter last1, InpIter2& first2, OutIter1& mismatch1, BinaryPred pred, segmented_iterator_tag)
{
typedef segmented_iterator_traits<SegIter> traits;
typedef typename traits::local_iterator local_iterator;
typedef typename traits::segment_iterator segment_iterator;
segment_iterator sfirst = traits::segment(first1);
segment_iterator slast = traits::segment(last1);
if(sfirst == slast) {
local_iterator lf = traits::local(first1);
if(!(mismatch_scan)(lf, traits::local(last1), first2, pred)) {
mismatch1 = traits::compose(sfirst, lf);
return false;
}
}
else {
{
local_iterator lf = traits::local(first1);
if(!(mismatch_scan)(lf, traits::end(sfirst), first2, pred)) {
mismatch1 = traits::compose(sfirst, lf);
return false;
}
}
for(++sfirst; sfirst != slast; ++sfirst) {
local_iterator lb = traits::begin(sfirst);
if(!(mismatch_scan)(lb, traits::end(sfirst), first2, pred)) {
mismatch1 = traits::compose(sfirst, lb);
return false;
}
}
{
local_iterator lb = traits::begin(sfirst);
if(!(mismatch_scan)(lb, traits::local(last1), first2, pred)) {
mismatch1 = traits::compose(sfirst, lb);
return false;
}
}
}
return true;
}
template <class InpIter1, class Sent, class InpIter2, class OutIter1, class BinaryPred, class Tag>
typename algo_enable_if_c<
!Tag::value || is_sentinel<Sent, InpIter1>::value, bool>::type
segmented_mismatch_ref(InpIter1 first1, Sent last1, InpIter2& first2_out, OutIter1& mismatch1, BinaryPred pred, Tag)
{
InpIter2 first2 = first2_out;
bool all_match = true;
for (; first1 != last1; ++first1, ++first2) {
if (!pred(*first1, *first2)) {
mismatch1 = first1;
all_match = false;
break;
}
}
mismatch1 = first1;
first2_out = first2;
return all_match;
}
} // namespace detail_algo
//! 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.
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
BOOST_CONTAINER_FORCEINLINE std::pair<InpIter1, InpIter2>
segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred)
{
typedef segmented_iterator_traits<InpIter1> traits;
InpIter1 mismatch1(last1);
detail_algo::segmented_mismatch_ref
(first1, last1, first2, mismatch1, pred, typename traits::is_segmented_iterator());
return std::pair<InpIter1, InpIter2>(mismatch1, first2);
}
//! 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.
template <class InpIter1, class Sent, class InpIter2>
BOOST_CONTAINER_FORCEINLINE std::pair<InpIter1, InpIter2>
segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2)
{
return boost::container::segmented_mismatch(first1, last1, first2, detail_algo::mismatch_equal());
}
} // namespace container
} // namespace boost
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_HPP