[ 
https://issues.apache.org/jira/browse/COLLECTIONS-826?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claude Warren resolved COLLECTIONS-826.
---------------------------------------
    Resolution: Fixed

fixed by https://github.com/apache/commons-collections/pull/314

> BloomFilter: move CountingLongPredicate
> ---------------------------------------
>
>                 Key: COLLECTIONS-826
>                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-826
>             Project: Commons Collections
>          Issue Type: Improvement
>          Components: Collection
>    Affects Versions: 4.5
>            Reporter: Claude Warren
>            Assignee: Claude Warren
>            Priority: Minor
>              Labels: bloom-filter
>
>  
> {noformat}
>     class CountingLongPredicate implements LongPredicate {
>         int idx = 0;
>         final long[] ary;
>         final LongBiPredicate func;
>         CountingLongPredicate(long[] ary, LongBiPredicate func) {
>             this.ary = ary;
>             this.func = func;
>         }
>         @Override
>         public boolean test(long other) {
>             return func.test(idx == ary.length ? 0 : ary[idx++], other);
>         }
>         boolean forEachRemaining() {
>             while (idx != ary.length && func.test(ary[idx], 0)) {
>                 idx++;
>             }
>             return idx == ary.length;
>         }
>     }
> {noformat}
>  
> Since this is in the interface it is public. It should be an implementation 
> detail. Hiding it ensures it is a one time use only and prevents strangeness 
> when calling forEachRemaining (see below).
> idx will be initialsed as zero anyway so this can be removed: int idx = 0;
>  @aherbert aherbert on 27 Feb
> If func.test returns false the loop will terminate before idx == ary.length. 
> So we return false. However this allows forEachRemaining to be called again. 
> This will use the same position in the array again. If public (currently it 
> is not) then the method could be invoked multiple times and the behaviour is 
> not defined (especially since you have added no comment on this).
> However the class is public but the forEachRemaining method is package 
> private. I suggest moving this out of the interface so the class is package 
> private.
> Note: I tested a spliterator from the List returned from Arrays.asList. The 
> forEachRemaining can be invoked one time only. This behaviour can be obtained 
> by caching idx and setting it to the array length:
> {noformat}
> boolean forEachRemaining() {
>     int i = idx;
>     final long[] a = ary;
>     final int limit = a.length;
>     if (i != limit) {
>         // Prevent subsequent calls
>         idx = limit;
>         while (i != limit && func.test(a[i], 0)) {
>             i++;
>         }
>     }
>     return i == limit;
> }
> {noformat}
> However the code above as it stands could fail-fast and return false. Then be 
> invoked again, do nothing with the func but will return true. The idx could 
> be set above limit but this will only work if limit is not Integer.MAX_VALUE 
> (which is unlikely). This can be handled by using compared unsigned:
> {noformat}
> boolean forEachRemaining() {
>     int i = idx;
>     final long[] a = ary;
>     final int limit = a.length;
>     if (Integer.compareUnsigned(i, limit) < 0) {
>         while (i != limit && func.test(a[i], 0)) {
>             i++;
>         }
>         // Set the result for repeat calls
>         idx = i == limit ? i : -1;
>     }
>     return i == limit;
> }
> {noformat}
> This is over engineering a simple helper class. However a tiny optimisation 
> to use local references would be of benefit. So make the class package 
> private, add some javadoc and do:
> {noformat}
> /**
>  * Call the long-long consuming bi-predicate for each remaining unpaired long 
> in
>  * the input array. This method should be invoked after the predicate has been
>  * passed to {@link BitMapProducer#forEachBitMap(LongPredicate)} to consume 
> any
>  * unpaired bitmaps. The second argument to the bi-predicate will be zero.
>  *
>  * @return true if all calls the predicate were successful
>  */
> boolean forEachRemaining() {
>     int i = idx;
>     final long[] a = ary;
>     final int limit = a.length;
>     while (i != limit && func.test(a[i], 0)) {
>         i++;
>     }
>     return i == limit;
> }
> {noformat}



--
This message was sent by Atlassian Jira
(v8.20.7#820007)

Reply via email to