mirror of
https://github.com/boostorg/container.git
synced 2026-07-06 19:10:47 +02:00
Reimplemented to avoid aliasing issues.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user