Skip to content

Commit f7990bd

Browse files
committed
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.
1 parent 216e6b7 commit f7990bd

1 file changed

Lines changed: 55 additions & 96 deletions

File tree

include/boost/container/experimental/segmented_is_sorted_until.hpp

Lines changed: 55 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -30,68 +30,42 @@ namespace detail_algo {
3030

3131
// Recursive dispatch for `segmented_is_sorted_until`.
3232
//
33-
// Cross-segment state is carried by reference:
33+
// Cross-segment state is carried by value and returned in segduo<Iter, DeepIt>:
3434
// - `prev` : iterator (of the deepest non-segmented local type) pointing
35-
// at the most recently examined element. Valid only when
36-
// `has_prev` is true.
37-
// - `has_prev` : becomes true the first time any element is seen.
35+
// at the most recently examined element.
3836
//
39-
// The segmented overload is the workhorse: it decomposes a range into
40-
// first / middle / last sub-ranges and dispatches each one back through
41-
// `sorted_until_rec`, which recurses if the local iterator is itself
42-
// segmented, until the non-segmented base case is reached. `prev` and
43-
// `has_prev` thread through every level of recursion unchanged, which is how
44-
// the "last element of segment K" is compared against "first element of
45-
// segment K+1" even when K and K+1 live at different levels of the nesting.
37+
// All sorted_until_rec overloads return segduo<Iter, DeepIt> where .first is
38+
// the result iterator and .second is the updated prev value. Passing prev by
39+
// value instead of by reference avoids pointer aliasing and lets the compiler
40+
// keep prev in a register throughout the inner loop.
4641

4742
// (1) Non-segmented base case.
4843
// At this level FwdIt == DeepIt (the deepest type computed from the top).
4944
template <class FwdIt, class Sent, class Comp, class DeepIt, class Cat>
50-
FwdIt sorted_until_rec
45+
segduo<FwdIt, DeepIt> sorted_until_rec
5146
(FwdIt first, Sent last, Comp comp,
52-
DeepIt &prev_out, bool &has_prev,
53-
const non_segmented_iterator_tag &, Cat)
47+
DeepIt prev, const non_segmented_iterator_tag &, Cat)
5448
{
55-
DeepIt prev = prev_out;
56-
if (!has_prev) {
57-
if (first == last)
58-
return first;
59-
prev = first;
60-
has_prev = true;
61-
++first;
62-
}
6349
for (; first != last; ++first) {
6450
if (comp(*first, *prev))
65-
goto final_update;
66-
prev = first;
51+
break;
52+
prev = detail_algo::deepest_local_iterator<FwdIt>::get(first);
6753
}
68-
final_update:
69-
prev_out = prev;
70-
return first;
54+
return segduo<FwdIt, DeepIt>(first, prev);
7155
}
7256

7357
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
7458

7559
// (1') Random-access unrolled variant of the non-segmented base case.
7660
template <class RAIter, class Comp, class DeepIt>
77-
RAIter sorted_until_rec
61+
segduo<RAIter, DeepIt> sorted_until_rec
7862
(RAIter first, RAIter last, Comp comp,
79-
DeepIt &prev_out, bool &has_prev,
63+
RAIter prev,
8064
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
8165
{
8266
typedef typename iterator_traits<RAIter>::difference_type difference_type;
8367

8468
difference_type n = last - first;
85-
if (n == difference_type(0))
86-
return last;
87-
88-
DeepIt prev = prev_out;
89-
if (!has_prev) {
90-
prev = first;
91-
has_prev = true;
92-
++first;
93-
--n;
94-
}
9569

9670
while (n >= difference_type(4)) {
9771
if (comp(*first, *prev))
@@ -130,43 +104,33 @@ RAIter sorted_until_rec
130104
}
131105

132106
final_result:
133-
prev_out = prev;
134-
return first;
107+
return segduo<RAIter, DeepIt>(first, prev);
135108
}
136109

137110
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
138111

139112
// (2) Segmented iterator with a heterogeneous sentinel as end.
140-
// Cannot locate `last`'s segment, so falls back to a simple linear loop
141-
// using a local iterator as previous. The `DeepIt &` / `has_prev &` are
142-
// not used here because this overload is only ever invoked at the very
143-
// top level (no cross-level state to propagate).
144-
template <class SegIter, class Sent, class Comp, class DeepIt, class Cat>
145-
typename algo_enable_if_c<is_sentinel<Sent, SegIter>::value, SegIter>::type
113+
// Cannot locate `last`'s segment, so falls back to a simple linear loop.
114+
template <class SegIter, class Sent, class Comp, class DeepIt, class Tag, class Cat>
115+
BOOST_CONTAINER_FORCEINLINE
116+
typename algo_enable_if_c< is_sentinel<Sent, SegIter>::value
117+
, segduo<SegIter, DeepIt> >::type
146118
sorted_until_rec
147119
(SegIter first, Sent last, Comp comp,
148-
DeepIt &, bool &,
149-
const segmented_iterator_tag &, Cat)
120+
DeepIt prev, const Tag &, const Cat &cat)
150121
{
151-
if (first != last) {
152-
SegIter prev_local = first;
153-
for (; ++first != last; ) {
154-
if (comp(*first, *prev_local))
155-
return first;
156-
prev_local = first;
157-
}
158-
}
159-
return first;
122+
return sorted_until_rec
123+
(first, last, comp, prev, non_segmented_iterator_tag(), cat);
160124
}
161125

