Reimplemented segmented_is_sorted_until to simplify and speed it up. The new implementation does an early check and there is no longer need to pass a boolean validity flag for the previous iterator.

This commit is contained in:
Ion Gaztañaga
2026-04-27 01:16:55 +02:00
parent 216e6b7f01
commit f7990bd034
@@ -30,68 +30,42 @@ namespace detail_algo {
// Recursive dispatch for `segmented_is_sorted_until`.
//
// Cross-segment state is carried by reference:
// Cross-segment state is carried by value and returned in segduo<Iter, DeepIt>:
// - `prev` : iterator (of the deepest non-segmented local type) pointing
// at the most recently examined element. Valid only when
// `has_prev` is true.
// - `has_prev` : becomes true the first time any element is seen.
// at the most recently examined element.
//
// The segmented overload is the workhorse: it decomposes a range into
// first / middle / last sub-ranges and dispatches each one back through
// `sorted_until_rec`, which recurses if the local iterator is itself
// segmented, until the non-segmented base case is reached. `prev` and
// `has_prev` thread through every level of recursion unchanged, which is how
// the "last element of segment K" is compared against "first element of
// segment K+1" even when K and K+1 live at different levels of the nesting.
// All sorted_until_rec overloads return segduo<Iter, DeepIt> where .first is
// the result iterator and .second is the updated prev value. Passing prev by
// value instead of by reference avoids pointer aliasing and lets the compiler
// keep prev in a register throughout the inner loop.
// (1) Non-segmented base case.
// At this level FwdIt == DeepIt (the deepest type computed from the top).
template <class FwdIt, class Sent, class Comp, class DeepIt, class Cat>
FwdIt sorted_until_rec
segduo<FwdIt, DeepIt> sorted_until_rec
(FwdIt first, Sent last, Comp comp,
DeepIt &prev_out, bool &has_prev,
const non_segmented_iterator_tag &, Cat)
DeepIt prev, const non_segmented_iterator_tag &, Cat)
{
DeepIt prev = prev_out;
if (!has_prev) {
if (first == last)
return first;
prev = first;
has_prev = true;
++first;
}
for (; first != last; ++first) {
if (comp(*first, *prev))
goto final_update;
prev = first;
break;
prev = detail_algo::deepest_local_iterator<FwdIt>::get(first);
}
final_update:
prev_out = prev;
return first;
return segduo<FwdIt, DeepIt>(first, prev);
}
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
// (1') Random-access unrolled variant of the non-segmented base case.
template <class RAIter, class Comp, class DeepIt>
RAIter sorted_until_rec
segduo<RAIter, DeepIt> sorted_until_rec
(RAIter first, RAIter last, Comp comp,
DeepIt &prev_out, bool &has_prev,
RAIter prev,
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
{
typedef typename iterator_traits<RAIter>::difference_type difference_type;
difference_type n = last - first;
if (n == difference_type(0))
return last;
DeepIt prev = prev_out;
if (!has_prev) {
prev = first;
has_prev = true;
++first;
--n;
}
while (n >= difference_type(4)) {
if (comp(*first, *prev))
@@ -130,43 +104,33 @@ RAIter sorted_until_rec
}
final_result:
prev_out = prev;
return first;
return segduo<RAIter, DeepIt>(first, prev);
}
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
// (2) Segmented iterator with a heterogeneous sentinel as end.
// Cannot locate `last`'s segment, so falls back to a simple linear loop
// using a local iterator as previous. The `DeepIt &` / `has_prev &` are
// not used here because this overload is only ever invoked at the very
// top level (no cross-level state to propagate).
template <class SegIter, class Sent, class Comp, class DeepIt, class Cat>
typename algo_enable_if_c<is_sentinel<Sent, SegIter>::value, SegIter>::type
// Cannot locate `last`'s segment, so falls back to a simple linear loop.
template <class SegIter, class Sent, class Comp, class DeepIt, class Tag, class Cat>
BOOST_CONTAINER_FORCEINLINE
typename algo_enable_if_c< is_sentinel<Sent, SegIter>::value
, segduo<SegIter, DeepIt> >::type
sorted_until_rec
(SegIter first, Sent last, Comp comp,
DeepIt &, bool &,
const segmented_iterator_tag &, Cat)
DeepIt prev, const Tag &, const Cat &cat)
{
if (first != last) {
SegIter prev_local = first;
for (; ++first != last; ) {
if (comp(*first, *prev_local))
return first;
prev_local = first;
}
}
return first;
return sorted_until_rec
(first, last, comp, prev, non_segmented_iterator_tag(), cat);
}
// (3) Segmented iterator with a matching segmented iterator as end.
// Recursive: decomposes the range and dispatches each sub-range back to
// `sorted_until_rec`, so recursive segmentation is exploited at every
// level. `prev` / `has_prev` are threaded unchanged.
// level. `prev` is threaded by value through the segduo return type.
template <class SegIter, class Comp, class DeepIt, class Cat>
SegIter sorted_until_rec
segduo<SegIter, DeepIt> sorted_until_rec
(SegIter first, SegIter last, Comp comp,
DeepIt &prev, bool &has_prev,
DeepIt prev,
const segmented_iterator_tag &, Cat)
{
typedef segmented_iterator_traits<SegIter> traits;
@@ -175,44 +139,35 @@ SegIter sorted_until_rec
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;
typedef segduo<local_iterator, DeepIt> local_result_t;
segment_iterator sfirst = traits::segment(first);
const segment_iterator slast = traits::segment(last);
if (sfirst == slast) {
const local_iterator ll = traits::local(last);
const local_iterator lr = (sorted_until_rec)
(traits::local(first), ll, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
if (lr != ll)
return traits::compose(sfirst, lr);
const local_result_t r = (sorted_until_rec)
(traits::local(first), ll, comp, prev, is_local_seg_t(), local_cat_t());
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
}
else {
// First segment: from local(first) to end(sfirst)
{
const local_iterator le = traits::end(sfirst);
const local_iterator lr = (sorted_until_rec)
(traits::local(first), le, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
if (lr != le)
return traits::compose(sfirst, lr);
}
// Middle segments
local_iterator le = traits::end(sfirst);
local_result_t r = (sorted_until_rec)
(traits::local(first), le, comp, prev, is_local_seg_t(), local_cat_t());
if (r.first != le)
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
for (++sfirst; sfirst != slast; ++sfirst) {
const local_iterator le = traits::end(sfirst);
const local_iterator lr = (sorted_until_rec)
(traits::begin(sfirst), le, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
if (lr != le)
return traits::compose(sfirst, lr);
}
// Last segment: from begin(slast) to local(last)
{
const local_iterator ll = traits::local(last);
const local_iterator lr = (sorted_until_rec)
(traits::begin(slast), ll, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
if (lr != ll)
return traits::compose(sfirst, lr);
le = traits::end(sfirst);
r = (sorted_until_rec)
(traits::begin(sfirst), le, comp, r.second, is_local_seg_t(), local_cat_t());
if (r.first != le)
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
}
r = (sorted_until_rec)
(traits::begin(slast), traits::local(last), comp, r.second, is_local_seg_t(), local_cat_t());
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
}
return last;
}
} // namespace detail_algo
@@ -224,14 +179,18 @@ template <class FwdIt, class Sent, class Comp>
BOOST_CONTAINER_FORCEINLINE
FwdIt segmented_is_sorted_until(FwdIt first, Sent last, Comp comp)
{
typedef segmented_iterator_traits<FwdIt> traits;
typedef typename detail_algo::deepest_local_iterator<FwdIt>::type deep_it;
deep_it prev = deep_it();
bool has_prev = false;
if (first == last)
return first;
typedef segmented_iterator_traits<FwdIt> traits;
typedef detail_algo::deepest_local_iterator<FwdIt> deep_it_helper;
typedef typename deep_it_helper::type deep_it;
deep_it prev = deep_it_helper::get(first);
return detail_algo::sorted_until_rec
(first, last, comp, prev, has_prev,
typename traits::is_segmented_iterator(),
typename iterator_traits<FwdIt>::iterator_category());
(++first, last, comp, prev,
typename traits::is_segmented_iterator(),
typename iterator_traits<FwdIt>::iterator_category()).first;
}
//! Returns an iterator to the first element that is less than its predecessor
@@ -249,4 +208,4 @@ FwdIt segmented_is_sorted_until(FwdIt first, Sent last)
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP