////////////////////////////////////////////////////////////////////////////// // // (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 #endif #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include #include namespace boost { namespace container { template std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred); template std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2); template std::pair segmented_mismatch(InpIter1 first1, Sent1 last1, InpIter2 first2, Sent2 last2, BinaryPred pred); template std::pair segmented_mismatch(InpIter1 first1, Sent1 last1, InpIter2 first2, InpIter2 last2); namespace detail_algo { struct mismatch_equal { template BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const U& b) const { return a == b; } }; ////////////////////////////////////////////////////////////////////////////// // Bounded iter2 helper: compares source [first1, last1) against // [first2, iter2_last), stopping when source, iter2, or a mismatch // is encountered. // Returns segduo with the final positions of both iterators. // Recursively walks iter2 segments when iter2 is segmented. // // The caller can derive whether a mismatch was found: // if first1 != last1 && first2 != iter2_last, a mismatch was found. // // When iter2_last is unreachable_sentinel_t the segment-boundary check // is optimised away, giving the same code as an unbounded loop. ////////////////////////////////////////////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE typename algo_enable_if_c >::type segmented_mismatch_iter2_bounded (SrcIter first1, Sent last1, Iter2 first2, Iter2Sent iter2_last, BinaryPred pred, Iter2Tag, SrcCat) { BOOST_CONTAINER_SEGMENTED_UNROLL(4) for(; first1 != last1; ++first1) { if(first2 == iter2_last || !pred(*first1, *first2)) break; ++first2; } return segduo(first1, first2); } template BOOST_CONTAINER_FORCEINLINE typename iterator_enable_if_tag >::type segmented_mismatch_iter2_bounded (RASrcIter first1, RASrcIter last1, RAIter2 first2, RAIter2 iter2_last, BinaryPred pred, const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag) { typedef typename iterator_traits::difference_type difference_type; const difference_type src_n = last1 - first1; const difference_type iter2_n = difference_type(iter2_last - first2); const difference_type n = src_n < iter2_n ? src_n : iter2_n; return (segmented_mismatch_iter2_bounded)(first1, first1 + n, first2, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), src_tag); } template segduo segmented_mismatch_iter2_bounded (SrcIter first1, Sent last1, SegIter2 iter2_first, SegIter2 iter2_last, BinaryPred pred, segmented_iterator_tag, SrcCat) { typedef segmented_iterator_traits 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::is_segmented_iterator iter2_is_local_seg_t; iter2_segment_iterator sfirst = iter2_traits::segment(iter2_first); const iter2_segment_iterator slast = iter2_traits::segment(iter2_last); if(sfirst == slast) { segduo r = (segmented_mismatch_iter2_bounded) (first1, last1, iter2_traits::local(iter2_first), iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat()); return segduo(r.first, iter2_traits::compose(sfirst, r.second)); } else { segduo r = (segmented_mismatch_iter2_bounded) (first1, last1, iter2_traits::local(iter2_first), iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat()); first1 = r.first; iter2_local_iterator loc2 = r.second; if(first1 == last1 || loc2 != iter2_traits::end(sfirst)) return segduo(first1, iter2_traits::compose(sfirst, loc2)); for(++sfirst; sfirst != slast; ++sfirst) { r = (segmented_mismatch_iter2_bounded) (first1, last1, iter2_traits::begin(sfirst), iter2_traits::end(sfirst), pred, iter2_is_local_seg_t(), SrcCat()); first1 = r.first; loc2 = r.second; if(first1 == last1 || loc2 != iter2_traits::end(sfirst)) return segduo(first1, iter2_traits::compose(sfirst, loc2)); } r = (segmented_mismatch_iter2_bounded) (first1, last1, iter2_traits::begin(slast), iter2_traits::local(iter2_last), pred, iter2_is_local_seg_t(), SrcCat()); return segduo(r.first, iter2_traits::compose(sfirst, r.second)); } } ////////////////////////////////////////////////////////////////////////////// // Iter2 dispatch (segmented iter2 only): loops over iter2 segments, // bounded per segment. Used as the body of the unbounded-iter2 shim // of segmented_mismatch_iter2_bounded below. ////////////////////////////////////////////////////////////////////////////// template segduo segmented_mismatch_iter2_dispatch (SrcIter first1, Sent last1, SegIter2 first2, BinaryPred pred, const segmented_iterator_tag &, Cat) { typedef segmented_iterator_traits 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::is_segmented_iterator iter2_is_local_seg_t; if(first1 == last1) return segduo(first1, first2); iter2_segment_iterator seg2 = iter2_traits::segment(first2); iter2_local_iterator loc2 = iter2_traits::local(first2); while(first1 != last1) { iter2_local_iterator end2 = iter2_traits::end(seg2); segduo r = (segmented_mismatch_iter2_bounded) (first1, last1, loc2, end2, pred, iter2_is_local_seg_t(), Cat()); first1 = r.first; loc2 = r.second; if(first1 != last1 && loc2 != end2) return segduo(first1, iter2_traits::compose(seg2, loc2)); if(first1 != last1) { ++seg2; loc2 = iter2_traits::begin(seg2); } } return segduo(first1, iter2_traits::compose(seg2, loc2)); } ////////////////////////////////////////////////////////////////////////////// // Shim: segmented_mismatch_iter2_bounded overload for the combination // "segmented iter2 + unreachable_sentinel_t as iter2_last". The primary // segmented-iter2 overload (above) requires iter2_first and iter2_last to // share the same type, which prevents passing unreachable_sentinel_t // directly. This shim forwards to segmented_mismatch_iter2_dispatch, which // walks iter2 segments without needing a global iter2_last. // // With this shim in place, segmented_mismatch_bounded_dispatch can be // reused as the single implementation for the unbounded case, simply by // passing unreachable_sentinel_t as last2. ////////////////////////////////////////////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE segduo segmented_mismatch_iter2_bounded (SrcIter first1, Sent last1, SegIter2 iter2_first, unreachable_sentinel_t, BinaryPred pred, segmented_iterator_tag, SrcCat) { return (segmented_mismatch_iter2_dispatch) (first1, last1, iter2_first, pred, segmented_iterator_tag(), SrcCat()); } ////////////////////////////////////////////////////////////////////////////// // Fully bounded dispatch (two-range mismatch): walks [first1, last1) and // [first2, last2) in lock-step, recursive on both sides. Stops at the first // of: mismatch, source exhaustion (first1 == last1), or iter2 exhaustion // (first2 == last2). Returns segduo{final source, final iter2}. // // - The non-segmented-source leaf forwards to segmented_mismatch_iter2_bounded, // which already recurses on iter2 segmentation and has the random-access // unrolled fast path. // - The segmented-source overload mirrors the classic segmented walk but // threads last2 through the recursion and exits early when iter2 is // exhausted. // // This dispatch is also reused to implement the unbounded (three-iterator) // segmented_mismatch_dispatch by passing unreachable_sentinel_t as last2 // (the shim above handles the segmented-iter2 case for that sentinel). ////////////////////////////////////////////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE typename algo_enable_if_c< !Tag::value || is_sentinel::value, segduo >::type segmented_mismatch_bounded_dispatch (SrcIter first1, Sent last1, InpIter2 first2, Sent2 last2, BinaryPred pred, Tag, Cat) { #if !defined(BOOST_CONTAINER_DISABLE_MULTI_SEGMENTED_ALGO) typedef segmented_iterator_traits iter2_traits; return (segmented_mismatch_iter2_bounded) (first1, last1, first2, last2, pred, typename iter2_traits::is_segmented_iterator(), Cat()); #else return (segmented_mismatch_iter2_bounded) (first1, last1, first2, last2, pred, non_segmented_iterator_tag(), Cat()); #endif } template segduo segmented_mismatch_bounded_dispatch (SegIter first1, SegIter last1, InpIter2 first2, Sent2 last2, BinaryPred pred, segmented_iterator_tag, Cat) { typedef segmented_iterator_traits traits; typedef typename traits::local_iterator local_iterator; typedef typename traits::segment_iterator segment_iterator; typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; typedef typename iterator_traits::iterator_category local_cat_t; typedef segduo return_t; typedef segduo local_return_t; segment_iterator sfirst = traits::segment(first1); segment_iterator const slast = traits::segment(last1); if (sfirst == slast) { const local_iterator ll = traits::local(last1); local_return_t r = (segmented_mismatch_bounded_dispatch) (traits::local(first1), ll, first2, last2, pred, is_local_seg_t(), local_cat_t()); return return_t((r.first != ll) ? traits::compose(sfirst, r.first) : last1, r.second); } else { local_iterator le = traits::end(sfirst); local_return_t r = (segmented_mismatch_bounded_dispatch) (traits::local(first1), le, first2, last2, pred, is_local_seg_t(), local_cat_t()); // Early exit: stopped inside segment (mismatch) or iter2 exhausted. if (r.first != le || r.second == last2) return return_t(traits::compose(sfirst, r.first), r.second); for (++sfirst; sfirst != slast; ++sfirst) { le = traits::end(sfirst); r = (segmented_mismatch_bounded_dispatch) (traits::begin(sfirst), le, r.second, last2, pred, is_local_seg_t(), local_cat_t()); if (r.first != le || r.second == last2) return return_t(traits::compose(sfirst, r.first), r.second); } le = traits::local(last1); r = (segmented_mismatch_bounded_dispatch) (traits::begin(slast), le, r.second, last2, pred, is_local_seg_t(), local_cat_t()); return return_t((r.first != le) ? traits::compose(sfirst, r.first) : last1, r.second); } } } // 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. //! Exploits segmentation on both ranges. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2, BinaryPred pred) { typedef segmented_iterator_traits traits; segduo r = (detail_algo::segmented_mismatch_bounded_dispatch) ( first1, last1, first2, unreachable_sentinel_t(), pred , typename traits::is_segmented_iterator() , typename iterator_traits::iterator_category()); return std::pair(r.first, r.second); } //! 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. //! Exploits segmentation on both ranges. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent last1, InpIter2 first2) { return boost::container::segmented_mismatch(first1, last1, first2, detail_algo::mismatch_equal()); } //! Returns a pair of iterators to the first elements where //! \c pred(*it1, *it2) is false in [first1, last1) and [first2, last2), //! or {last1, last2} if all elements in the common prefix match. //! When the two ranges have different lengths, iteration stops at the end //! of the shorter range; the returned pair then points to the end of the //! shorter range and the corresponding position in the other range. //! Exploits segmentation on both ranges. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent1 last1, InpIter2 first2, Sent2 last2, BinaryPred pred) { typedef segmented_iterator_traits traits; segduo r = detail_algo::segmented_mismatch_bounded_dispatch (first1, last1, first2, last2, pred, typename traits::is_segmented_iterator(), typename iterator_traits::iterator_category()); return std::pair(r.first, r.second); } //! Returns a pair of iterators to the first mismatching elements in //! [first1, last1) and [first2, last2), or {last1, last2} if all elements //! in the common prefix match. When the two ranges have different lengths, //! iteration stops at the end of the shorter range. //! Exploits segmentation on both ranges. //! //! Note: \c last2 must have the same type as \c first2. To pass a sentinel //! type for the end of the second range, use the overload with an explicit //! predicate. template BOOST_CONTAINER_FORCEINLINE std::pair segmented_mismatch(InpIter1 first1, Sent1 last1, InpIter2 first2, InpIter2 last2) { return boost::container::segmented_mismatch (first1, last1, first2, last2, detail_algo::mismatch_equal()); } } // namespace container } // namespace boost #include #endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_MISMATCH_HPP