162126
// (3) Segmented iterator with a matching segmented iterator as end.
163127
// Recursive: decomposes the range and dispatches each sub-range back to
164128
// `sorted_until_rec`, so recursive segmentation is exploited at every
165-
// level. `prev` / `has_prev` are threaded unchanged.
129+
// level. `prev` is threaded by value through the segduo return type.
166130
template <class SegIter, class Comp, class DeepIt, class Cat>
167-
SegIter sorted_until_rec
131+
segduo<SegIter, DeepIt> sorted_until_rec
168132
(SegIter first, SegIter last, Comp comp,
169-
DeepIt &prev, bool &has_prev,
133+
DeepIt prev,
170134
const segmented_iterator_tag &, Cat)
171135
{
172136
typedef segmented_iterator_traits<SegIter> traits;
@@ -175,44 +139,35 @@ SegIter sorted_until_rec
175139
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator
176140
is_local_seg_t;
177141
typedef typename iterator_traits<local_iterator>::iterator_category local_cat_t;
142+
typedef segduo<local_iterator, DeepIt> local_result_t;
178143

179144
segment_iterator sfirst = traits::segment(first);
180145
const segment_iterator slast = traits::segment(last);
181146

182147
if (sfirst == slast) {
183148
const local_iterator ll = traits::local(last);
184-
const local_iterator lr = (sorted_until_rec)
185-
(traits::local(first), ll, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
186-
if (lr != ll)
187-
return traits::compose(sfirst, lr);
149+
const local_result_t r = (sorted_until_rec)
150+
(traits::local(first), ll, comp, prev, is_local_seg_t(), local_cat_t());
151+
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
188152
}
189153
else {
190-
// First segment: from local(first) to end(sfirst)
191-
{
192-
const local_iterator le = traits::end(sfirst);
193-
const local_iterator lr = (sorted_until_rec)
194-
(traits::local(first), le, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
195-
if (lr != le)
196-
return traits::compose(sfirst, lr);
197-
}
198-
// Middle segments
154+
local_iterator le = traits::end(sfirst);
155+
local_result_t r = (sorted_until_rec)
156+
(traits::local(first), le, comp, prev, is_local_seg_t(), local_cat_t());
157+
if (r.first != le)
158+
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
159+
199160
for (++sfirst; sfirst != slast; ++sfirst) {
200-
const local_iterator le = traits::end(sfirst);
201-
const local_iterator lr = (sorted_until_rec)
202-
(traits::begin(sfirst), le, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
203-
if (lr != le)
204-
return traits::compose(sfirst, lr);
205-
}
206-
// Last segment: from begin(slast) to local(last)
207-
{
208-
const local_iterator ll = traits::local(last);
209-
const local_iterator lr = (sorted_until_rec)
210-
(traits::begin(slast), ll, comp, prev, has_prev, is_local_seg_t(), local_cat_t());
211-
if (lr != ll)
212-
return traits::compose(sfirst, lr);
161+
le = traits::end(sfirst);
162+
r = (sorted_until_rec)
163+
(traits::begin(sfirst), le, comp, r.second, is_local_seg_t(), local_cat_t());
164+
if (r.first != le)
165+
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
213166
}
167+
r = (sorted_until_rec)
168+
(traits::begin(slast), traits::local(last), comp, r.second, is_local_seg_t(), local_cat_t());
169+
return segduo<SegIter, DeepIt>(traits::compose(sfirst, r.first), r.second);
214170
}
215-
return last;
216171
}
217172

218173
} // namespace detail_algo
@@ -224,14 +179,18 @@ template <class FwdIt, class Sent, class Comp>
224179
BOOST_CONTAINER_FORCEINLINE
225180
FwdIt segmented_is_sorted_until(FwdIt first, Sent last, Comp comp)
226181
{
227-
typedef segmented_iterator_traits<FwdIt> traits;
228-
typedef typename detail_algo::deepest_local_iterator<FwdIt>::type deep_it;
229-
deep_it prev = deep_it();
230-
bool has_prev = false;
182+
if (first == last)
183+
return first;
184+
185+
typedef segmented_iterator_traits<FwdIt> traits;
186+
typedef detail_algo::deepest_local_iterator<FwdIt> deep_it_helper;
187+
typedef typename deep_it_helper::type deep_it;
188+
189+
deep_it prev = deep_it_helper::get(first);
231190
return detail_algo::sorted_until_rec
232-
(first, last, comp, prev, has_prev,
233-
typename traits::is_segmented_iterator(),
234-
typename iterator_traits<FwdIt>::iterator_category());
191+
(++first, last, comp, prev,
192+
typename traits::is_segmented_iterator(),
193+
typename iterator_traits<FwdIt>::iterator_category()).first;
235194
}
236195

237196
//! 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)
249208

250209
#include <boost/container/detail/config_end.hpp>
251210

252-
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP
211+
#endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_IS_SORTED_UNTIL_HPP

0 commit comments

Comments
 (0)