This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 60c123f9fc GROOVY-10710: operator == is slow when comparing primitive
arrays and lists
60c123f9fc is described below
commit 60c123f9fc9ae03f874a5af61d6bc5cd3e2ad9ad
Author: Paul King <[email protected]>
AuthorDate: Sun Aug 14 23:10:08 2022 +1000
GROOVY-10710: operator == is slow when comparing primitive arrays and lists
---
.../groovy/runtime/DefaultGroovyMethods.java | 16 +-
.../typehandling/DefaultTypeTransformation.java | 182 ++++++++++++++++++++-
.../DefaultTypeTransformationTest.groovy | 22 +++
3 files changed, 210 insertions(+), 10 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index f1b4bfb3de..6695419a25 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -14932,7 +14932,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Byte> toSet(byte[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -14945,7 +14945,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Boolean> toSet(boolean[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -14958,7 +14958,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Character> toSet(char[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -14971,7 +14971,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Short> toSet(short[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -14984,7 +14984,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Integer> toSet(int[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -14997,7 +14997,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Long> toSet(long[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -15010,7 +15010,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Float> toSet(float[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
@@ -15023,7 +15023,7 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
*/
@SuppressWarnings("unchecked")
public static Set<Double> toSet(double[] array) {
- return toSet(DefaultTypeTransformation.primitiveArrayToList(array));
+ return
toSet(DefaultTypeTransformation.primitiveArrayToUnmodifiableList(array));
}
/**
diff --git
a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index 173ad5a2c7..3727c16047 100644
---
a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++
b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -46,11 +46,14 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.BaseStream;
import java.util.stream.DoubleStream;
@@ -562,6 +565,181 @@ public class DefaultTypeTransformation {
return list;
}
+ /**
+ * Allows conversion of arrays into an immutable List view
+ *
+ * @param array an array
+ * @return a List view of the array
+ */
+ public static List primitiveArrayToUnmodifiableList(Object array) {
+ return new ArrayToUnmodifiableListAdapter(array);
+ }
+
+ static class ArrayToUnmodifiableListAdapter implements List {
+ private Object delegate;
+
+ public ArrayToUnmodifiableListAdapter(Object delegate) {
+ Objects.requireNonNull(delegate);
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int size() {
+ return Array.getLength(delegate);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ for (Object next : this) {
+ if (next.equals(o)) return true;
+ }
+ return false;
+ }
+
+ private class Itr implements Iterator {
+ private int idx = 0;
+
+ @Override
+ public boolean hasNext() {
+ return idx < size();
+ }
+
+ @Override
+ public Object next() {
+ return get(idx++);
+ }
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Itr();
+ }
+
+ @Override
+ public Object get(int index) {
+ Object item = Array.get(delegate, index);
+ if (item != null && item.getClass().isArray() &&
item.getClass().getComponentType().isPrimitive()) {
+ item = primitiveArrayToUnmodifiableList(item);
+ }
+ return item;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ int idx = 0;
+ boolean found = false;
+ while (!found && idx < size()) {
+ found = get(idx).equals(o);
+ if (!found) idx++;
+ }
+ return found ? idx : -1;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ int idx = size() - 1;
+ boolean found = false;
+ while (!found && idx >= 0) {
+ found = get(idx).equals(o);
+ if (!found) idx--;
+ }
+ return found ? idx : -1;
+ }
+
+ @Override
+ public boolean containsAll(Collection coll) {
+ for (Object next : coll) {
+ if (!contains(next)) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public ListIterator listIterator() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ListIterator listIterator(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List subList(int fromIndex, int toIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object[] toArray(Object[] a) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object set(int index, Object element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void add(int index, Object element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object remove(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(int index, Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeIf(Predicate filter) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
public static Object[] primitiveArrayBox(Object array) {
int size = Array.getLength(array);
Object[] ret = (Object[])
Array.newInstance(ReflectionCache.autoboxType(array.getClass().getComponentType()),
size);
@@ -664,10 +842,10 @@ public class DefaultTypeTransformation {
return compareArrayEqual(left, right);
}
if (leftClass.isArray() && leftClass.getComponentType().isPrimitive())
{
- left = primitiveArrayToList(left);
+ left = primitiveArrayToUnmodifiableList(left);
}
if (rightClass.isArray() &&
rightClass.getComponentType().isPrimitive()) {
- right = primitiveArrayToList(right);
+ right = primitiveArrayToUnmodifiableList(right);
}
if (left instanceof Object[] && right instanceof List) {
return DefaultGroovyMethods.equals((Object[]) left, (List) right);
diff --git
a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
index fc03274ae2..f27b7c603a 100644
---
a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
+++
b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
@@ -318,6 +318,28 @@ final class DefaultTypeTransformationTest {
assert G == N
}
+ @Test
+ void testPrimitiveArrayToUnmodifiableList() {
+ int[] nums = [1, 3, 3, 5]
+ def numList =
DefaultTypeTransformation.primitiveArrayToUnmodifiableList(nums)
+ assert numList.get(1) == 3
+ assert numList.contains(1)
+ assert numList.contains(3)
+ assert numList.contains(5)
+ assert !numList.contains(2)
+ assert numList.indexOf(1) == 0
+ assert numList.indexOf(3) == 1
+ assert numList.indexOf(5) == 3
+ assert numList.indexOf(2) == -1
+ assert numList.lastIndexOf(2) == -1
+ assert numList.lastIndexOf(3) == 2
+ assert numList.containsAll([5,3,1])
+ assert !numList.containsAll([5,3,2])
+ assert !numList.containsAll([4,3,1])
+ assert !numList.isEmpty()
+ assert numList.size() == 4
+ }
+
//--------------------------------------------------------------------------
private static void checkCompareToSymmetricSmallerThan(a, b) {