Reimplemented to avoid aliasing issues.

This commit is contained in:
Ion Gaztañaga
2026-05-04 16:03:32 +02:00
parent 0454dfe325
commit dd1308fd0e
@@ -20,19 +20,206 @@
#include <boost/container/detail/config_begin.hpp>
#include <boost/container/detail/workaround.hpp>
#include <boost/container/detail/compare_functors.hpp>
#include <boost/container/experimental/segmented_find_last_if.hpp>
#include <boost/container/detail/iterator.hpp>
#include <boost/container/experimental/segmented_iterator_traits.hpp>
namespace boost {
namespace container {
template <class FwdIt, class Sent, class T>
FwdIt segmented_find_last(FwdIt first, Sent last, const T& value);
namespace detail_algo {
//////////////////////////////////////////////
// Non-segmented scans
//////////////////////////////////////////////
template <class FwdIt, class Sent, class T>
BOOST_CONTAINER_FORCEINLINE
FwdIt find_last_scan(FwdIt first, Sent last, const T& value,
non_segmented_iterator_tag, const std::forward_iterator_tag&)
{
FwdIt result = last;
for (; first != last; ++first)
if (*first == value)
result = first;
return result;
}
template <class BidirIt, class T>
BOOST_CONTAINER_FORCEINLINE
BidirIt find_last_scan(BidirIt first, BidirIt last, const T& value,
non_segmented_iterator_tag, const std::bidirectional_iterator_tag&)
{
BidirIt cur = last;
while (cur != first) {
--cur;
if (*cur == value)
return cur;
}
return last;
}
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
template <class RAIter, class T>
BOOST_CONTAINER_FORCEINLINE
RAIter find_last_scan(RAIter first, RAIter const last, const T& value,
non_segmented_iterator_tag, const std::random_access_iterator_tag&)
{
typedef typename iterator_traits<RAIter>::difference_type difference_type;
RAIter cur = last;
difference_type n = cur - first;
while (n >= difference_type(4)) {
--cur;
if (*cur == value)
goto found;
--cur;
if (*cur == value)
goto found;
--cur;
if (*cur == value)
goto found;
--cur;
if (*cur == value)
goto found;
n -= 4;
}
switch(n) {
case 3:
--cur;
if (*cur == value)
goto found;
BOOST_FALLTHROUGH;
case 2:
--cur;
if (*cur == value)
goto found;
BOOST_FALLTHROUGH;
case 1:
--cur;
if (*cur == value)
goto found;
BOOST_FALLTHROUGH;
default:
break;
}
return last;
found:
return cur;
}
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
//////////////////////////////////////////////
// Segmented forward scan
//////////////////////////////////////////////
template <class SegIt, class T>
SegIt find_last_scan(SegIt first, SegIt last, const T& value,
segmented_iterator_tag, const std::forward_iterator_tag&)
{
typedef segmented_iterator_traits<SegIt> 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;
SegIt result = last;
segment_iterator sfirst = traits::segment(first);
const segment_iterator slast = traits::segment(last);
if (sfirst == slast) {
return traits::compose
(sfirst, find_last_scan(traits::local(first), traits::local(last), value, is_local_seg_t(), local_cat_t()));
}
else {
{ // First segment
const local_iterator le = traits::end(sfirst);
const local_iterator r = find_last_scan(traits::local(first), le, value, is_local_seg_t(), local_cat_t());
if (r != le)
result = traits::compose(sfirst, r);
}
// Middle segments
for (++sfirst; sfirst != slast; ++sfirst) {
const local_iterator le = traits::end(sfirst);
const local_iterator r = find_last_scan(traits::begin(sfirst), le, value, is_local_seg_t(), local_cat_t());
if (r != le)
result = traits::compose(sfirst, r);
}
// Last segment
return traits::compose
(sfirst, find_last_scan(traits::begin(slast), traits::local(last), value, is_local_seg_t(), local_cat_t()));
}
}
//////////////////////////////////////////////
// Segmented bidirectional scan
//////////////////////////////////////////////
template <class SegIt, class T>
SegIt find_last_scan(SegIt first, SegIt last, const T& value, segmented_iterator_tag, const std::bidirectional_iterator_tag&)
{
typedef segmented_iterator_traits<SegIt> 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 const sfirst = traits::segment(first);
segment_iterator slast = traits::segment(last);
const local_iterator ll = traits::local(last);
if (sfirst == slast) {
return traits::compose
(sfirst, find_last_scan(traits::local(first), ll, value, is_local_seg_t(), local_cat_t()));
}
{ // Last segment (partial): [begin(slast), local(last))
local_iterator r = find_last_scan(traits::begin(slast), ll, value, is_local_seg_t(), local_cat_t());
if (r != ll)
return traits::compose(slast, r);
}
// Middle segments in reverse
for (--slast; slast != sfirst; --slast) {
const local_iterator le = traits::end(slast);
const local_iterator r = find_last_scan(traits::begin(slast), le, value, is_local_seg_t(), local_cat_t());
if (r != le)
return traits::compose(slast, r);
}
{ // First segment (partial): [local(first), end(sfirst))
const local_iterator le = traits::end(sfirst);
const local_iterator r = find_last_scan(traits::local(first), le, value, is_local_seg_t(), local_cat_t());
if (r != le)
return traits::compose(sfirst, r);
}
return last;
}
//////////////////////////////////////////////
// Sentinel / generic fallback
//////////////////////////////////////////////
} // namespace detail_algo
//! Returns an iterator to the last element equal to \c value
//! in [first, last), or \c last if not found.
//! For bidirectional iterators, scans backward for early exit.
//! For forward iterators, scans the entire range and remembers
//! the last match.
template <class FwdIt, class Sent, class T>
BOOST_CONTAINER_FORCEINLINE
FwdIt segmented_find_last(FwdIt first, Sent last, const T& value)
{
return boost::container::segmented_find_last_if(first, last, equal_to_value<T>(value));
typedef detail_algo::sent_filter<FwdIt, Sent> sf;
return detail_algo::find_last_scan
( first, last, value, typename sf::seg_t(), typename sf::cat_t());
}
} // namespace container