[1/2] groovy git commit: GROOVY-8545: DGM#intersect(Set, Iterable) throws ClassCastException if Iterable is larger than Set (closes #645)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[1/2] groovy git commit: GROOVY-8545: DGM#intersect(Set, Iterable) throws ClassCastException if Iterable is larger than Set (closes #645)

paulk
Repository: groovy
Updated Branches:
  refs/heads/master ebb1d1c19 -> cc23c7be9


GROOVY-8545: DGM#intersect(Set, Iterable) throws ClassCastException if Iterable is larger than Set (closes #645)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/86cb87b2
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/86cb87b2
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/86cb87b2

Branch: refs/heads/master
Commit: 86cb87b2a4192200e0b2cd2cd5886f107132bae3
Parents: ebb1d1c
Author: Hugues Lerebours <[hidden email]>
Authored: Tue Dec 19 18:37:56 2017 +0100
Committer: Paul King <[hidden email]>
Committed: Mon Apr 16 10:03:17 2018 +1000

----------------------------------------------------------------------
 .../groovy/runtime/DefaultGroovyMethods.java         | 10 ++--------
 src/test/groovy/GroovyMethodsTest.groovy             | 15 ++++++++++++---
 .../shell/completion/ImportsSyntaxCompletor.groovy   |  6 +++---
 3 files changed, 17 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/86cb87b2/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 07b7c25..a52abf9 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -12224,18 +12224,12 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if (left.isEmpty() || right.isEmpty())
             return createSimilarCollection(left, 0);
 
-        if (left.size() < right.size()) {
-            Collection<T> swaptemp = left;
-            left = right;
-            right = swaptemp;
-        }
-
         // TODO optimise if same type?
         // boolean nlgnSort = sameType(new Collection[]{left, right});
 
-        Collection<T> result = createSimilarCollection(left, left.size());
+        Collection<T> result = createSimilarCollection(left, Math.min(left.size(), right.size()));
         //creates the collection to look for values.
-        Collection<T> pickFrom = new TreeSet<T>(new NumberAwareComparator<T>());
+        Collection<T> pickFrom = new TreeSet<>(new NumberAwareComparator<>());
         pickFrom.addAll(left);
 
         for (final T t : right) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/86cb87b2/src/test/groovy/GroovyMethodsTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/GroovyMethodsTest.groovy b/src/test/groovy/GroovyMethodsTest.groovy
index 7f550af..903ea02 100644
--- a/src/test/groovy/GroovyMethodsTest.groovy
+++ b/src/test/groovy/GroovyMethodsTest.groovy
@@ -809,10 +809,10 @@ class GroovyMethodsTest extends GroovyTestCase {
     }
 
     void doIt(col) {
-        col.clear();
-        col.addAll(leftCol);
+        col.clear()
+        col.addAll(leftCol)
         // not really concerned about  correctness, rather that the method can be called, however..
-        assert col.intersect(rightCol) == ["2"]
+        assert col.intersect(rightCol) as List == ["2"]
     }
 
     void testFileWithReader() {
@@ -1565,6 +1565,15 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert [4, 5] == iterableA.intersect(iterableB)
     }
 
