From 00bf2a2808c69b4f9bc8a890cf0cd0ab7a52d063 Mon Sep 17 00:00:00 2001 From: Paul King Date: Fri, 24 Apr 2026 14:26:59 +1000 Subject: [PATCH] GROOVY-11957: Add DGM#grepping(Iterator) --- .../groovy/runtime/DefaultGroovyMethods.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index bb2a6a54344..be3aab3c345 100644 --- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java @@ -7735,6 +7735,90 @@ public static Set grep(Set self) { return grep(self, Closure.IDENTITY); } + //-------------------------------------------------------------------------- + // grepping + + /** + * Lazily returns an Iterator of items matching the given filter - calling the + * {@link #isCase(java.lang.Object, java.lang.Object)} method used by + * switch statements. This method can be used with different kinds of filters like + * regular expressions, classes, ranges etc. + *
+     * def iter = [1, 'a', 'aa', 2, 'bc', 3, 4.5].iterator()
+     * assert iter.grepping(Number).toList() == [1, 2, 3, 4.5]
+     * 
+ * + * @param self a source Iterator + * @param filter the filter to perform on each element (using the {@link #isCase(java.lang.Object, java.lang.Object)} method) + * @return an Iterator returning the filtered elements + * @since 6.0.0 + */ + public static Iterator grepping(Iterator self, Object filter) { + return new GrepIterator<>(self, filter); + } + + /** + * Lazily returns an Iterator of elements which satisfy Groovy truth. + * Equivalent to calling {@link #grepping(Iterator, Object)} with the IDENTITY Closure. + *
+     * def iter = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null].iterator()
+     * assert iter.grepping().toList() == [1, 2, true, 'foo', [4, 5]]
+     * 
+ * + * @param self a source Iterator + * @return an Iterator of elements satisfying Groovy truth + * @see Closure#IDENTITY + * @since 6.0.0 + */ + public static Iterator grepping(Iterator self) { + return grepping(self, Closure.IDENTITY); + } + + private static final class GrepIterator implements Iterator { + private final Iterator source; + private final Object filter; + private T current; + private boolean found; + + private GrepIterator(Iterator source, Object filter) { + this.source = source; + this.filter = filter; + this.found = false; + advance(); + } + + @Override + public boolean hasNext() { + return found; + } + + private void advance() { + while (!found && source.hasNext()) { + current = source.next(); + if (DefaultTypeTransformation.castToBoolean(InvokerHelper.invokeMethod(filter, "isCase", current))) { + found = true; + return; + } + } + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("GrepIterator has been exhausted and contains no more elements"); + } + T result = current; + found = false; + advance(); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + //-------------------------------------------------------------------------- // groupBy