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 cd8c0f30f3 OAK-11680 : added Iterators.cycle replacement in 
oak-commons (#2250)
cd8c0f30f3 is described below

commit cd8c0f30f354b37e2b007cb926e83928b02be1e8
Author: Rishabh Kumar <[email protected]>
AuthorDate: Tue Apr 29 11:22:27 2025 +0530

    OAK-11680 : added Iterators.cycle replacement in oak-commons (#2250)
    
    Co-authored-by: Rishabh Kumar <[email protected]>
---
 .../oak/commons/collections/CollectionUtils.java   |  29 ++++++
 .../oak/commons/collections/IteratorUtils.java     |  45 +++++++++
 .../commons/collections/CollectionUtilsTest.java   |  76 ++++++++++++++-
 .../oak/commons/collections/IteratorUtilsTest.java | 105 +++++++++++++++++++++
 4 files changed, 251 insertions(+), 4 deletions(-)

diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtils.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtils.java
index a20affce1c..1c3bb714e2 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtils.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtils.java
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.commons.collections;
 
+import java.util.Collection;
+
 /**
  * Utility methods for collections conversions.
  */
@@ -49,4 +51,31 @@ public class CollectionUtils {
 
         return 1 + (int) (capacity / 0.75f);
     }
+
+    /**
+     * Converts an Iterable to a Collection.
+     * <p>
+     * If the provided iterable is already a Collection, it is simply cast and 
returned.
+     * Otherwise, the elements from the iterable are copied into a new List 
using
+     * {@link ListUtils#toList(Iterable)}.
+     * <p>
+     * Example usage:
+     * <pre>
+     * Iterable&lt;String&gt; iterable = () -> Arrays.asList("a", "b", 
"c").iterator();
+     * Collection&lt;String&gt; collection = 
CollectionUtils.asCollection(iterable);
+     * // collection will contain "a", "b", "c"
+     * </pre>
+     *
+     * @param <E> the type of elements in the iterable
+     * @param iterable the iterable to convert, must not be null
+     * @return a Collection containing all elements of the iterable
+     * @throws NullPointerException if the iterable is null
+     */
+    @SuppressWarnings("unchecked")
+    static <E> Collection<E> toCollection(final Iterable<? extends E> 
iterable) {
+        if (iterable instanceof Collection) {
+            return (Collection<E>) iterable;
+        }
+        return ListUtils.toList(iterable);
+    }
 }
\ No newline at end of file
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 214e404b47..b6830593e4 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
@@ -429,5 +429,50 @@ public class IteratorUtils {
     public static <F, T> Iterator<T> transform(Iterator<? extends F> itr, 
final Function<? super F, ? extends T> transform) {
         return 
org.apache.commons.collections4.IteratorUtils.transformedIterator(itr, 
transform::apply);
     }
+
+    /**
+     * Creates an iterator that cycles indefinitely over the provided elements.
+     * <p>
+     * The returned iterator will continuously loop through the given elements 
in the same order.
+     * If no elements are provided, the iterator will be empty.
+     * <p>
+     * Example usage:
+     * <pre>
+     * Iterator&lt;String&gt; cyclingIterator = IteratorUtils.cycle("a", "b", 
"c");
+     * // Iterates: "a", "b", "c", "a", "b", "c", ...
+     * </pre>
+     *
+     * @param <E> the type of elements in the iterator
+     * @param elements the elements to cycle through, must not be null
+     * @return an iterator that cycles indefinitely over the provided elements
+     * @throws NullPointerException if the elements array is null
+     */
+    @SafeVarargs
+    public static <E> Iterator<E> cycle(final E... elements) {
+        Objects.requireNonNull(elements, "elements must not be null");
+        return IteratorUtils.cycle(SetUtils.toLinkedSet(elements));
+    }
+
+    /**
+     * Creates an iterator that cycles indefinitely over the elements of the 
given iterable.
+     * <p>
+     * The returned iterator will continuously loop through the elements of 
the iterable in the same order.
+     * If the iterable is empty, the iterator will also be empty.
+     * <p>
+     * Example usage:
+     * <pre>
+     * List&lt;String&gt; list = Arrays.asList("a", "b", "c");
+     * Iterator&lt;String&gt; cyclingIterator = IteratorUtils.cycle(list);
+     * // Iterates: "a", "b", "c", "a", "b", "c", ...
+     * </pre>
+     *
+     * @param <E> the type of elements in the iterable
+     * @param iterable the iterable to cycle through, must not be null
+     * @return an iterator that cycles indefinitely over the elements of the 
iterable
+     * @throws NullPointerException if the iterable is null
+     */
+    public static <E> Iterator<E> cycle(final Iterable<E> iterable) {
+        return 
org.apache.commons.collections4.IteratorUtils.loopingIterator(CollectionUtils.toCollection(iterable));
+    }
 }
 
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtilsTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtilsTest.java
index 65d97851be..4b798fbbe8 100644
--- 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtilsTest.java
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/CollectionUtilsTest.java
@@ -21,7 +21,10 @@ package org.apache.jackrabbit.oak.commons.collections;
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.junit.Assert.fail;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 
 public class CollectionUtilsTest {
 
@@ -37,9 +40,74 @@ public class CollectionUtilsTest {
         Assert.assertEquals(1073741824, capacity);
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test
     public void ensureCapacityWithNegativeValue() {
-        int capacity = CollectionUtils.ensureCapacity(-8);
-        fail("Should throw IllegalArgumentException");
+        Assert.assertThrows(IllegalArgumentException.class, () -> 
CollectionUtils.ensureCapacity(-8));
+    }
+
+    @Test
+    public void testToCollectionWithCollection() {
+        // Create a Collection
+        Collection<String> original = Arrays.asList("a", "b", "c");
+
+        // Convert to Collection
+        Collection<String> result = CollectionUtils.toCollection(original);
+
+        // Verify it's the same instance
+        Assert.assertSame(original, result);
+        Assert.assertEquals(Arrays.asList("a", "b", "c"), result);
+    }
+
+    @Test
+    public void testToCollectionWithNonCollection() {
+        // Create a non-Collection Iterable using custom implementation
+        Iterable<Integer> iterable = () -> Arrays.asList(1, 2, 3).iterator();
+
+        // Convert to Collection
+        Collection<Integer> result = CollectionUtils.toCollection(iterable);
+
+        // Verify it created a new List with the correct elements
+        Assert.assertTrue(result instanceof List);
+        Assert.assertEquals(Arrays.asList(1, 2, 3), result);
+    }
+
+    @Test
+    public void testToCollectionWithNull() {
+        Assert.assertThrows(NullPointerException.class, () -> 
CollectionUtils.toCollection(null));
+    }
+
+    @Test
+    public void testToCollectionWithEmptyIterable() {
+        Iterable<String> empty = Collections.emptyList();
+        Collection<String> result = CollectionUtils.toCollection(empty);
+
+        Assert.assertTrue(result.isEmpty());
+        Assert.assertEquals(0, result.size());
+    }
+
+    @Test
+    public void testToCollectionWithCustomIterable() {
+        // Create a custom Iterable
+        Iterable<Character> chars = () -> Arrays.asList('a', 'b', 
'c').iterator();
+
+        Collection<Character> result = CollectionUtils.toCollection(chars);
+
+        Assert.assertEquals(3, result.size());
+        Assert.assertTrue(result.contains('a'));
+        Assert.assertTrue(result.contains('b'));
+        Assert.assertTrue(result.contains('c'));
+    }
+
+    @Test
+    public void testToCollectionMutability() {
+        // Create a non-Collection Iterable
+        Iterable<String> iterable = () -> Arrays.asList("a", "b").iterator();
+
+        // Convert to Collection
+        Collection<String> result = CollectionUtils.toCollection(iterable);
+
+        // Verify the resulting collection is mutable
+        result.add("c");
+        Assert.assertEquals(Arrays.asList("a", "b", "c"), result);
     }
 }
\ No newline at end of file
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 bb549e068c..ddcd9a8a7b 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
@@ -1030,4 +1030,109 @@ public class IteratorUtilsTest {
 
         Assert.assertEquals(Arrays.asList(4, 4, 4, 4), result);
     }
+
+    @Test
+    public void testCycleWithNonEmptyElements() {
+        Iterator<String> cyclingIterator = IteratorUtils.cycle("a", "b", "c");
+
+        Assert.assertTrue(cyclingIterator.hasNext());
+        Assert.assertEquals("a", cyclingIterator.next());
+        Assert.assertEquals("b", cyclingIterator.next());
+        Assert.assertEquals("c", cyclingIterator.next());
+        Assert.assertEquals("a", cyclingIterator.next()); // Cycles back
+        Assert.assertEquals("b", cyclingIterator.next()); // Cycles back
+        Assert.assertEquals("c", cyclingIterator.next()); // Cycles back
+    }
+
+    @Test
+    public void testCycleWithSingleElement() {
+        Iterator<Integer> cyclingIterator = IteratorUtils.cycle(42);
+
+        Assert.assertTrue(cyclingIterator.hasNext());
+        Assert.assertEquals(Integer.valueOf(42), cyclingIterator.next());
+        Assert.assertEquals(Integer.valueOf(42), cyclingIterator.next()); // 
Repeats
+    }
+
+    @Test
+    public void testCycleWithEmptyElements() {
+        Iterator<Object> cyclingIterator = IteratorUtils.cycle();
+
+        Assert.assertFalse(cyclingIterator.hasNext());
+    }
+
+    @Test
+    public void testCycleWithNullElements() {
+        Assert.assertThrows(NullPointerException.class,() -> 
IteratorUtils.cycle((String[]) null));
+    }
+
+    @Test
+    public void testCycleWithRemove() {
+        Iterator<String> cyclingIterator = IteratorUtils.cycle("x", "y");
+
+        Assert.assertEquals("x", cyclingIterator.next());
+        cyclingIterator.remove(); // Should remove "x"
+        Assert.assertEquals("y", cyclingIterator.next());
+        Assert.assertEquals("y", cyclingIterator.next());
+        cyclingIterator.remove(); // Should remove "y"
+        Assert.assertFalse(cyclingIterator.hasNext());
+    }
+
+    @Test
+    public void testCycleWithNonEmptyIterable() {
+        List<String> list = Arrays.asList("a", "b", "c");
+        Iterator<String> cyclingIterator = IteratorUtils.cycle(list);
+
+        Assert.assertTrue(cyclingIterator.hasNext());
+        Assert.assertEquals("a", cyclingIterator.next());
+        Assert.assertEquals("b", cyclingIterator.next());
+        Assert.assertEquals("c", cyclingIterator.next());
+        Assert.assertEquals("a", cyclingIterator.next()); // Cycles back
+    }
+
+    @Test
+    public void testCycleWithSingleElementIterable() {
+        List<Integer> list = Collections.singletonList(42);
+        Iterator<Integer> cyclingIterator = IteratorUtils.cycle(list);
+
+        Assert.assertTrue(cyclingIterator.hasNext());
+        Assert.assertEquals(Integer.valueOf(42), cyclingIterator.next());
+        Assert.assertEquals(Integer.valueOf(42), cyclingIterator.next()); // 
Repeats
+    }
+
+    @Test
+    public void testCycleWithEmptyIterable() {
+        List<Object> emptyList = Collections.emptyList();
+        Iterator<Object> cyclingIterator = IteratorUtils.cycle(emptyList);
+
+        Assert.assertFalse(cyclingIterator.hasNext());
+    }
+
+    @Test
+    public void testCycleWithNullIterable() {
+        Assert.assertThrows(NullPointerException.class, () -> 
IteratorUtils.cycle((Iterable<String>) null));
+    }
+
+    @Test
+    public void testCycleWithRemoveWhenIterableAllows() {
+        List<String> list = new ArrayList<>(Arrays.asList("x", "y"));
+        Iterator<String> cyclingIterator = IteratorUtils.cycle(list);
+
+        Assert.assertEquals("x", cyclingIterator.next());
+        cyclingIterator.remove(); // Removes "x"
+        Assert.assertEquals("y", cyclingIterator.next());
+        cyclingIterator.remove(); // Removes "y"
+        Assert.assertFalse(cyclingIterator.hasNext());
+    }
+
+    @Test
+    public void testCycleWithRemoveWhenIterableDisallows() {
+        List<String> list = Arrays.asList("x", "y");
+        Iterator<String> cyclingIterator = IteratorUtils.cycle(list);
+
+        Assert.assertEquals("x", cyclingIterator.next());
+        Assert.assertThrows(UnsupportedOperationException.class, 
cyclingIterator::remove); // Doesn't Removes "x"
+        Assert.assertEquals("y", cyclingIterator.next());
+        Assert.assertEquals("x", cyclingIterator.next());
+        Assert.assertTrue(cyclingIterator.hasNext());
+    }
 }

Reply via email to