3
3
//!
4
4
//! These are provided by [`iter_set`], except [`progressive`], which is written by be.
5
5
use std:: cmp:: Ordering ;
6
+ use std:: fmt:: Debug ;
6
7
use std:: iter:: Peekable ;
7
8
use std:: mem;
8
9
@@ -121,12 +122,13 @@ struct Progressive<
121
122
L : Iterator < Item = T > ,
122
123
R : Iterator < Item = T > ,
123
124
C : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
124
- M : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
125
+ M : FnMut ( & T , & T ) -> core:: cmp:: Ordering ,
125
126
> {
126
127
l : L ,
127
128
r : R ,
128
129
matches : M ,
129
130
comparison : C ,
131
+ minimize_dist_right : Option < fn ( & T , & T ) -> usize > ,
130
132
l_next : Option < T > ,
131
133
r_next : Option < T > ,
132
134
l_peek : Option < T > ,
@@ -137,7 +139,7 @@ impl<
137
139
L : Iterator < Item = T > ,
138
140
R : Iterator < Item = T > ,
139
141
C : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
140
- M : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
142
+ M : FnMut ( & T , & T ) -> core:: cmp:: Ordering ,
141
143
> Progressive < T , L , R , C , M >
142
144
{
143
145
fn next_l ( & mut self ) {
@@ -154,79 +156,109 @@ impl<
154
156
L : Iterator < Item = T > ,
155
157
R : Iterator < Item = T > ,
156
158
C : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
157
- M : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
159
+ M : FnMut ( & T , & T ) -> core:: cmp:: Ordering ,
158
160
> Iterator for Progressive < T , L , R , C , M >
159
161
{
160
162
type Item = ProgressiveInclusion < T > ;
161
163
fn next ( & mut self ) -> Option < Self :: Item > {
162
- match ( self . l_next . take ( ) , self . r_next . take ( ) ) {
163
- ( Some ( mut l) , Some ( mut r) ) => match ( self . matches ) ( & mut l, & mut r) {
164
- Ordering :: Less => {
165
- let l = ProgressiveInclusion :: Left ( l) ;
166
- self . r_next = Some ( r) ;
167
- self . next_l ( ) ;
168
- return Some ( l) ;
169
- }
170
- Ordering :: Equal => {
171
- self . l_next = Some ( l) ;
172
- self . r_next = Some ( r) ;
173
- }
174
- Ordering :: Greater => {
175
- let r = ProgressiveInclusion :: Right ( r) ;
176
- self . l_next = Some ( l) ;
177
- self . next_r ( ) ;
178
- return Some ( r) ;
179
- }
180
- } ,
181
- _ => return None ,
182
- }
164
+ loop {
165
+ match ( self . l_next . take ( ) , self . r_next . take ( ) ) {
166
+ ( Some ( l) , Some ( r) ) => match ( self . matches ) ( & l, & r) {
167
+ Ordering :: Less => {
168
+ let l = ProgressiveInclusion :: Left ( l) ;
169
+ self . r_next = Some ( r) ;
170
+ self . next_l ( ) ;
171
+ return Some ( l) ;
172
+ }
173
+ Ordering :: Equal => {
174
+ self . l_next = Some ( l) ;
175
+ self . r_next = Some ( r) ;
176
+ }
177
+ Ordering :: Greater => {
178
+ let r = ProgressiveInclusion :: Right ( r) ;
179
+ self . l_next = Some ( l) ;
180
+ self . next_r ( ) ;
181
+ return Some ( r) ;
182
+ }
183
+ } ,
184
+ _ => return None ,
185
+ }
183
186
184
- if self . r_peek . is_none ( ) {
185
- let ret = ProgressiveInclusion :: Both ( self . l_next . take ( ) ?, self . r_next . clone ( ) ?) ;
186
- self . next_l ( ) ;
187
- return Some ( ret) ;
188
- }
189
- if self . l_peek . is_none ( ) {
190
- let ret = ProgressiveInclusion :: Both ( self . l_next . clone ( ) ?, self . r_next . take ( ) ?) ;
191
- self . next_r ( ) ;
187
+ if self . r_peek . is_none ( ) {
188
+ let ret = ProgressiveInclusion :: Both ( self . l_next . take ( ) ?, self . r_next . clone ( ) ?) ;
189
+ self . next_l ( ) ;
190
+ return Some ( ret) ;
191
+ }
192
+ if self . l_peek . is_none ( ) {
193
+ let ret = ProgressiveInclusion :: Both ( self . l_next . clone ( ) ?, self . r_next . take ( ) ?) ;
194
+ self . next_r ( ) ;
195
+ return Some ( ret) ;
196
+ }
197
+
198
+ // If `self.r_peek` and `self.l_peek` are both some, these must be Some. It's a logic error
199
+ // otherwise.
200
+ let left = self . l_next . as_mut ( ) . unwrap ( ) ;
201
+ let right = self . r_next . as_mut ( ) . unwrap ( ) ;
202
+ let cmp = ( self . comparison ) ( left, right) ;
203
+ let advance_right = cmp == Ordering :: Greater ;
204
+ // If dist between left and right is less on next iter, iterate right to get closer.
205
+ if let Some ( minimize_dist_right) = self . minimize_dist_right {
206
+ if advance_right {
207
+ let dist = minimize_dist_right ( left, right) ;
208
+ let peek_dist = if let Some ( right) = & self . r_peek {
209
+ if ( self . matches ) ( left, right) == Ordering :: Equal {
210
+ Some ( minimize_dist_right ( left, right) )
211
+ } else {
212
+ None
213
+ }
214
+ } else {
215
+ None
216
+ } ;
217
+ // The == part of <= is really important, as we can have duplicates.
218
+ if peek_dist. map_or ( false , |peek_dist| peek_dist <= dist) {
219
+ self . next_r ( ) ;
220
+ continue ;
221
+ }
222
+ }
223
+ }
224
+ let ret = ProgressiveInclusion :: Both ( left. clone ( ) , right. clone ( ) ) ;
225
+ if advance_right {
226
+ self . next_r ( ) ;
227
+ } else {
228
+ self . next_l ( ) ;
229
+ } ;
192
230
return Some ( ret) ;
193
231
}
194
-
195
- // If `self.r_peek` and `self.l_peek` are both some, these must be Some. It's a logic error
196
- // otherwise.
197
- let left = self . l_next . as_mut ( ) . unwrap ( ) ;
198
- let right = self . r_next . as_mut ( ) . unwrap ( ) ;
199
- let advance_right = ( self . comparison ) ( left, right) == Ordering :: Greater ;
200
- let ret = ProgressiveInclusion :: Both ( left. clone ( ) , right. clone ( ) ) ;
201
- if advance_right {
202
- self . next_r ( ) ;
203
- } else {
204
- self . next_l ( ) ;
205
- } ;
206
- Some ( ret)
207
232
}
208
233
}
209
234
/// Like [`iter_set::classify`] but when we get two "equal" from `matches`, we let one of those
210
235
/// stay in the "cache" to match future ones. The last one or the greatest one according to
211
236
/// `comparison` stays.
237
+ ///
238
+ /// If `minimize_dist_right` is [`Some`], the algorithm will only return
239
+ /// [`ProgressiveInclusion::Both`] once `b` is close to `a` as possible.
240
+ /// It should return the distance between the two points (using the same algorithm as `comparison`).
241
+ /// This is very useful when doing `AND NOT` operations. Set it to [`None`] otherwise.
212
242
pub fn progressive < T , L , R , C , M > (
213
243
a : L ,
214
244
b : R ,
215
245
comparison : C ,
216
246
matches : M ,
247
+ minimize_dist_right : Option < fn ( & T , & T ) -> usize > ,
217
248
) -> impl Iterator < Item = ProgressiveInclusion < T > >
218
249
where
219
250
T : Clone ,
220
251
L : IntoIterator < Item = T > ,
221
252
R : IntoIterator < Item = T > ,
222
253
C : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
223
- M : FnMut ( & mut T , & mut T ) -> core:: cmp:: Ordering ,
254
+ M : FnMut ( & T , & T ) -> core:: cmp:: Ordering ,
224
255
{
225
256
let mut l = a. into_iter ( ) ;
226
257
let mut r = b. into_iter ( ) ;
227
258
Progressive {
228
259
comparison,
229
260
matches,
261
+ minimize_dist_right,
230
262
l_next : l. next ( ) ,
231
263
r_next : r. next ( ) ,
232
264
l_peek : l. next ( ) ,
0 commit comments