mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 14:50:46 +02:00
Add segmented_mismatch algorithm
This commit is contained in:
@@ -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)");
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user