mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 17:40:46 +02:00
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:
@@ -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
|
||||
Reference in New Issue
Block a user