diff --git a/include/boost/container/experimental/segmented_is_sorted_until.hpp b/include/boost/container/experimental/segmented_is_sorted_until.hpp index 55d63c3..8ff0132 100644 --- a/include/boost/container/experimental/segmented_is_sorted_until.hpp +++ b/include/boost/container/experimental/segmented_is_sorted_until.hpp @@ -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: // - `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 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 -FwdIt sorted_until_rec +segduo 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::get(first); } - final_update: - prev_out = prev; - return first; + return segduo(first, prev); } #if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) // (1') Random-access unrolled variant of the non-segmented base case. template -RAIter sorted_until_rec +segduo 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::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(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 -typename algo_enable_if_c::value, SegIter>::type +// Cannot locate `last`'s segment, so falls back to a simple linear loop. +template +BOOST_CONTAINER_FORCEINLINE +typename algo_enable_if_c< is_sentinel::value + , segduo >::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 -SegIter sorted_until_rec +segduo 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 traits; @@ -175,44 +139,35 @@ SegIter sorted_until_rec typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; typedef typename iterator_traits::iterator_category local_cat_t; + typedef segduo 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(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(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(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(traits::compose(sfirst, r.first), r.second); } - return last; } } // namespace detail_algo @@ -224,14 +179,18 @@ template BOOST_CONTAINER_FORCEINLINE FwdIt segmented_is_sorted_until(FwdIt first, Sent last, Comp comp) { - typedef segmented_iterator_traits traits; - typedef typename detail_algo::deepest_local_iterator::type deep_it; - deep_it prev = deep_it(); - bool has_prev = false; + if (first == last) + return first; + + typedef segmented_iterator_traits traits; + typedef detail_algo::deepest_local_iterator 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::iterator_category()); + (++first, last, comp, prev, + typename traits::is_segmented_iterator(), + typename iterator_traits::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 -#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP +#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP \ No newline at end of file