mirror of
https://github.com/boostorg/container.git
synced 2026-07-06 08:50:46 +02:00
Added segmented_find_last, segmented_find_last_if, segmented_find_last_if_not
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user