Переглянути джерело

resolve #47: FilterIterator moved forward eagerly, without no reason

Ranides Atterwim 4 роки тому
батько
коміт
5bcd3aaa76

+ 21 - 19
assira.core/src/main/java/net/ranides/assira/collection/iterators/IteratorUtils.java

@@ -460,6 +460,7 @@ public final class IteratorUtils {
         private final boolean limit;
         private T next;
         private boolean hasNext;
+        private boolean isTerminated;
         private int index;
 
         public FilterIterator(Iterator<? extends T> iterator, Predicate<? super T> predicate, boolean limit) {
@@ -471,45 +472,46 @@ public final class IteratorUtils {
 			this.predicate = predicate;
             this.limit = limit;
             this.index = -1;
-            nextMatch();
+            this.hasNext = false;
+            this.isTerminated = false;
         }
 
         @Override
         public boolean hasNext() {
-            return hasNext;
-        }
-
-        @Override
-        public T next() {
-            if (!hasNext) {
-                throw new NoSuchElementException();
+            if(hasNext) {
+                return true;
+            }
+            if(isTerminated) {
+                return false;
             }
-            index++;
-            return nextMatch();
-        }
-
-        private T nextMatch() {
-            T last = next;
 
             while (iterator.hasNext()) {
                 T value = iterator.next();
                 if (predicate.test(index, value)) {
                     hasNext = true;
-                    next = value;
-                    return last;
+                    this.next = value;
+                    return true;
                 } else if(limit) {
                     break;
                 }
             }
+            isTerminated = true;
+            return false;
+        }
 
+        @Override
+        public T next() {
+            if(!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            index++;
             hasNext = false;
-            return last;
+            return next;
         }
 
         @Override
         public void remove() {
-            // impossible to implement both "hasNext" & "mutable methods" reliably
-            throw new UnsupportedOperationException();
+            iterator.remove();
         }
 
     }

+ 18 - 0
assira.core/src/test/java/net/ranides/assira/collection/iterators/IteratorUtilsTest.java

@@ -10,6 +10,7 @@ import java.io.BufferedReader;
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
@@ -174,6 +175,23 @@ public class IteratorUtilsTest {
             .function(new IteratorParams(), this::range2greater)
             .run();
     }
+    @Test
+    public void testFilter_Lazy() {
+        List<Integer> generated = new ArrayList<>();
+
+        Iterator<Integer> iterator = IteratorUtils.map(Arrays.asList(7, 8, 3, 4, 5, 6).iterator(), v -> {
+            generated.add(v);
+            return v;
+        });
+
+        Iterator<Integer> filtered = IteratorUtils.filter(iterator, v -> true);
+
+        assertTrue(generated.isEmpty());
+        assertTrue(filtered.hasNext());
+        assertEquals(Collections.singletonList(7), generated);
+        assertEquals(7, filtered.next().intValue());
+        assertEquals(Collections.singletonList(7), generated);
+    }
     
     @Test
 	public void testLimit_Iterator() {

+ 1 - 7
assira.core/src/test/java/net/ranides/assira/reflection/util/ServiceScannerTest.java

@@ -50,13 +50,7 @@ public class ServiceScannerTest {
         List<?> list = query.list();
 
         assertEquals(2,list.size());
-
-        // at this moment CQuery iterates a bit further than necessary
-        // it is acceptable in that sense, that it returns correct result...
-        // possibly that is because some iterators move forward inside `#hasNext` instead of `#next`?
-        // bug report is already created:
-        // https://git.ranides.net/projects/assira/issues/47
-        assertTrue(names.size() <= 3);
+        assertEquals(2, names.size());
     }
 
     public static class SpecialCharset extends CharsetProvider {