This is an automated email from the ASF dual-hosted git repository.

daim pushed a commit to branch OAK-11691
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git

commit fd152d6cf67b488cf3a71172a1e7452c3b872c38
Author: Rishabh Kumar <d...@adobe.com>
AuthorDate: Sun May 4 13:35:10 2025 +0530

    OAK-11691 : added Iterators.partition replacement in oak-commons
---
 .../oak/commons/collections/IterableUtils.java     |  23 +----
 .../oak/commons/collections/IteratorUtils.java     |  57 +++++++++++
 .../oak/commons/collections/IterableUtilsTest.java |  25 +++++
 .../oak/commons/collections/IteratorUtilsTest.java | 111 +++++++++++++++++++++
 4 files changed, 194 insertions(+), 22 deletions(-)

diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java
index 9f7b8d393a..4f93afc75f 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java
@@ -238,28 +238,7 @@ public class IterableUtils {
         return new Iterable<>() {
             @Override
             public @NotNull Iterator<List<T>> iterator() {
-                return new Iterator<>() {
-                    private final Iterator<T> iterator = itr.iterator();
-
-                    @Override
-                    public boolean hasNext() {
-                        return iterator.hasNext();
-                    }
-
-                    @Override
-                    public List<T> next() {
-                        // check if there are elements left, throw an 
exception if not
-                        if (!hasNext()) {
-                            throw new NoSuchElementException();
-                        }
-
-                        List<T> currentPartition = new ArrayList<>(size);
-                        for (int i = 0; i < size && iterator.hasNext(); i++) {
-                            currentPartition.add(iterator.next());
-                        }
-                        return currentPartition;
-                    }
-                };
+                return IteratorUtils.partition(itr.iterator(), size);
             }
         };
     }
diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
index b6830593e4..7d98918b8c 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
@@ -20,12 +20,17 @@ package org.apache.jackrabbit.oak.commons.collections;
 
 import org.apache.commons.collections4.iterators.IteratorChain;
 import org.apache.commons.collections4.iterators.PeekingIterator;
+import org.apache.commons.collections4.iterators.UnmodifiableIterator;
+import org.apache.jackrabbit.oak.commons.conditions.Validate;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.Iterator;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.PriorityQueue;
@@ -474,5 +479,57 @@ public class IteratorUtils {
     public static <E> Iterator<E> cycle(final Iterable<E> iterable) {
         return 
org.apache.commons.collections4.IteratorUtils.loopingIterator(CollectionUtils.toCollection(iterable));
     }
+
+    /**
+     * Returns an iterator that partitions the elements of another iterator 
into fixed-size lists.
+     * <p>
+     * This method creates a new iterator that will group elements from the 
source iterator
+     * into lists of the specified size. The final list may be smaller than 
the requested size
+     * if there are not enough elements remaining in the source iterator.
+     * <p>
+     * The returned lists are unmodifiable. The source iterator is consumed 
only as the
+     * returned iterator is advanced.
+     * <p>
+     * Example usage:
+     * <pre>
+     * Iterator&lt;Integer&gt; numbers = Arrays.asList(1, 2, 3, 4, 
5).iterator();
+     * Iterator&lt;List&lt;Integer&gt;&gt; partitioned = 
IteratorUtils.partition(numbers, 2);
+     * // partitioned will iterate through [1, 2], [3, 4], [5]
+     * </pre>
+     *
+     * @param <T> the type of elements in the source iterator
+     * @param iterator the source iterator to partition, must not be null
+     * @param size the size of each partition, must be greater than 0
+     * @return an iterator of fixed-size lists containing the elements of the 
source iterator
+     * @throws NullPointerException if the iterator is null
+     * @throws IllegalArgumentException if size is less than or equal to 0
+     */
+    public static <T> Iterator<List<T>> partition(final Iterator<T> iterator, 
final int size) {
+
+        Objects.requireNonNull(iterator, "Iterator must not be null.");
+        Validate.checkArgument(size > 0, "Size must be greater than 0.");
+
+        return UnmodifiableIterator.unmodifiableIterator(new Iterator<>() {
+
+            @Override
+            public boolean hasNext() {
+                return iterator.hasNext();
+            }
+
+            @Override
+            public List<T> next() {
+                // check if there are elements left, throw an exception if not
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                final List<T> currentPartition = new ArrayList<>(size);
+                for (int i = 0; i < size && iterator.hasNext(); i++) {
+                    currentPartition.add(iterator.next());
+                }
+                return Collections.unmodifiableList(currentPartition);
+            }
+        });
+    }
 }
 
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
index 4acd80283c..7b8e17336b 100644
--- 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
@@ -400,6 +400,31 @@ public class IterableUtilsTest {
         Assert.assertThrows(NoSuchElementException.class, iterator::next);
     }
 
