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 588da45c92 OAK-11543 : Add Iterables.elementEquals replacement in 
IterableUtils (#2131)
588da45c92 is described below

commit 588da45c92e034557dd32329cf5ba885b65ac7d3
Author: Rishabh Kumar <[email protected]>
AuthorDate: Tue Mar 4 14:22:32 2025 +0530

    OAK-11543 : Add Iterables.elementEquals replacement in IterableUtils (#2131)
    
    * OAK-11543 : replaced Guava's Iterables.elementEquals with oak-commons util
    
    * OAK-11543 : removed un-unsed import
    
    ---------
    
    Co-authored-by: Rishabh Kumar <[email protected]>
---
 .../oak/commons/collections/IterableUtils.java     |  37 ++++++
 .../oak/commons/collections/IteratorUtils.java     |  33 ++++++
 .../oak/commons/collections/IterableUtilsTest.java | 126 +++++++++++++++++++++
 .../oak/commons/collections/IteratorUtilsTest.java |  88 ++++++++++++++
 4 files changed, 284 insertions(+)

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 52cc0a36f6..c88b7b1d23 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
@@ -320,4 +320,41 @@ public class IterableUtils {
         final Iterable<T> iterable = () -> 
IteratorUtils.mergeSorted(org.apache.commons.collections4.IterableUtils.transformedIterable(iterables,
 Iterable::iterator), c);
         return 
org.apache.commons.collections4.IterableUtils.unmodifiableIterable(iterable);
     }
+
+    /**
+     * Checks if two iterables have the same elements in the same order.
+     * <p>
+     * This method iterates through both iterables and compares each 
corresponding pair of elements using
+     * {@link Objects#equals(Object, Object)}.
+     * <p>
+     * Note that both iterables will be fully traversed during the comparison.
+     *
+     * @param itr1 the first iterable to compare, may be null
+     * @param itr2 the second iterable to compare, may be null
+     * @return {@code true} if both iterables contain the same elements in the 
same order, {@code false} otherwise.
+     *         Returns {@code true} if both iterables are null and {@code 
false} if only one is null.
+     *
+     * @see IteratorUtils#elementsEqual(Iterator, Iterator)
+     */
+    public static boolean elementsEqual(final Iterable<?> itr1, final 
Iterable<?> itr2) {
+
+        if (itr1 == itr2) {
+            // Both are null or the same instance
+            return true;
+        }
+
+        if (itr1 == null || itr2 == null) {
+            // returns false if one of the iterator is null
+            return false;
+        }
+
+        if (itr1 instanceof Collection && itr2 instanceof Collection) {
+            Collection<?> c1 = (Collection<?>) itr1;
+            Collection<?> c2 = (Collection<?>) itr2;
+            if (c1.size() != c2.size()) {
+                return false;
+            }
+        }
+        return IteratorUtils.elementsEqual(itr1.iterator(), itr2.iterator());
+    }
 }
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 c392724501..1da3dfa3b1 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
@@ -144,4 +144,37 @@ public class IteratorUtils {
             return next;
         }
     }
+
+    /**
+     * Compares two iterators to determine if they contain the same elements 
in the same order.
+     * <p>
+     * This method iterates through both iterators and compares each 
corresponding pair of elements.
+     * <p>
+     * Note that this method consumes both iterators.
+     *
+     * @param iterator1 the first iterator to compare, may be null
+     * @param iterator2 the second iterator to compare, may be null
+     * @return {@code true} if both iterators contain the same number of 
elements and all corresponding elements
+     *         are equal, {@code false} otherwise.
+     */
+    public static boolean elementsEqual(final Iterator<?> iterator1, final 
Iterator<?> iterator2) {
+        if (iterator1 == iterator2) {
+            // returns true if both point to same object or both are null
+            return true;
+        }
+
+        if (iterator1 == null || iterator2 == null) {
+            // returns false if one of the iterator is null
+            return false;
+        }
+
+        while (iterator1.hasNext() && iterator2.hasNext()) {
+            if (!Objects.equals(iterator1.next(), iterator2.next())) {
+                return false;
+            }
+        }
+
+        // return true if both the iterators have same number of elements
+        return !iterator1.hasNext() && !iterator2.hasNext();
+    }
 }
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 2ab596addc..9c1aa94551 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
@@ -22,10 +22,12 @@ import org.apache.commons.collections4.Predicate;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.function.Function;
@@ -629,4 +631,128 @@ public class IterableUtilsTest {
         Assert.assertFalse(merged.iterator().hasNext());
         Assert.assertThrows(NoSuchElementException.class, () -> 
merged.iterator().next());
     }
