Added segmented_find_last, segmented_find_last_if, segmented_find_last_if_not

This commit is contained in:
Ion Gaztañaga
2026-03-20 01:33:48 +01:00
parent 60761d2df4
commit 57ae7a82d3
7 changed files with 880 additions and 8 deletions
@@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FIND_LAST_HPP
#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_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/detail/compare_functors.hpp>
#include <boost/container/experimental/segmented_find_last_if.hpp>
namespace boost {
namespace container {
//! Returns an iterator to the last element equal to \c value
//! in [first, last), or \c last if not found.
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));
}
} // namespace container
} // namespace boost
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_HPP
@@ -0,0 +1,234 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FIND_LAST_IF_HPP
#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_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/detail/iterator.hpp>
#include <boost/container/experimental/segmented_iterator_traits.hpp>
namespace boost {
namespace container {
template <class FwdIt, class Sent, class Pred>
FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred);
namespace detail_algo {
//////////////////////////////////////////////
// Non-segmented scans
//////////////////////////////////////////////
template <class FwdIt, class Pred>
FwdIt find_last_if_scan(FwdIt first, FwdIt last, Pred pred,
non_segmented_iterator_tag, const std::forward_iterator_tag&)
{
FwdIt result = last;
for (; first != last; ++first)
if (pred(*first)) result = first;
return result;
}
template <class BidirIt, class Pred>
BidirIt find_last_if_scan(BidirIt first, BidirIt last, Pred pred,
non_segmented_iterator_tag, const std::bidirectional_iterator_tag&)
{
BidirIt cur = last;
while (cur != first) {
--cur;
if (pred(*cur)) return cur;
}
return last;
}
//////////////////////////////////////////////
// Segmented forward scan
//////////////////////////////////////////////
template <class SegIt, class Pred>
SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred,
segmented_iterator_tag, const std::forward_iterator_tag& cat)
{
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;
if (first == last) return last;
SegIt result = last;
segment_iterator sfirst = traits::segment(first);
const segment_iterator slast = traits::segment(last);
if (sfirst == slast) {
const local_iterator lf = traits::local(first);
const local_iterator ll = traits::local(last);
const local_iterator r = find_last_if_scan(lf, ll, pred, is_local_seg_t(), cat);
if (r != ll)
return traits::compose(sfirst, r);
return last;
}
// First segment
{
const local_iterator le = traits::end(sfirst);
const local_iterator r = find_last_if_scan(traits::local(first), le, pred, is_local_seg_t(), cat);
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_if_scan(traits::begin(sfirst), le, pred, is_local_seg_t(), cat);
if (r != le)
result = traits::compose(sfirst, r);
}
// Last segment
{
const local_iterator ll = traits::local(last);
const local_iterator r = find_last_if_scan(traits::begin(sfirst), ll, pred, is_local_seg_t(), cat);
if (r != ll)
result = traits::compose(sfirst, r);
}
return result;
}
//////////////////////////////////////////////
// Segmented bidirectional scan
//////////////////////////////////////////////
template <class SegIt, class Pred>
SegIt find_last_if_scan(SegIt first, SegIt last, Pred pred,
segmented_iterator_tag, const std::bidirectional_iterator_tag& cat)
{
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;
if (first == last) return last;
segment_iterator sfirst = traits::segment(first);
segment_iterator slast = traits::segment(last);
if (sfirst == slast) {
const local_iterator lf = traits::local(first);
const local_iterator ll = traits::local(last);
const local_iterator r = find_last_if_scan(lf, ll, pred, is_local_seg_t(), cat);
if (r != ll)
return traits::compose(sfirst, r);
return last;
}
// Last segment (partial): [begin(slast), local(last))
{
const local_iterator lb = traits::begin(slast);
const local_iterator ll = traits::local(last);
if (lb != ll) {
const local_iterator r = find_last_if_scan(lb, ll, pred, is_local_seg_t(), cat);
if (r != ll)
return traits::compose(slast, r);
}
}
// Middle segments in reverse
{
segment_iterator scur = slast;
for (--scur; scur != sfirst; --scur) {
const local_iterator lb = traits::begin(scur);
const local_iterator le = traits::end(scur);
const local_iterator r = find_last_if_scan(lb, le, pred, is_local_seg_t(), cat);
if (r != le)
return traits::compose(scur, r);
}
}
// First segment (partial): [local(first), end(sfirst))
{
const local_iterator lf = traits::local(first);
const local_iterator le = traits::end(sfirst);
const local_iterator r = find_last_if_scan(lf, le, pred, is_local_seg_t(), cat);
if (r != le)
return traits::compose(sfirst, r);
}
return last;
}
//////////////////////////////////////////////
// Sentinel / generic fallback
//////////////////////////////////////////////
template <class FwdIt, class Sent, class Pred, class SegTag, class CatTag>
FwdIt find_last_if_scan(FwdIt first, Sent last, Pred pred, SegTag, CatTag)
{
FwdIt result = first;
bool found = false;
for (; first != last; ++first) {
if (pred(*first)) { result = first; found = true; }
}
return found ? result : first;
}
//////////////////////////////////////////////
// sent_filter: sentinel ⇒ forward + flat
//////////////////////////////////////////////
template<class It, class Sent, class Seg, class Tag>
struct find_last_sent_filter
{
typedef std::forward_iterator_tag cat_t;
typedef non_segmented_iterator_tag seg_t;
};
template<class It, class Seg, class Tag>
struct find_last_sent_filter<It, It, Seg, Tag>
{
typedef Tag cat_t;
typedef Seg seg_t;
};
} // namespace detail_algo
//! Returns an iterator to the last element satisfying \c pred
//! 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 Pred>
BOOST_CONTAINER_FORCEINLINE
FwdIt segmented_find_last_if(FwdIt first, Sent last, Pred pred)
{
typedef segmented_iterator_traits<FwdIt> traits;
typedef typename boost::container::iterator_traits<FwdIt>::iterator_category cat_t;
typedef typename traits::is_segmented_iterator seg_t;
typedef detail_algo::find_last_sent_filter<FwdIt, Sent, seg_t, cat_t> sf;
return detail_algo::find_last_if_scan
( first, last, pred
, typename sf::seg_t()
, typename sf::cat_t());
}
} // namespace container
} // namespace boost
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_HPP
@@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FIND_LAST_IF_NOT_HPP
#define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_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/detail/compare_functors.hpp>
#include <boost/container/experimental/segmented_find_last_if.hpp>
namespace boost {
namespace container {
//! Returns an iterator to the last element for which \c pred
//! returns false in [first, last), or \c last if not found.
template <class FwdIt, class Sent, class Pred>
BOOST_CONTAINER_FORCEINLINE
FwdIt segmented_find_last_if_not(FwdIt first, Sent last, Pred pred)
{
return (segmented_find_last_if)(first, last, not_pred<Pred>(pred));
}
} // namespace container
} // namespace boost
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_FIND_LAST_IF_NOT_HPP