This is an automated email from the ASF dual-hosted git repository.
daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new 6e532a4d12 OAK-11691 : added Iterators.partition replacement in
oak-commons (#2267)
6e532a4d12 is described below
commit 6e532a4d123136b38c65dd3fb905927f4e04f343
Author: Rishabh Kumar <[email protected]>
AuthorDate: Wed May 7 10:42:48 2025 +0530
OAK-11691 : added Iterators.partition replacement in oak-commons (#2267)
Co-authored-by: Rishabh Kumar <[email protected]>
---
.../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<Integer> numbers = Arrays.asList(1, 2, 3, 4,
5).iterator();
+ * Iterator<List<Integer>> 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);
+ }
}