+
+    @Test
+    public void testNullIterables() {
+        // Both null
+        Assert.assertTrue(IterableUtils.elementsEqual(null, null));
+
+        // One null
+        Assert.assertFalse(IterableUtils.elementsEqual(null, 
Collections.emptyList()));
+        
Assert.assertFalse(IterableUtils.elementsEqual(Collections.emptyList(), null));
+    }
+
+    @Test
+    public void testEmptyIterables() {
+        Iterable<String> empty1 = Collections.emptyList();
+        Iterable<String> empty2 = Collections.emptyList();
+
+        Assert.assertTrue(IterableUtils.elementsEqual(empty1, empty2));
+    }
+
+    @Test
+    public void testSameIterable() {
+        Iterable<String> iterable = Arrays.asList("a", "b", "c");
+        Assert.assertTrue(IterableUtils.elementsEqual(iterable, iterable));
+    }
+
+    @Test
+    public void testEqualIterables() {
+        Iterable<String> iterable1 = Arrays.asList("a", "b", "c");
+        Iterable<String> iterable2 = Arrays.asList("a", "b", "c");
+
+        Assert.assertTrue(IterableUtils.elementsEqual(iterable1, iterable2));
+    }
+
+    @Test
+    public void testDifferentElements() {
+        Iterable<String> iterable1 = Arrays.asList("a", "b", "c");
+        Iterable<String> iterable2 = Arrays.asList("a", "d", "c");
+
+        Assert.assertFalse(IterableUtils.elementsEqual(iterable1, iterable2));
+    }
+
+    @Test
+    public void testDifferentLengthsFirstLonger() {
+        Iterable<String> iterable1 = Arrays.asList("a", "b", "c", "d");
+        Iterable<String> iterable2 = Arrays.asList("a", "b", "c");
+
+        Assert.assertFalse(IterableUtils.elementsEqual(iterable1, iterable2));
+    }
+
+    @Test
+    public void testDifferentLengthsSecondLonger() {
+        Iterable<String> iterable1 = Arrays.asList("a", "b");
+        Iterable<String> iterable2 = Arrays.asList("a", "b", "c");
+
+        Assert.assertFalse(IterableUtils.elementsEqual(iterable1, iterable2));
+    }
+
+    @Test
+    public void testWithNullElements() {
+        Iterable<String> iterable1 = Arrays.asList("a", null, "c");
+        Iterable<String> iterable2 = Arrays.asList("a", null, "c");
+
+        Assert.assertTrue(IterableUtils.elementsEqual(iterable1, iterable2));
+
+        Iterable<String> iterable3 = Arrays.asList("a", null, "c");
+        Iterable<String> iterable4 = Arrays.asList("a", "b", "c");
+
+        Assert.assertFalse(IterableUtils.elementsEqual(iterable3, iterable4));
+    }
+
+    @Test
+    public void testCollectionSizeOptimization() {
+        // Different sizes should return false quickly without comparing 
elements
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+
+        for (int i = 0; i < 1000; i++) {
+            list1.add(i);
+        }
+
+        for (int i = 0; i < 999; i++) {
+            list2.add(i);
+        }
+
+        Assert.assertFalse(IterableUtils.elementsEqual(list1, list2));
+    }
+
+    @Test
+    public void testLargeIterables() {
+        // Create two large identical lists
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        for (int i = 0; i < 10000; i++) {
+            list1.add(i);
+            list2.add(i);
+        }
+
+        Assert.assertTrue(IterableUtils.elementsEqual(list1, list2));
+
+        // Modify one value in the second list
+        list2.set(9999, -1);
+        Assert.assertFalse(IterableUtils.elementsEqual(list1, list2));
+    }
+
+    @Test
+    public void testCustomIterableImplementations() {
+        // Test with a custom iterable implementation
+        Iterable<Integer> customIterable1 = () -> Arrays.asList(1, 2, 
3).iterator();
+        Iterable<Integer> customIterable2 = () -> Arrays.asList(1, 2, 
3).iterator();
+
+        Assert.assertTrue(IterableUtils.elementsEqual(customIterable1, 
customIterable2));
+
+        Iterable<Integer> customIterable3 = () -> Arrays.asList(1, 2, 
4).iterator();
+        Assert.assertFalse(IterableUtils.elementsEqual(customIterable1, 
customIterable3));
+    }
+
+    @Test
+    public void testMixedCollectionTypes() {
+        // Test with different collection implementations
+        List<String> arrayList = new ArrayList<>(Arrays.asList("a", "b", "c"));
+        List<String> linkedList = new LinkedList<>(Arrays.asList("a", "b", 
"c"));
+
+        Assert.assertTrue(IterableUtils.elementsEqual(arrayList, linkedList));
+    }
 }
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 02eefee034..5986534bc2 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
@@ -21,7 +21,9 @@ package org.apache.jackrabbit.oak.commons.collections;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
@@ -143,4 +145,90 @@ public class IteratorUtilsTest {
 
         Assert.assertThrows(NoSuchElementException.class, merged::next);
     }
