You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2022/08/19 03:37:30 UTC
[groovy] 01/03: GROOVY-10710: operator == is slow when comparing primitive arrays and lists (port to 4_0_X)
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit bd45d5b86033b38c427df6a14646884f1760d674
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sun Aug 14 23:10:08 2022 +1000
GROOVY-10710: operator == is slow when comparing primitive arrays and lists (port to 4_0_X)
---
.../groovy/runtime/DefaultGroovyMethods.java | 16 +-
.../typehandling/DefaultTypeTransformation.java | 181 ++++++++++++++++++++-
.../DefaultTypeTransformationTest.groovy | 22 +++
3 files changed, 209 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 9402610ac8..c5e9b65a92 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -14975,7 +14975,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));
}
/**
@@ -14988,7 +14988,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));
}
/**
@@ -15001,7 +15001,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));
}
/**
@@ -15014,7 +15014,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));
}
/**
@@ -15027,7 +15027,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));
}
/**
@@ -15040,7 +15040,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));
}
/**
@@ -15053,7 +15053,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));
}
/**
@@ -15066,7 +15066,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 ac816bdf57..e19400fc31 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -46,8 +46,10 @@ 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.function.Supplier;
@@ -559,6 +561,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);
@@ -661,10 +838,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 5054fb57a3..a889287f71 100644
--- a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
@@ -234,6 +234,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) {