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 2021/04/12 09:23:30 UTC

[groovy] 13/25: GROOVY-9649: Make createRange create EmptyRanges when from != to

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

commit cca4515dc11ab13a8225f010cc7bc83a403b4e53
Author: Esko Toivonen <es...@tuni.fi>
AuthorDate: Wed Apr 7 17:48:08 2021 +0300

    GROOVY-9649: Make createRange create EmptyRanges when from != to
    
    Ranges like 0<..<1 should be EmptyRanges. One complicating fact is that
    ranges like 0<..<-1 can be used for list indexing, thus only ranges
    where from and to share the same sign (zeros and positives are
    considered equal) and their difference is one are treated as EmptyRanges.
---
 .../groovy/runtime/ScriptBytecodeAdapter.java      | 47 ++++++++++++++--------
 1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
index 5161f65..fdd593d 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -636,38 +636,53 @@ public class ScriptBytecodeAdapter {
     }
 
     public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) throws Throwable {
+        if (exclusiveLeft && exclusiveRight) {
+            if (compareEqual(from, to)) {
+                return new EmptyRange((Comparable) from);
+            }
+            Object tmpFrom;
+            if (compareLessThan(from, to)) {
+                tmpFrom = invokeMethod0(ScriptBytecodeAdapter.class, from, "next");
+            } else {
+                tmpFrom = invokeMethod0(ScriptBytecodeAdapter.class, from, "previous");
+            }
+            // Create an empty range if the difference between from and to is one and they have the same sign. This
+            // means that range syntaxes like 5<..<6 will result in an empty range, but 0<..<-1 won't, since the latter
+            // is used in list indexing where negative indices count from the end towards the beginning. Note that
+            // positive numbers and zeros are considered to have the same sign to make ranges like 0<..<1 be EmptyRanges
+            int fromComp = compareTo(from, 0);
+            int toComp = compareTo(to, 0);
+            boolean sameSign = (fromComp >= 0 && toComp >= 0) || (fromComp < 0 && toComp < 0);
+            if (compareEqual(tmpFrom, to) && sameSign) {
+                return new EmptyRange((Comparable) from);
+            }
+        }
+        if ((exclusiveLeft || exclusiveRight) && compareEqual(from, to)) {
+            return new EmptyRange((Comparable) from);
+        }
         if (from instanceof Integer && to instanceof Integer) {
             int ifrom = (Integer) from;
             int ito = (Integer) to;
             if ((!exclusiveLeft && !exclusiveRight) || ifrom != ito) {
-                // Currently, empty ranges where from != to and the range is full exclusive (e.g. 0<..<-1) are
-                // constructed as IntRanges. This is because these ranges can still be used to index into lists.
+                // Currently, empty ranges where from != to, the range is full exclusive (e.g. 0<..<-1) and from and to
+                // have a different sign are constructed as IntRanges. This is because these ranges can still be used to
+                // index into lists.
                 return new IntRange(!exclusiveLeft, !exclusiveRight, ifrom, ito);
-            } // else fall through for EmptyRange
-        }
-        if ((exclusiveLeft || exclusiveRight) && compareEqual(from, to)) {
-            return new EmptyRange((Comparable) from);
+            }
         }
         if (from instanceof Number && to instanceof Number) {
             return new NumberRange(comparableNumber((Number) from), comparableNumber((Number) to), !exclusiveLeft, !exclusiveRight);
         }
-        Boolean greater = null;
+        // ObjectRange does not include information about inclusivity, so we need to consider it here
         if (exclusiveRight) {
-            greater = compareGreaterThan(from, to);
-            if (greater) {
+            if (compareGreaterThan(from, to)) {
                 to = invokeMethod0(ScriptBytecodeAdapter.class, to, "next");
             } else {
                 to = invokeMethod0(ScriptBytecodeAdapter.class, to, "previous");
             }
         }
         if (exclusiveLeft) {
-            if (greater == null) {
-                greater = compareGreaterThan(from, to);
-            }
-            if (compareEqual(from, to)) {
-                return new EmptyRange((Comparable) from);
-            }
-            if (greater) {
+            if (compareGreaterThan(from, to)) {
                 from = invokeMethod0(ScriptBytecodeAdapter.class, from, "previous");
             } else {
                 from = invokeMethod0(ScriptBytecodeAdapter.class, from, "next");