+    void testIntersectForSets() {
+        assert [].toSet() == [].toSet().intersect([] as Iterable)
+        assert [].toSet() == [].toSet().intersect([1, 2, 3] as Iterable)
+        assert [].toSet() == [1, 2, 3].toSet().intersect([] as Iterable)
+        assert [2, 3].toSet() == [2, 3, 4].toSet().intersect([1, 2, 3] as Iterable)
+        assert [2, 3, 4].toSet() == [2, 3, 4].toSet().intersect([1, 2, 3, 4] as Iterable)
+        assert [2, 3].toSet() == [2, 3, 4, 5].toSet().intersect([1, 2, 3] as Iterable)
+    }
+
     void testIntersectForMaps() {
         // GROOVY-7602
         def list1 = [[language: 'Java'], [language: 'Groovy'], [language: 'Scala']]

http://git-wip-us.apache.org/repos/asf/groovy/blob/86cb87b2/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
index cb446a6..67c9b22 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
@@ -105,12 +105,12 @@ class ImportsSyntaxCompletor implements IdentifierCompletor {
                 Class clazz = shell.interp.evaluate([className]) as Class
                 if (clazz != null) {
                     List<String> clazzSymbols = ReflectionCompletor.getPublicFieldsAndMethods(clazz, '')*.value
-                    List<String> importedSymbols;
+                    Collection<String> importedSymbols
                     if (symbolName == '*') {
-                        importedSymbols = clazzSymbols;
+                        importedSymbols = clazzSymbols
                     } else {
                         Set<String> acceptableMatches = [symbolName, symbolName + '(', symbolName + '()']
-                        importedSymbols = acceptableMatches.intersect(clazzSymbols)
+                        importedSymbols = (acceptableMatches as Collection).intersect(clazzSymbols)
                     }
                     matches.addAll(importedSymbols)
                 }

Reply | Threaded
Open this post in threaded view
|

[2/2] groovy git commit: GROOVY-8548: DGM#intersect should provide a variant with a comparator

paulk
GROOVY-8548: DGM#intersect should provide a variant with a comparator


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/cc23c7be
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/cc23c7be
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/cc23c7be

Branch: refs/heads/master
Commit: cc23c7be9213f1b73062858543a969705e011e2d
Parents: 86cb87b
Author: Paul King <[hidden email]>
Authored: Mon Apr 16 13:59:10 2018 +1000
Committer: Paul King <[hidden email]>
Committed: Mon Apr 16 13:59:10 2018 +1000

----------------------------------------------------------------------
 .../groovy/runtime/DefaultGroovyMethods.java    | 112 ++++++++++++++++++-
 1 file changed, 106 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/cc23c7be/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index a52abf9..4d4e3f6 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -12212,24 +12212,51 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Create a Collection composed of the intersection of both collections.  Any
      * elements that exist in both collections are added to the resultant collection.
-     * For collection of custom objects; objects should implement java.lang.Comparable
+     * For collections of custom objects; the objects should implement java.lang.Comparable
      * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+     * By default, Groovy uses a {@link NumberAwareComparator} when determining if an
+     * element exists in both collections.
      *
      * @param left  a Collection
      * @param right a Collection
      * @return a Collection as an intersection of both collections
+     * @see #intersect(Collection, Collection, Comparator)
      * @since 1.5.6
      */
     public static <T> Collection<T> intersect(Collection<T> left, Collection<T> right) {
+        return intersect(left, right, new NumberAwareComparator<>());
+    }
+
+    /**
+     * Create a Collection composed of the intersection of both collections.  Any
+     * elements that exist in both collections are added to the resultant collection.
+     * For collections of custom objects; the objects should implement java.lang.Comparable
+     * <pre class="groovyTestCase">
+     * assert [3,4] == [1,2,3,4].intersect([3,4,5,6], Comparator.naturalOrder())
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def one = ['a', 'B', 'c', 'd']
+     * def two = ['b', 'C', 'd', 'e']
+     * def compareIgnoreCase = { a, b -> a.toLowerCase() <=> b.toLowerCase() }
+     * assert one.intersect(two) == ['d']
+     * assert two.intersect(one) == ['d']
+     * assert one.intersect(two, compareIgnoreCase) == ['b', 'C', 'd']
+     * assert two.intersect(one, compareIgnoreCase) == ['B', 'c', 'd']
+     * </pre>
+     *
+     * @param left  a Collection
+     * @param right a Collection
+     * @param comparator a Comparator
+     * @return a Collection as an intersection of both collections
+     * @since 2.5.0
+     */
+    public static <T> Collection<T> intersect(Collection<T> left, Collection<T> right, Comparator<T> comparator) {
         if (left.isEmpty() || right.isEmpty())
             return createSimilarCollection(left, 0);
 
-        // TODO optimise if same type?
-        // boolean nlgnSort = sameType(new Collection[]{left, right});
-
         Collection<T> result = createSimilarCollection(left, Math.min(left.size(), right.size()));
         //creates the collection to look for values.
-        Collection<T> pickFrom = new TreeSet<>(new NumberAwareComparator<>());
+        Collection<T> pickFrom = new TreeSet<T>(comparator);
         pickFrom.addAll(left);
 
         for (final T t : right) {
@@ -12242,12 +12269,15 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Create a Collection composed of the intersection of both iterables.  Any
      * elements that exist in both iterables are added to the resultant collection.
-     * For collection of custom objects; objects should implement java.lang.Comparable
+     * For iterables of custom objects; the objects should implement java.lang.Comparable
      * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+     * By default, Groovy uses a {@link NumberAwareComparator} when determining if an
+     * element exists in both collections.
      *
      * @param left  an Iterable
      * @param right an Iterable
      * @return a Collection as an intersection of both iterables
+     * @see #intersect(Iterable, Iterable, Comparator)
      * @since 2.4.0
      */
     public static <T> Collection<T> intersect(Iterable<T> left, Iterable<T> right) {
@@ -12255,13 +12285,32 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a Collection composed of the intersection of both iterables.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * For iterables of custom objects; the objects should implement java.lang.Comparable
+     * <pre class="groovyTestCase">assert [3,4] == [1,2,3,4].intersect([3,4,5,6], Comparator.naturalOrder())</pre>
+     *
+     * @param left  an Iterable
+     * @param right an Iterable
+     * @param comparator a Comparator
+     * @return a Collection as an intersection of both iterables
+     * @since 2.5.0
+     */
+    public static <T> Collection<T> intersect(Iterable<T> left, Iterable<T> right, Comparator<T> comparator) {
+        return intersect(asCollection(left), asCollection(right), comparator);
+    }
+
+    /**
      * Create a List composed of the intersection of a List and an Iterable.  Any
      * elements that exist in both iterables are added to the resultant collection.
      * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+     * By default, Groovy uses a {@link NumberAwareComparator} when determining if an
+     * element exists in both collections.
      *
      * @param left  a List
      * @param right an Iterable
      * @return a List as an intersection of a List and an Iterable
+     * @see #intersect(List, Iterable, Comparator)
      * @since 2.4.0
      */
     public static <T> List<T> intersect(List<T> left, Iterable<T> right) {
@@ -12269,13 +12318,31 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a List composed of the intersection of a List and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [3,4] == [1,2,3,4].intersect([3,4,5,6])</pre>
+     *
+     * @param left  a List
+     * @param right an Iterable
+     * @param comparator a Comparator
+     * @return a List as an intersection of a List and an Iterable
+     * @since 2.5.0
+     */
+    public static <T> List<T> intersect(List<T> left, Iterable<T> right, Comparator<T> comparator) {
+        return (List<T>) intersect((Collection<T>) left, asCollection(right), comparator);
+    }
+
+    /**
      * Create a Set composed of the intersection of a Set and an Iterable.  Any
      * elements that exist in both iterables are added to the resultant collection.
      * <pre class="groovyTestCase">assert [4,5] as Set == ([1,2,3,4,5] as Set).intersect([4,5,6,7,8])</pre>
+     * By default, Groovy uses a {@link NumberAwareComparator} when determining if an
+     * element exists in both collections.
      *
      * @param left  a Set
      * @param right an Iterable
      * @return a Set as an intersection of a Set and an Iterable
+     * @see #intersect(Set, Iterable, Comparator)
      * @since 2.4.0
      */
     public static <T> Set<T> intersect(Set<T> left, Iterable<T> right) {
@@ -12283,13 +12350,31 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a Set composed of the intersection of a Set and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [3,4] as Set == ([1,2,3,4] as Set).intersect([3,4,5,6], Comparator.naturalOrder())</pre>
+     *
+     * @param left  a Set
+     * @param right an Iterable
+     * @param comparator a Comparator
+     * @return a Set as an intersection of a Set and an Iterable
+     * @since 2.5.0
+     */
+    public static <T> Set<T> intersect(Set<T> left, Iterable<T> right, Comparator<T> comparator) {
+        return (Set<T>) intersect((Collection<T>) left, asCollection(right), comparator);
+    }
+
+    /**
      * Create a SortedSet composed of the intersection of a SortedSet and an Iterable.  Any
      * elements that exist in both iterables are added to the resultant collection.
      * <pre class="groovyTestCase">assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])</pre>
+     * By default, Groovy uses a {@link NumberAwareComparator} when determining if an
+     * element exists in both collections.
      *
      * @param left  a SortedSet
      * @param right an Iterable
      * @return a Set as an intersection of a SortedSet and an Iterable
+     * @see #intersect(SortedSet, Iterable, Comparator)
      * @since 2.4.0
      */
     public static <T> SortedSet<T> intersect(SortedSet<T> left, Iterable<T> right) {
@@ -12297,6 +12382,21 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a SortedSet composed of the intersection of a SortedSet and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])</pre>
+     *
+     * @param left  a SortedSet
+     * @param right an Iterable
+     * @param comparator a Comparator
+     * @return a Set as an intersection of a SortedSet and an Iterable
+     * @since 2.5.0
+     */
+    public static <T> SortedSet<T> intersect(SortedSet<T> left, Iterable<T> right, Comparator<T> comparator) {
+        return (SortedSet<T>) intersect((Collection<T>) left, asCollection(right), comparator);
+    }
+
+    /**
      * Create a Map composed of the intersection of both maps.
      * Any entries that exist in both maps are added to the resultant map.
      * <pre class="groovyTestCase">assert [4:4,5:5] == [1:1,2:2,3:3,4:4,5:5].intersect([4:4,5:5,6:6,7:7,8:8])</pre>