+    @Test
+    public void testPartitionReturnsUnmodifiableLists() {
+        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
+        Iterable<List<String>> partitioned = IterableUtils.partition(list, 2);
+
+        List<String> partition = partitioned.iterator().next();
+        Assert.assertThrows(UnsupportedOperationException.class, () -> 
partition.add("d")); // Should throw UnsupportedOperationException
+    }
+
+    @Test
+    public void testPartitionWithRemovableIterable() {
+        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
+        Iterable<List<String>> partitioned = IterableUtils.partition(list, 2);
+
+        // Get first partition
+        List<String> partition = partitioned.iterator().next();
+        Assert.assertEquals(Arrays.asList("a", "b"), partition);
+
+        // Original iterator shouldn't support removal through partition
+        Assert.assertThrows(UnsupportedOperationException.class, 
partitioned.iterator()::remove);
+
+        // But original list should still have all elements
+        Assert.assertEquals(Arrays.asList("a", "b", "c", "d"), list);
+    }
+
     @Test
     public void testFilterWithNonEmptyIterable() {
         Iterable<Integer> iterable = Arrays.asList(1, 2, 3, 4, 5);
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
index ddcd9a8a7b..7abc2a8186 100644
--- 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
@@ -1135,4 +1135,115 @@ public class IteratorUtilsTest {
         Assert.assertEquals("x", cyclingIterator.next());
         Assert.assertTrue(cyclingIterator.hasNext());
     }
+
+    @Test
+    public void testPartitionWithEvenDivision() {
+        List<String> list = Arrays.asList("a", "b", "c", "d");
+        Iterator<List<String>> partitioned = 
IteratorUtils.partition(list.iterator(), 2);
+
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Arrays.asList("a", "b"), partitioned.next());
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Arrays.asList("c", "d"), partitioned.next());
+        Assert.assertFalse(partitioned.hasNext());
+    }
+
+    @Test
+    public void testPartitionWithUnevenDivision() {
+        List<String> list = Arrays.asList("a", "b", "c", "d", "e");
+        Iterator<List<String>> partitioned = 
IteratorUtils.partition(list.iterator(), 2);
+
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Arrays.asList("a", "b"), partitioned.next());
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Arrays.asList("c", "d"), partitioned.next());
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(List.of("e"), partitioned.next());
+        Assert.assertFalse(partitioned.hasNext());
+    }
+
+    @Test
+    public void testPartitionWithEmptyIterator() {
+        Iterator<List<String>> partitioned = 
IteratorUtils.partition(Collections.emptyIterator(), 3);
+        Assert.assertFalse(partitioned.hasNext());
+    }
+
+    @Test
+    public void testPartitionWithSizeOne() {
+        List<Integer> list = Arrays.asList(1, 2, 3);
+        Iterator<List<Integer>> partitioned = 
IteratorUtils.partition(list.iterator(), 1);
+
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Collections.singletonList(1), partitioned.next());
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Collections.singletonList(2), partitioned.next());
+        Assert.assertTrue(partitioned.hasNext());
+        Assert.assertEquals(Collections.singletonList(3), partitioned.next());
+        Assert.assertFalse(partitioned.hasNext());
+    }
+
+    @Test
+    public void testPartitionWithLargeIterator() {
+        // Create a large list
+        List<Integer> list = new ArrayList<>();
+        for (int i = 0; i < 1000; i++) {
+            list.add(i);
+        }
+
+        Iterator<List<Integer>> partitioned = 
IteratorUtils.partition(list.iterator(), 100);
+
+        // Verify we get 10 partitions of 100 elements each
+        int partitionCount = 0;
+        while (partitioned.hasNext()) {
+            List<Integer> partition = partitioned.next();
+            if (partitionCount < 9) {
+                Assert.assertEquals(100, partition.size());
+            }
+            partitionCount++;
+        }
+        Assert.assertEquals(10, partitionCount);
+    }
+
+    @Test
+    public void testPartitionWithNullIterator() {
+        Assert.assertThrows(NullPointerException.class, () -> 
IteratorUtils.partition(null, 5));
+    }
+
+    @Test
+    public void testPartitionWithZeroSize() {
+        List<String> list = Arrays.asList("a", "b", "c");
+        Assert.assertThrows(IllegalArgumentException.class, () -> 
IteratorUtils.partition(list.iterator(), 0));
+    }
+
+    @Test
+    public void testPartitionWithNegativeSize() {
+        List<String> list = Arrays.asList("a", "b", "c");
+        Assert.assertThrows(IllegalArgumentException.class, () -> 
IteratorUtils.partition(list.iterator(), -1));
+    }
+
+    @Test
+    public void testPartitionReturnsUnmodifiableLists() {
+        List<String> list = Arrays.asList("a", "b", "c");
+        Iterator<List<String>> partitioned = 
IteratorUtils.partition(list.iterator(), 2);
+
+        List<String> partition = partitioned.next();
+        Assert.assertThrows(UnsupportedOperationException.class, () -> 
partition.add("d")); // Should throw UnsupportedOperationException
+    }
+
+    @Test
+    public void testPartitionWithRemovableIterator() {
+        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
+        Iterator<String> iterator = list.iterator();
+        Iterator<List<String>> partitioned = IteratorUtils.partition(iterator, 
2);
+
+        // Get first partition
+        List<String> partition = partitioned.next();
+        Assert.assertEquals(Arrays.asList("a", "b"), partition);
+
+        // Original iterator shouldn't support removal through partition
+        Assert.assertThrows(UnsupportedOperationException.class, 
partitioned::remove);
+
+        // But original list should still have all elements
+        Assert.assertEquals(Arrays.asList("a", "b", "c", "d"), list);
+    }
 }

Reply via email to