mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 10:50:47 +02:00
Implement segmented_equal without relying in mismatch, as the implementation is slower in some compilers.
This commit is contained in:
@@ -125,6 +125,90 @@ void test_equal_seg2()
|
||||
BOOST_TEST(!segmented_equal(sv2.begin(), sv2.end(), ref_bad));
|
||||
}
|
||||
|
||||
void test_equal_seg_to_seg()
|
||||
{
|
||||
test_detail::seg_vector<int> sv1;
|
||||
int a1[] = {1, 2, 3};
|
||||
int a2[] = {4, 5};
|
||||
int a3[] = {6, 7, 8, 9};
|
||||
sv1.add_segment_range(a1, a1 + 3);
|
||||
sv1.add_segment_range(a2, a2 + 2);
|
||||
sv1.add_segment_range(a3, a3 + 4);
|
||||
|
||||
test_detail::seg_vector<int> sv2;
|
||||
int b1[] = {1, 2};
|
||||
int b2[] = {3, 4, 5, 6};
|
||||
int b3[] = {7, 8, 9};
|
||||
sv2.add_segment_range(b1, b1 + 2);
|
||||
sv2.add_segment_range(b2, b2 + 4);
|
||||
sv2.add_segment_range(b3, b3 + 3);
|
||||
|
||||
BOOST_TEST(segmented_equal(sv1.begin(), sv1.end(), sv2.begin()));
|
||||
}
|
||||
|
||||
void test_equal_seg_to_seg_mismatch()
|
||||
{
|
||||
test_detail::seg_vector<int> sv1;
|
||||
int a1[] = {1, 2, 3};
|
||||
int a2[] = {4, 5};
|
||||
sv1.add_segment_range(a1, a1 + 3);
|
||||
sv1.add_segment_range(a2, a2 + 2);
|
||||
|
||||
test_detail::seg_vector<int> sv2;
|
||||
int b1[] = {1, 2};
|
||||
int b2[] = {3, 4, 99};
|
||||
sv2.add_segment_range(b1, b1 + 2);
|
||||
sv2.add_segment_range(b2, b2 + 3);
|
||||
|
||||
BOOST_TEST(!segmented_equal(sv1.begin(), sv1.end(), sv2.begin()));
|
||||
}
|
||||
|
||||
void test_equal_seg2_to_seg2()
|
||||
{
|
||||
test_detail::seg2_vector<int> sv1;
|
||||
int a1[] = {1, 2, 3};
|
||||
int a2[] = {4, 5};
|
||||
int a3[] = {6, 7, 8, 9};
|
||||
sv1.add_flat_segment_range(a1, a1 + 3);
|
||||
sv1.add_flat_segment_range(a2, a2 + 2);
|
||||
sv1.add_flat_segment_range(a3, a3 + 4);
|
||||
|
||||
test_detail::seg2_vector<int> sv2;
|
||||
int b1[] = {1, 2};
|
||||
int b2[] = {3, 4, 5, 6};
|
||||
int b3[] = {7, 8, 9};
|
||||
sv2.add_flat_segment_range(b1, b1 + 2);
|
||||
sv2.add_flat_segment_range(b2, b2 + 4);
|
||||
sv2.add_flat_segment_range(b3, b3 + 3);
|
||||
|
||||
BOOST_TEST(segmented_equal(sv1.begin(), sv1.end(), sv2.begin()));
|
||||
|
||||
test_detail::seg2_vector<int> sv3;
|
||||
int c1[] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
|
||||
sv3.add_flat_segment_range(c1, c1 + 9);
|
||||
|
||||
BOOST_TEST(!segmented_equal(sv1.begin(), sv1.end(), sv3.begin()));
|
||||
}
|
||||
|
||||
void test_equal_seg_to_seg_misaligned()
|
||||
{
|
||||
test_detail::seg_vector<int> sv1;
|
||||
int a1[] = {10};
|
||||
int a2[] = {20, 30};
|
||||
int a3[] = {40, 50, 60};
|
||||
sv1.add_segment_range(a1, a1 + 1);
|
||||
sv1.add_segment_range(a2, a2 + 2);
|
||||
sv1.add_segment_range(a3, a3 + 3);
|
||||
|
||||
test_detail::seg_vector<int> sv2;
|
||||
int b1[] = {10, 20, 30, 40};
|
||||
int b2[] = {50, 60};
|
||||
sv2.add_segment_range(b1, b1 + 4);
|
||||
sv2.add_segment_range(b2, b2 + 2);
|
||||
|
||||
BOOST_TEST(segmented_equal(sv1.begin(), sv1.end(), sv2.begin()));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_equal_matching();
|
||||
@@ -136,5 +220,9 @@ int main()
|
||||
test_equal_sentinel_segmented();
|
||||
test_equal_sentinel_non_segmented();
|
||||
test_equal_seg2();
|
||||
test_equal_seg_to_seg();
|
||||
test_equal_seg_to_seg_mismatch();
|
||||
test_equal_seg2_to_seg2();
|
||||
test_equal_seg_to_seg_misaligned();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -21,18 +21,280 @@
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/workaround.hpp>
|
||||
#include <boost/container/experimental/segmented_iterator_traits.hpp>
|
||||
#include <boost/container/experimental/segmented_mismatch.hpp>
|
||||
#include <boost/container/detail/iterators.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
|
||||
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
|
||||
bool segmented_equal(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred);
|
||||
|
||||
template <class InpIter1, class Sent, class InpIter2>
|
||||
bool segmented_equal(InpIter1 first1, Sent last1, InpIter2 first2);
|
||||
|
||||
namespace detail_algo {
|
||||
|
||||
struct equal_pred
|
||||
{
|
||||
template <class T, class U>
|
||||
BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const U& b) const { return a == b; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Bounded iter2 helper: compares source [first1, last1) against
|
||||
// [iter2_first, iter2_last), stopping when source, iter2, or a mismatch
|
||||
// is encountered.
|
||||
// Advances first1 (by reference) so the caller knows how far we got.
|
||||
// Advances iter2_first (by reference) for the same reason.
|
||||
// Recursively walks iter2 segments when iter2 is segmented.
|
||||
//
|
||||
// When iter2_last is unreachable_sentinel_t the segment-boundary check
|
||||
// is optimised away, giving the same code as an unbounded loop.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
|
||||
|
||||
template <class RASrcIter, class Iter2, class Iter2Sent, class BinaryPred>
|
||||
bool segmented_equal_iter2_bounded
|
||||
(RASrcIter &first1_out, RASrcIter last1, Iter2 &iter2_first, Iter2Sent iter2_last, BinaryPred pred,
|
||||
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
|
||||
{
|
||||
typedef typename iterator_traits<RASrcIter>::difference_type difference_type;
|
||||
RASrcIter first1 = first1_out;
|
||||
Iter2 first2 = iter2_first;
|
||||
|
||||
difference_type n = last1 - first1;
|
||||
|
||||
while(n >= difference_type(4)) {
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
switch(n) {
|
||||
case 3:
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
BOOST_FALLTHROUGH;
|
||||
case 2:
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
BOOST_FALLTHROUGH;
|
||||
case 1:
|
||||
if(first2 == iter2_last) goto out_path; if(!pred(*first1, *first2)) goto out_path; ++first1; ++first2;
|
||||
BOOST_FALLTHROUGH;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
out_path:
|
||||
first1_out = first1;
|
||||
iter2_first = first2;
|
||||
return (first1 == last1) || (first2 == iter2_last);
|
||||
}
|
||||
|
||||
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
|
||||
|
||||
template <class SrcIter, class Sent, class Iter2, class Iter2Sent, class BinaryPred, class Iter2Tag, class SrcCat>
|
||||
typename algo_enable_if_c<!Iter2Tag::value, bool>::type
|
||||
segmented_equal_iter2_bounded
|
||||
(SrcIter &first1_out, Sent last1, Iter2 &iter2_first, Iter2Sent iter2_last, BinaryPred pred, Iter2Tag, SrcCat)
|
||||
{
|
||||
SrcIter first1 = first1_out;
|
||||
Iter2 first2 = iter2_first;
|
||||
|
||||
for(; first1 != last1; ++first1) {
|
||||
if(first2 == iter2_last)
|
||||
goto out_path;
|
||||
if(!pred(*first1, *first2)) {
|
||||
first1_out = first1;
|
||||
iter2_first = first2;
|
||||
return false;
|
||||
}
|
||||
++first2;
|
||||
}
|
||||
out_path:
|
||||
first1_out = first1;
|
||||
iter2_first = first2;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SrcIter, class Sent, class SegIter2, class BinaryPred, class SrcCat>
|
||||
bool segmented_equal_iter2_bounded
|
||||
(SrcIter &first1, Sent last1, SegIter2 &iter2_first_out, SegIter2 iter2_last, BinaryPred pred,
|
||||
segmented_iterator_tag, SrcCat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter2> iter2_traits;
|
||||
typedef typename iter2_traits::local_iterator iter2_local_iterator;
|
||||
typedef typename iter2_traits::segment_iterator iter2_segment_iterator;
|
||||
typedef typename segmented_iterator_traits<iter2_local_iterator>::is_segmented_iterator iter2_is_local_seg_t;
|
||||
|
||||
iter2_segment_iterator sfirst = iter2_traits::segment(iter2_first_out);
|
||||
const iter2_segment_iterator slast = iter2_traits::segment(iter2_last);
|
||||
|
||||
if(sfirst == slast) {
|
||||
iter2_local_iterator loc2 = iter2_traits::local(iter2_first_out);
|
||||
bool r = (segmented_equal_iter2_bounded)
|
||||
(first1, last1, loc2, iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat());
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
iter2_local_iterator loc2 = iter2_traits::local(iter2_first_out);
|
||||
if(!(segmented_equal_iter2_bounded)
|
||||
(first1, last1, loc2, iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat())) {
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return false;
|
||||
}
|
||||
if(first1 == last1) {
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return true;
|
||||
}
|
||||
|
||||
for(++sfirst; sfirst != slast; ++sfirst) {
|
||||
loc2 = iter2_traits::begin(sfirst);
|
||||
if(!(segmented_equal_iter2_bounded)
|
||||
(first1, last1, loc2, iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat())) {
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return false;
|
||||
}
|
||||
if(first1 == last1) {
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
loc2 = iter2_traits::begin(slast);
|
||||
bool r = (segmented_equal_iter2_bounded)
|
||||
(first1, last1, loc2, iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat());
|
||||
iter2_first_out = iter2_traits::compose(sfirst, loc2);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Iter2 dispatch: routes to bounded helper.
|
||||
// Non-segmented iter2: single unbounded call (unreachable_sentinel_t).
|
||||
// Segmented iter2: loop over iter2 segments, bounded per segment.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class SrcIter, class Sent, class InpIter2, class BinaryPred, class Cat>
|
||||
BOOST_CONTAINER_FORCEINLINE bool segmented_equal_iter2_dispatch
|
||||
(SrcIter first1, Sent last1, InpIter2 &first2, BinaryPred pred,
|
||||
const non_segmented_iterator_tag &, Cat)
|
||||
{
|
||||
bool r = (segmented_equal_iter2_bounded)
|
||||
(first1, last1, first2, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat());
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class SrcIter, class Sent, class SegIter2, class BinaryPred, class Cat>
|
||||
bool segmented_equal_iter2_dispatch
|
||||
(SrcIter first1, Sent last1, SegIter2 &first2_out, BinaryPred pred,
|
||||
const segmented_iterator_tag &, Cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter2> iter2_traits;
|
||||
typedef typename iter2_traits::local_iterator iter2_local_iterator;
|
||||
typedef typename iter2_traits::segment_iterator iter2_segment_iterator;
|
||||
typedef typename segmented_iterator_traits<iter2_local_iterator>::is_segmented_iterator iter2_is_local_seg_t;
|
||||
|
||||
if(first1 == last1)
|
||||
return true;
|
||||
|
||||
iter2_segment_iterator seg2 = iter2_traits::segment(first2_out);
|
||||
iter2_local_iterator loc2 = iter2_traits::local(first2_out);
|
||||
|
||||
while(first1 != last1) {
|
||||
iter2_local_iterator end2 = iter2_traits::end(seg2);
|
||||
if(!(segmented_equal_iter2_bounded)
|
||||
(first1, last1, loc2, end2, pred, iter2_is_local_seg_t(), Cat())) {
|
||||
first2_out = iter2_traits::compose(seg2, loc2);
|
||||
return false;
|
||||
}
|
||||
if(first1 != last1) {
|
||||
++seg2;
|
||||
loc2 = iter2_traits::begin(seg2);
|
||||
}
|
||||
}
|
||||
first2_out = iter2_traits::compose(seg2, loc2);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Source dispatch: walks the source (first1) segments
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class SrcIter, class Sent, class InpIter2, class BinaryPred, class Tag, class Cat>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
typename algo_enable_if_c
|
||||
< !Tag::value || is_sentinel<Sent, SrcIter>::value
|
||||
, bool
|
||||
>::type
|
||||
segmented_equal_dispatch(SrcIter first1, Sent last1, InpIter2 &first2_out, BinaryPred pred, Tag, Cat)
|
||||
{
|
||||
#if !defined(BOOST_CONTAINER_DISABLE_SEGMENTED_OUTPUT)
|
||||
typedef segmented_iterator_traits<InpIter2> iter2_traits;
|
||||
return (segmented_equal_iter2_dispatch)
|
||||
(first1, last1, first2_out, pred, typename iter2_traits::is_segmented_iterator(), Cat());
|
||||
#else
|
||||
return (segmented_equal_iter2_dispatch)
|
||||
(first1, last1, first2_out, pred, non_segmented_iterator_tag(), Cat());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class SegIter, class InpIter2, class BinaryPred, class Cat>
|
||||
bool segmented_equal_dispatch
|
||||
(SegIter first1, SegIter last1, InpIter2 &first2, BinaryPred pred, segmented_iterator_tag, Cat)
|
||||
{
|
||||
typedef segmented_iterator_traits<SegIter> 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;
|
||||
typedef typename iterator_traits<local_iterator>::iterator_category local_cat_t;
|
||||
|
||||
segment_iterator sfirst = traits::segment(first1);
|
||||
segment_iterator const slast = traits::segment(last1);
|
||||
|
||||
if(sfirst == slast) {
|
||||
return (segmented_equal_dispatch)
|
||||
(traits::local(first1), traits::local(last1), first2, pred, is_local_seg_t(), local_cat_t());
|
||||
}
|
||||
else {
|
||||
if(!(segmented_equal_dispatch)
|
||||
(traits::local(first1), traits::end(sfirst), first2, pred, is_local_seg_t(), local_cat_t()))
|
||||
return false;
|
||||
|
||||
for(++sfirst; sfirst != slast; ++sfirst) {
|
||||
if(!(segmented_equal_dispatch)
|
||||
(traits::begin(sfirst), traits::end(sfirst), first2, pred, is_local_seg_t(), local_cat_t()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return (segmented_equal_dispatch)
|
||||
(traits::begin(slast), traits::local(last1), first2, pred, is_local_seg_t(), local_cat_t());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail_algo
|
||||
|
||||
//! Returns \c true if elements in [first1, last1) are equal to the
|
||||
//! range starting at \c first2. Exploits segmentation on the first range.
|
||||
//! range starting at \c first2 according to \c pred.
|
||||
//! Exploits segmentation on both ranges.
|
||||
template <class InpIter1, class Sent, class InpIter2, class BinaryPred>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
bool segmented_equal(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred)
|
||||
{
|
||||
typedef segmented_iterator_traits<InpIter1> traits;
|
||||
return detail_algo::segmented_equal_dispatch
|
||||
(first1, last1, first2, pred, typename traits::is_segmented_iterator(), typename iterator_traits<InpIter1>::iterator_category());
|
||||
}
|
||||
|
||||
//! Returns \c true if elements in [first1, last1) are equal to the
|
||||
//! range starting at \c first2. Exploits segmentation on both ranges.
|
||||
template <class InpIter1, class Sent, class InpIter2>
|
||||
BOOST_CONTAINER_FORCEINLINE
|
||||
bool segmented_equal(InpIter1 first1, Sent last1, InpIter2 first2)
|
||||
{
|
||||
return (segmented_mismatch)(first1, last1, first2).first == last1;
|
||||
return boost::container::segmented_equal(first1, last1, first2, detail_algo::equal_pred());
|
||||
}
|
||||
|
||||
} // namespace container
|
||||
|
||||
Reference in New Issue
Block a user