@@ -144,12 +144,8 @@ where
144
144
return Some ( ( indices, items) ) ;
145
145
}
146
146
// Keep yielding items list, incrementing indices rightmost first.
147
- for index in indices. iter_mut ( ) . rev ( ) {
148
- * index += 1 ;
149
- if * index < base {
150
- return Some ( ( indices, items) ) ;
151
- }
152
- * index = 0 ; // Wrap and increment left.
147
+ if Self :: inbounds_increment ( indices, base) {
148
+ return Some ( ( indices, items) ) ;
153
149
}
154
150
// Iteration is over.
155
151
// Mark a special index value to not fuse the iterator
@@ -160,9 +156,176 @@ where
160
156
}
161
157
}
162
158
159
+ /// Increment indices, returning false in case of overflow.
160
+ fn inbounds_increment ( indices : & mut [ usize ] , base : usize ) -> bool {
161
+ for index in indices. iter_mut ( ) . rev ( ) {
162
+ * index += 1 ;
163
+ if * index < base {
164
+ return true ;
165
+ }
166
+ * index = 0 ; // Wrap and increment left.
167
+ }
168
+ false
169
+ }
170
+
171
+ /// Increment indices by n, returning false in case of (saturating) overflow.
172
+ fn inbounds_increment_by ( n : usize , indices : & mut [ usize ] , base : usize ) -> bool {
173
+ let mut q = n;
174
+ for index in indices. iter_mut ( ) . rev ( ) {
175
+ q = ( * index + q) / base;
176
+ * index = ( * index + n) % base;
177
+ if q == 0 {
178
+ return true ;
179
+ }
180
+ }
181
+ // Saturation requires a second pass to reset all indices.
182
+ for index in indices. iter_mut ( ) {
183
+ * index = 0 ;
184
+ }
185
+ false
186
+ }
187
+
163
188
/// Same as [`increment_indices`], but does n increments at once.
189
+ /// The iterator is cycling, but `.nth()` does not 'wrap'
190
+ /// and 'saturates' to None instead.
191
+ #[ allow( clippy:: too_many_lines) ] // HERE: fix when tests pass.
164
192
fn increment_indices_by_n ( & mut self , n : usize ) -> Option < ( & [ usize ] , & [ I :: Item ] ) > {
165
- todo ! ( )
193
+ let Self {
194
+ pow,
195
+ iter,
196
+ items,
197
+ indices,
198
+ } = self ;
199
+ print ! (
200
+ "^{pow}: +{n} {} {indices:?}\t {:?}\t -> " ,
201
+ if iter. is_some( ) { 'S' } else { 'N' } ,
202
+ items. as_ref( ) . map( Vec :: len)
203
+ ) ;
204
+
205
+ match ( * pow, iter, & mut * items, n) {
206
+ // First iteration with degenerated 0th power.
207
+ ( 0 , Some ( _) , items @ None , 0 ) => {
208
+ println ! ( "AAA" ) ;
209
+ // Same as .next().
210
+ self . iter = None ;
211
+ let empty = items. insert ( Vec :: new ( ) ) ;
212
+ Some ( ( indices, empty) )
213
+ }
214
+ ( 0 , Some ( _) , None , _) => {
215
+ println ! ( "BBB" ) ;
216
+ // Saturate.
217
+ self . iter = None ;
218
+ None
219
+ }
220
+
221
+ // Subsequent degenerated 0th power iteration.
222
+ // Same as `.next()`.
223
+ ( 0 , None , items @ None , 0 ) => {
224
+ println ! ( "CCC" ) ;
225
+ Some ( ( indices, items. insert ( Vec :: new ( ) ) ) )
226
+ }
227
+ // Saturate.
228
+ ( 0 , None , items, _) => {
229
+ println ! ( "DDD" ) ;
230
+ * items = None ;
231
+ None
232
+ }
233
+
234
+ // First iterations in the general case.
235
+ // Possibly this will consume the entire underlying iterator,
236
+ // but we need to consume to check.
237
+ ( pow, Some ( it) , items @ None , mut remaining) => {
238
+ println ! ( "EEE" ) ;
239
+ if let Some ( first) = it. next ( ) {
240
+ // There is at least one element in the iterator, prepare collection + indices.
241
+ let items = items. insert ( Vec :: with_capacity ( it. size_hint ( ) . 0 ) ) ;
242
+ items. push ( first) ;
243
+ indices. reserve_exact ( pow) ;
244
+ for _ in 0 ..pow {
245
+ indices. push ( 0 ) ;
246
+ }
247
+ // Collect more.
248
+ loop {
249
+ if remaining == 0 {
250
+ // Stop before collection completion.
251
+ indices[ pow - 1 ] = n; // Hasn't wrapped yet.
252
+ return Some ( ( indices, items) ) ;
253
+ }
254
+ if let Some ( next) = it. next ( ) {
255
+ items. push ( next) ;
256
+ remaining -= 1 ;
257
+ continue ;
258
+ }
259
+ // Collection completed, but we need to go further.
260
+ self . iter = None ;
261
+ let base = items. len ( ) ;
262
+ if Self :: inbounds_increment_by ( n, indices, base) {
263
+ return Some ( ( indices, items) ) ;
264
+ }
265
+ // Immediate saturation.
266
+ indices[ 0 ] = base;
267
+ return None ;
268
+ }
269
+ } else {
270
+ // Degenerated iteration over an empty set.
271
+ self . iter = None ;
272
+ None
273
+ }
274
+ }
275
+
276
+ // Stable iteration in the degenerated case 'base = 0'.
277
+ ( _, None , None , _) => {
278
+ println ! ( "FFF" ) ;
279
+ None
280
+ }
281
+
282
+ // Subsequent iteration in the general case.
283
+ // Again, immediate saturation is an option.
284
+ ( pow, Some ( it) , Some ( items) , mut remaining) => {
285
+ println ! ( "GGG" ) ;
286
+ if let Some ( next) = it. next ( ) {
287
+ items. push ( next) ;
288
+ loop {
289
+ if remaining == 0 {
290
+ indices[ pow - 1 ] += n; // Hasn't wrapped yet.
291
+ return Some ( ( indices, items) ) ;
292
+ }
293
+ if let Some ( next) = it. next ( ) {
294
+ items. push ( next) ;
295
+ remaining -= 1 ;
296
+ continue ;
297
+ }
298
+ break ;
299
+ }
300
+ }
301
+ // Collection completed.
302
+ self . iter = None ;
303
+ let base = items. len ( ) ;
304
+ if Self :: inbounds_increment_by ( n, indices, base) {
305
+ return Some ( ( indices, items) ) ;
306
+ }
307
+ // Saturate.
308
+ indices[ 0 ] = base;
309
+ None
310
+ }
311
+
312
+ // Subsequent iteration in the general case
313
+ // after all items have been collected.
314
+ ( _, None , Some ( items) , n) => {
315
+ println ! ( "HHH" ) ;
316
+ let base = items. len ( ) ;
317
+ if indices[ 0 ] == base {
318
+ // Start over for a new round.
319
+ indices[ 0 ] = 0 ;
320
+ }
321
+ if Self :: inbounds_increment_by ( n, indices, base) {
322
+ return Some ( ( indices, items) ) ;
323
+ }
324
+ // Immediate re-saturation.
325
+ indices[ 0 ] = base;
326
+ None
327
+ }
328
+ }
166
329
}
167
330
}
168
331
@@ -319,66 +482,63 @@ mod tests {
319
482
#[ test]
320
483
fn nth ( ) {
321
484
fn check ( origin : & str , pow : usize , expected : & [ ( usize , Option < & str > ) ] ) {
485
+ println ! ( "================== ({origin:?}^{pow})" ) ;
322
486
let mut it = origin. chars ( ) . cartesian_power ( pow) ;
323
487
let mut total_n = Vec :: new ( ) ;
324
- for r in 1 ..=3 {
325
- for & ( n, exp) in expected {
326
- let act = it. nth ( n) ;
327
- total_n. push ( n) ;
328
- if act != exp. map ( |s| s. chars ( ) . collect :: < Vec < _ > > ( ) ) {
329
- panic ! (
330
- "Failed nth({}) iteration (repetition {}) for {:?}^{}. \
488
+ for & ( n, exp) in expected {
489
+ let act = it. nth ( n) ;
490
+ total_n. push ( n) ;
491
+ if act != exp. map ( |s| s. chars ( ) . collect :: < Vec < _ > > ( ) ) {
492
+ panic ! (
493
+ "Failed nth({}) iteration for {:?}^{}. \
331
494
Expected {:?}, got {:?} instead.",
332
- total_n
333
- . iter( )
334
- . map( ToString :: to_string)
335
- . collect:: <Vec <_>>( )
336
- . join( ", " ) ,
337
- r,
338
- origin,
339
- pow,
340
- exp,
341
- act
342
- ) ;
343
- }
495
+ total_n
496
+ . iter( )
497
+ . map( ToString :: to_string)
498
+ . collect:: <Vec <_>>( )
499
+ . join( ", " ) ,
500
+ origin,
501
+ pow,
502
+ exp,
503
+ act
504
+ ) ;
344
505
}
345
506
}
346
507
}
347
508
348
- // Check degenerated cases.
349
- check ( "" , 0 , & [ ( 0 , Some ( "" ) ) , ( 0 , None ) ] ) ;
350
- check ( "" , 0 , & [ ( 0 , Some ( "" ) ) , ( 1 , None ) ] ) ;
351
- check ( "" , 0 , & [ ( 0 , Some ( "" ) ) , ( 2 , None ) ] ) ;
352
- check ( "" , 0 , & [ ( 1 , None ) , ( 0 , None ) ] ) ;
353
- check ( "" , 0 , & [ ( 1 , None ) , ( 1 , None ) ] ) ;
354
- check ( "" , 0 , & [ ( 1 , None ) , ( 2 , None ) ] ) ;
355
- check ( "" , 0 , & [ ( 2 , None ) , ( 0 , None ) ] ) ;
356
- check ( "" , 0 , & [ ( 2 , None ) , ( 1 , None ) ] ) ;
357
- check ( "" , 0 , & [ ( 2 , None ) , ( 2 , None ) ] ) ;
358
-
359
- check ( "a" , 0 , & [ ( 0 , Some ( "" ) ) , ( 0 , None ) ] ) ;
360
- check ( "a" , 0 , & [ ( 0 , Some ( "" ) ) , ( 1 , None ) ] ) ;
361
- check ( "a" , 0 , & [ ( 0 , Some ( "" ) ) , ( 2 , None ) ] ) ;
362
- check ( "a" , 0 , & [ ( 1 , None ) , ( 0 , None ) ] ) ;
363
- check ( "a" , 0 , & [ ( 1 , None ) , ( 1 , None ) ] ) ;
364
- check ( "a" , 0 , & [ ( 1 , None ) , ( 2 , None ) ] ) ;
365
- check ( "a" , 0 , & [ ( 2 , None ) , ( 0 , None ) ] ) ;
366
- check ( "a" , 0 , & [ ( 2 , None ) , ( 1 , None ) ] ) ;
367
- check ( "a" , 0 , & [ ( 2 , None ) , ( 2 , None ) ] ) ;
509
+ // Ease test read/write.
510
+ macro_rules! check {
511
+ ( $base: expr, $pow: expr => $( $n: literal $expected: expr) + ) => {
512
+ check( $base, $pow, & [ $( ( $n, $expected) ) ,+] ) ;
513
+ } ;
514
+ }
515
+
516
+ // Degenerated cases.
517
+ for base in [ "" , "a" , "ab" ] {
518
+ check ! ( base, 0 => 0 Some ( "" ) 0 None 0 Some ( "" ) 0 None ) ;
519
+ check ! ( base, 0 => 0 Some ( "" ) 1 None 0 Some ( "" ) 1 None ) ;
520
+ check ! ( base, 0 => 0 Some ( "" ) 2 None 1 None 0 Some ( "" ) ) ;
521
+ check ! ( base, 0 => 1 None 0 Some ( "" ) 0 None 1 None ) ;
522
+ check ! ( base, 0 => 1 None 1 None 0 Some ( "" ) 0 None ) ;
523
+ check ! ( base, 0 => 1 None 2 None 0 Some ( "" ) 1 None ) ;
524
+ check ! ( base, 0 => 2 None 0 Some ( "" ) 1 None 0 Some ( "" ) ) ;
525
+ check ! ( base, 0 => 2 None 1 None 2 None 0 Some ( "" ) ) ;
526
+ check ! ( base, 0 => 2 None 2 None 0 Some ( "" ) 2 None ) ;
527
+ }
368
528
369
529
// Unit power.
370
- check ( "a" , 1 , & [ ( 0 , Some ( "a" ) ) , ( 0 , None ) ] ) ;
371
- check ( "a" , 1 , & [ ( 0 , Some ( "a" ) ) , ( 1 , None ) ] ) ;
372
- check ( "a" , 1 , & [ ( 0 , Some ( "a" ) ) , ( 2 , None ) ] ) ;
373
- check ( "a" , 1 , & [ ( 1 , None ) , ( 0 , None ) ] ) ;
374
- check ( "a" , 1 , & [ ( 1 , None ) , ( 1 , None ) ] ) ;
375
- check ( "a" , 1 , & [ ( 1 , None ) , ( 2 , None ) ] ) ;
376
- check ( "a" , 1 , & [ ( 2 , None ) , ( 0 , None ) ] ) ;
377
- check ( "a" , 1 , & [ ( 2 , None ) , ( 1 , None ) ] ) ;
378
- check ( "a" , 1 , & [ ( 2 , None ) , ( 2 , None ) ] ) ;
379
-
380
- check ( "ab" , 1 , & [ ( 0 , Some ( "a" ) ) , ( 0 , Some ( "b" ) ) , ( 0 , None ) ] ) ;
381
- check ( "ab" , 1 , & [ ( 1 , Some ( "b" ) ) , ( 0 , None ) , ( 0 , None ) ] ) ;
382
- check ( "ab" , 1 , & [ ( 2 , None ) , ( 0 , None ) , ( 0 , None ) ] ) ;
530
+ check ! ( "a" , 1 => 0 Some ( "a" ) 0 None 0 Some ( "a" ) 0 None ) ; // HERE: fix.
531
+ check ! ( "a" , 1 => 0 Some ( "a" ) 1 None 0 Some ( "a" ) 1 None ) ;
532
+ check ! ( "a" , 1 => 0 Some ( "a" ) 2 None 1 None 0 Some ( "a" ) ) ;
533
+ check ! ( "a" , 1 => 1 None 0 Some ( "a" ) 0 None 1 None ) ;
534
+ check ! ( "a" , 1 => 1 None 1 None 0 Some ( "a" ) 0 None ) ;
535
+ check ! ( "a" , 1 => 1 None 2 None 0 Some ( "a" ) 1 None ) ;
536
+ check ! ( "a" , 1 => 2 None 0 Some ( "a" ) 1 None 0 Some ( "a" ) ) ;
537
+ check ! ( "a" , 1 => 2 None 1 None 2 None 0 Some ( "a" ) ) ;
538
+ check ! ( "a" , 1 => 2 None 2 None 0 Some ( "a" ) 2 None ) ;
539
+
540
+ check ! ( "ab" , 1 => 0 Some ( "a" ) 0 Some ( "b" ) 0 None ) ;
541
+ check ! ( "ab" , 1 => 1 Some ( "b" ) 0 None 0 None ) ;
542
+ check ! ( "ab" , 1 => 2 None 0 None 0 None ) ;
383
543
}
384
544
}
0 commit comments