+
+    @Test
+    public void testNullIterators() {
+        // Both null
+        Assert.assertTrue(IteratorUtils.elementsEqual(null, null));
+
+        // One null
+        Assert.assertFalse(IteratorUtils.elementsEqual(null, 
Collections.emptyIterator()));
+        
Assert.assertFalse(IteratorUtils.elementsEqual(Collections.emptyIterator(), 
null));
+    }
+
+    @Test
+    public void testEmptyIterators() {
+        Iterator<String> empty1 = Collections.emptyIterator();
+        Iterator<String> empty2 = Collections.emptyIterator();
+
+        Assert.assertTrue(IteratorUtils.elementsEqual(empty1, empty2));
+    }
+
+    @Test
+    public void testSameIterator() {
+        Iterator<String> iterator = Arrays.asList("a", "b", "c").iterator();
+        Assert.assertTrue(IteratorUtils.elementsEqual(iterator, iterator));
+    }
+
+    @Test
+    public void testEqualIterators() {
+        Iterator<String> iterator1 = Arrays.asList("a", "b", "c").iterator();
+        Iterator<String> iterator2 = Arrays.asList("a", "b", "c").iterator();
+
+        Assert.assertTrue(IteratorUtils.elementsEqual(iterator1, iterator2));
+    }
+
+    @Test
+    public void testDifferentElements() {
+        Iterator<String> iterator1 = Arrays.asList("a", "b", "c").iterator();
+        Iterator<String> iterator2 = Arrays.asList("a", "d", "c").iterator();
+
+        Assert.assertFalse(IteratorUtils.elementsEqual(iterator1, iterator2));
+    }
+
+    @Test
+    public void testDifferentLengthsFirstLonger() {
+        Iterator<String> iterator1 = Arrays.asList("a", "b", "c", 
"d").iterator();
+        Iterator<String> iterator2 = Arrays.asList("a", "b", "c").iterator();
+
+        Assert.assertFalse(IteratorUtils.elementsEqual(iterator1, iterator2));
+    }
+
+    @Test
+    public void testDifferentLengthsSecondLonger() {
+        Iterator<String> iterator1 = Arrays.asList("a", "b").iterator();
+        Iterator<String> iterator2 = Arrays.asList("a", "b", "c").iterator();
+
+        Assert.assertFalse(IteratorUtils.elementsEqual(iterator1, iterator2));
+    }
+
+    @Test
+    public void testWithNullElements() {
+        Iterator<String> iterator1 = Arrays.asList("a", null, "c").iterator();
+        Iterator<String> iterator2 = Arrays.asList("a", null, "c").iterator();
+
+        Assert.assertTrue(IteratorUtils.elementsEqual(iterator1, iterator2));
+
+        Iterator<String> iterator3 = Arrays.asList("a", null, "c").iterator();
+        Iterator<String> iterator4 = Arrays.asList("a", "b", "c").iterator();
+
+        Assert.assertFalse(IteratorUtils.elementsEqual(iterator3, iterator4));
+    }
+
+    @Test
+    public void testLargeIterators() {
+        // Create two large identical lists
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        for (int i = 0; i < 10000; i++) {
+            list1.add(i);
+            list2.add(i);
+        }
+
+        Assert.assertTrue(IteratorUtils.elementsEqual(list1.iterator(), 
list2.iterator()));
+
+        // Modify one value in the second list
+        list2.set(9999, -1);
+        Assert.assertFalse(IteratorUtils.elementsEqual(list1.iterator(), 
list2.iterator()));
+    }
 }

Reply via email to