@@ -56,13 +56,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F>
56
56
}
57
57
58
58
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
59
- let max_size = self
60
- . query_state
61
- . matched_archetype_ids
62
- . iter ( )
63
- . map ( |id| self . archetypes [ * id] . len ( ) )
64
- . sum ( ) ;
65
-
59
+ let max_size = self . cursor . remaining ( self . tables , self . archetypes ) ;
66
60
let archetype_query = Q :: IS_ARCHETYPAL && F :: IS_ARCHETYPAL ;
67
61
let min_size = if archetype_query { max_size } else { 0 } ;
68
62
( min_size, Some ( max_size) )
@@ -333,11 +327,16 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<
333
327
return None ;
334
328
}
335
329
336
- // first, iterate from last to first until next item is found
330
+ // TODO: can speed up the following code using `cursor.remaining()` instead of `next_item.is_none()`
331
+ // when Q::IS_ARCHETYPAL && F::IS_ARCHETYPAL
332
+ //
333
+ // let `i` be the index of `c`, the last cursor in `self.cursors` that
334
+ // returns `K-i` or more elements.
335
+ // Make cursor in index `j` for all `j` in `[i, K)` a copy of `c` advanced `j-i+1` times.
336
+ // If no such `c` exists, return `None`
337
337
' outer: for i in ( 0 ..K ) . rev ( ) {
338
338
match self . cursors [ i] . next ( self . tables , self . archetypes , self . query_state ) {
339
339
Some ( _) => {
340
- // walk forward up to last element, propagating cursor state forward
341
340
for j in ( i + 1 ) ..K {
342
341
self . cursors [ j] = self . cursors [ j - 1 ] . clone ( ) ;
343
342
match self . cursors [ j] . next ( self . tables , self . archetypes , self . query_state ) {
@@ -398,36 +397,29 @@ where
398
397
}
399
398
400
399
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
401
- if K == 0 {
402
- return ( 0 , Some ( 0 ) ) ;
403
- }
404
-
405
- let max_size: usize = self
406
- . query_state
407
- . matched_archetype_ids
408
- . iter ( )
409
- . map ( |id| self . archetypes [ * id] . len ( ) )
410
- . sum ( ) ;
411
-
412
- if max_size < K {
413
- return ( 0 , Some ( 0 ) ) ;
414
- }
415
- if max_size == K {
416
- return ( 1 , Some ( 1 ) ) ;
417
- }
418
-
419
400
// binomial coefficient: (n ; k) = n! / k!(n-k)! = (n*n-1*...*n-k+1) / k!
420
401
// See https://en.wikipedia.org/wiki/Binomial_coefficient
421
402
// See https://blog.plover.com/math/choose.html for implementation
422
403
// It was chosen to reduce overflow potential.
423
404
fn choose ( n : usize , k : usize ) -> Option < usize > {
405
+ if k > n || n == 0 {
406
+ return Some ( 0 ) ;
407
+ }
408
+ let k = k. min ( n - k) ;
424
409
let ks = 1 ..=k;
425
- let ns = ( n - k + 1 ..=n) . rev ( ) ;
410
+ let ns = ( n + 1 - k ..=n) . rev ( ) ;
426
411
ks. zip ( ns)
427
412
. try_fold ( 1_usize , |acc, ( k, n) | Some ( acc. checked_mul ( n) ? / k) )
428
413
}
429
- let smallest = K . min ( max_size - K ) ;
430
- let max_combinations = choose ( max_size, smallest) ;
414
+ // sum_i=0..k choose(cursors[i].remaining, k-i)
415
+ let max_combinations = self
416
+ . cursors
417
+ . iter ( )
418
+ . enumerate ( )
419
+ . try_fold ( 0 , |acc, ( i, cursor) | {
420
+ let n = cursor. remaining ( self . tables , self . archetypes ) ;
421
+ Some ( acc + choose ( n, K - i) ?)
422
+ } ) ;
431
423
432
424
let archetype_query = F :: IS_ARCHETYPAL && Q :: IS_ARCHETYPAL ;
433
425
let known_max = max_combinations. unwrap_or ( usize:: MAX ) ;
@@ -441,11 +433,7 @@ where
441
433
F : ArchetypeFilter ,
442
434
{
443
435
fn len ( & self ) -> usize {
444
- self . query_state
445
- . matched_archetype_ids
446
- . iter ( )
447
- . map ( |id| self . archetypes [ * id] . len ( ) )
448
- . sum ( )
436
+ self . size_hint ( ) . 0
449
437
}
450
438
}
451
439
@@ -562,6 +550,18 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
562
550
}
563
551
}
564
552
553
+ /// How many values will this cursor return?
554
+ fn remaining ( & self , tables : & ' w Tables , archetypes : & ' w Archetypes ) -> usize {
555
+ let remaining_matched: usize = if Self :: IS_DENSE {
556
+ let ids = self . table_id_iter . clone ( ) ;
557
+ ids. map ( |id| tables[ * id] . len ( ) ) . sum ( )
558
+ } else {
559
+ let ids = self . archetype_id_iter . clone ( ) ;
560
+ ids. map ( |id| archetypes[ * id] . len ( ) ) . sum ( )
561
+ } ;
562
+ remaining_matched + self . current_len - self . current_index
563
+ }
564
+
565
565
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
566
566
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
567
567
/// # Safety
0 commit comments