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) {

Reply via email to