@@ -95,5 +95,70 @@ function findfirstsortedequal(var::Int64, vars::DenseVector{Int64},
95
95
end
96
96
97
97
98
+ """
99
+ bracketstrictlymontonic(v, x, guess; lt=<comparison>, by=<transform>, rev=false)
100
+
101
+ Starting from an initial `guess` index, find indices `(lo, hi)` such that `v[lo] ≤ x ≤
102
+ v[hi]` according to the specified order, assuming that `x` is actually within the range of
103
+ values found in `v`. If `x` is outside that range, either `lo` will be `firstindex(v)` or
104
+ `hi` will be `lastindex(v)`.
105
+
106
+ Note that the results will not typically satisfy `lo ≤ guess ≤ hi`. If `x` is precisely
107
+ equal to a value that is not unique in the input `v`, there is no guarantee that `(lo, hi)`
108
+ will encompass *all* indices corresponding to that value.
109
+
110
+ This algorithm is essentially an expanding binary search, which can be used as a precursor
111
+ to `searchsorted` and related functions, which can take `lo` and `hi` as arguments. The
112
+ purpose of using this function first would be to accelerate convergence in those functions
113
+ by using correlated `guess`es for repeated calls. The best `guess` for the next call of
114
+ this function would be the index returned by the previous call to `searchsorted`.
115
+
116
+ See [`sort!`](@ref) for an explanation of the keyword arguments `by`, `lt` and `rev`.
117
+ """
118
+ function bracketstrictlymontonic (v:: AbstractVector ,
119
+ x,
120
+ guess:: T ,
121
+ o:: Base.Order.Ordering ):: NTuple{2,keytype(v)} where {T<: Integer }
122
+ bottom = firstindex (v)
123
+ top = lastindex (v)
124
+ if guess < bottom || guess > top
125
+ return bottom, top
126
+ # # NOTE: for cache efficiency in repeated calls, we avoid accessing the first and last elements of `v`
127
+ # # on each call to this function. This should only result in significant slow downs for calls with
128
+ # # out-of-bounds values of `x` *and* bad `guess`es.
129
+ # elseif lt(o, x, v[bottom])
130
+ # return bottom, bottom
131
+ # elseif lt(o, v[top], x)
132
+ # return top, top
133
+ else
134
+ u = T (1 )
135
+ lo, hi = guess, min (guess + u, top)
136
+ @inbounds if Base. Order. lt (o, x, v[lo])
137
+ while lo > bottom && Base. Order. lt (o, x, v[lo])
138
+ lo, hi = max (bottom, lo - u), lo
139
+ u += u
140
+ end
141
+ else
142
+ while hi < top && ! Base. Order. lt (o, x, v[hi])
143
+ lo, hi = hi, min (top, hi + u)
144
+ u += u
145
+ end
146
+ end
147
+ end
148
+ return lo, hi
149
+ end
150
+
151
+ function searchsortedfirstcorrelated (v:: AbstractVector , x, guess)
152
+ lo, hi = bracketstrictlymontonic (v, x, guess, Base. Order. Forward)
153
+ searchsortedfirst (v, x, lo, hi, Base. Order. Forward)
154
+ end
155
+
156
+ function searchsortedlastcorrelated (v:: AbstractVector , x, guess)
157
+ lo, hi = bracketstrictlymontonic (v, x, guess, Base. Order. Forward)
158
+ searchsortedlast (v, x, lo, hi, Base. Order. Forward)
159
+ end
160
+
161
+ searchsortedfirstcorrelated (r:: AbstractRange , x, _) = searchsortedfirst (r, x)
162
+ searchsortedlastcorrelated (r:: AbstractRange , x, _) = searchsortedlast (r, x)
98
163
99
164
end
0 commit comments