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()));
+ }
}