From 16c59a569d79f84cf2d38c59c93ba307c8250508 Mon Sep 17 00:00:00 2001
From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com>
Date: Tue, 23 Aug 2016 20:41:07 +0200
Subject: [PATCH] IsUnsorted builtin refactored, isType functions

---
 .../r/nodes/builtin/base/IsTypeFunctions.java |  35 ++--
 .../r/nodes/builtin/base/IsUnsorted.java      | 150 ++++++++++++++++--
 .../truffle/r/test/ExpectedTestOutput.test    |  20 +++
 .../test/builtins/TestBuiltin_isunsorted.java |   3 +
 .../r/test/builtins/TestBuiltin_isvector.java |   2 +
 5 files changed, 181 insertions(+), 29 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index 2d10974c2f..87b2f73c14 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -22,6 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
@@ -29,9 +32,9 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -46,7 +49,6 @@ import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RRaw;
@@ -66,21 +68,13 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @SuppressWarnings("unused")
 public class IsTypeFunctions {
 
-    protected abstract static class ErrorAdapter extends RBuiltinNode {
-        protected final BranchProfile errorProfile = BranchProfile.create();
+    protected abstract static class MissingAdapter extends RBuiltinNode {
 
-        protected RError missingError() throws RError {
-            errorProfile.enter();
-            throw RError.error(this, RError.Message.ARGUMENT_MISSING, "x");
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("x").mustBe(missingValue().not(), RError.Message.ARGUMENT_MISSING, "x");
         }
-    }
-
-    protected abstract static class MissingAdapter extends ErrorAdapter {
 
-        @Specialization
-        protected byte isType(RMissing value) throws RError {
-            throw missingError();
-        }
     }
 
     @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
@@ -476,21 +470,22 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.vector", kind = INTERNAL, parameterNames = {"x", "mode"}, behavior = PURE)
-    public abstract static class IsVector extends ErrorAdapter {
+    public abstract static class IsVector extends RBuiltinNode {
 
         private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("x").mustBe(missingValue().not(), RError.Message.ARGUMENT_MISSING, "x");
+            casts.arg("mode").defaultError(this, RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1));
+        }
+
         @Override
         public Object[] getDefaultParameterValues() {
             // INTERNAL does not need default parameters
             return RNode.EMPTY_OBJECT_ARRAY;
         }
 
-        @Specialization
-        protected byte isVector(RMissing value, String mode) {
-            throw missingError();
-        }
-
         @Specialization
         protected byte isVector(RAbstractVector x, String mode) {
             if (!namesOnlyOrNoAttr(x) || !modeIsAnyOrMatches(x, mode)) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
index 827a48a9ed..9642e599e9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
@@ -22,17 +22,29 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.binary.BinaryMapBooleanFunctionNode;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.Order.CmpNode;
+import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryCompare;
 
 @RBuiltin(name = "is.unsorted", kind = INTERNAL, parameterNames = {"x", "strictly"}, behavior = PURE)
@@ -41,14 +53,30 @@ import com.oracle.truffle.r.runtime.ops.BinaryCompare;
 public abstract class IsUnsorted extends RBuiltinNode {
 
     @Child private BinaryMapBooleanFunctionNode ge = new BinaryMapBooleanFunctionNode(BinaryCompare.GREATER_EQUAL.create());
+    @Child private BinaryMapBooleanFunctionNode gt = new BinaryMapBooleanFunctionNode(BinaryCompare.GREATER_THAN.create());
+
+    private final ConditionProfile strictlyProfile = ConditionProfile.createBinaryProfile();
+
+    @Child private RComplexComparator ccmp = new RComplexComparator();
+
+    @Override
+    protected void createCasts(CastBuilder casts) {
+        casts.arg("strictly").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).notNA().map(toBoolean());
+    }
 
     @Specialization
-    protected byte isUnsorted(RAbstractDoubleVector x, @SuppressWarnings("unused") byte strictly) {
+    protected byte isUnsorted(RAbstractDoubleVector x, boolean strictly) {
         double last = x.getDataAt(0);
         for (int k = 1; k < x.getLength(); k++) {
             double current = x.getDataAt(k);
-            if (ge.applyLogical(current, last) == RRuntime.LOGICAL_FALSE) {
-                return RRuntime.LOGICAL_TRUE;
+            if (strictlyProfile.profile(strictly)) {
+                if (ge.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            } else {
+                if (gt.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
             }
             last = current;
         }
@@ -56,12 +84,18 @@ public abstract class IsUnsorted extends RBuiltinNode {
     }
 
     @Specialization
-    protected byte isUnsorted(RAbstractIntVector x, @SuppressWarnings("unused") byte strictly) {
+    protected byte isUnsorted(RAbstractIntVector x, boolean strictly) {
         int last = x.getDataAt(0);
         for (int k = 1; k < x.getLength(); k++) {
             int current = x.getDataAt(k);
-            if (ge.applyLogical(current, last) == RRuntime.LOGICAL_FALSE) {
-                return RRuntime.LOGICAL_TRUE;
+            if (strictlyProfile.profile(strictly)) {
+                if (ge.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            } else {
+                if (gt.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
             }
             last = current;
         }
@@ -69,15 +103,113 @@ public abstract class IsUnsorted extends RBuiltinNode {
     }
 
     @Specialization
-    protected byte isUnsorted(RAbstractStringVector x, @SuppressWarnings("unused") byte strictly) {
+    protected byte isUnsorted(RAbstractStringVector x, boolean strictly) {
         String last = x.getDataAt(0);
         for (int k = 1; k < x.getLength(); k++) {
             String current = x.getDataAt(k);
-            if (ge.applyLogical(current, last) == RRuntime.LOGICAL_FALSE) {
-                return RRuntime.LOGICAL_TRUE;
+            if (strictlyProfile.profile(strictly)) {
+                if (ge.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            } else {
+                if (gt.applyLogical(last, current) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            }
+            last = current;
+        }
+        return RRuntime.LOGICAL_FALSE;
+    }
+
+    protected CmpNode createCmpNode() {
+        return CmpNodeGen.create();
+    }
+
+    @Specialization
+    protected byte isUnsorted(RAbstractRawVector x, boolean strictly) {
+        RRaw last = x.getDataAt(0);
+        for (int k = 1; k < x.getLength(); k++) {
+            RRaw current = x.getDataAt(k);
+            if (strictlyProfile.profile(strictly)) {
+                if (ge.applyRaw(last.getValue(), current.getValue()) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            } else {
+                if (gt.applyRaw(last.getValue(), current.getValue()) == RRuntime.LOGICAL_TRUE) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
             }
             last = current;
         }
         return RRuntime.LOGICAL_FALSE;
     }
+
+    @Specialization
+    protected byte isUnsorted(RAbstractComplexVector x, boolean strictly, @Cached("createCmpNode()") CmpNode cmpNode) {
+        int last = 0;
+        for (int k = 1; k < x.getLength(); k++) {
+            if (strictlyProfile.profile(strictly)) {
+                if (cmpNode.ccmp(x, last, k, true) >= 0) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            } else {
+                if (cmpNode.ccmp(x, last, k, true) > 0) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+            }
+            last = k;
+        }
+        return RRuntime.LOGICAL_FALSE;
+    }
+
+    @Fallback
+    @SuppressWarnings("unused")
+    protected byte isUnsortedFallback(Object x, boolean strictly) {
+        return RRuntime.LOGICAL_NA;
+    }
+
+    public final class RComplexComparator extends RBaseNode {
+
+        public Object execute(RComplex x, RComplex y, boolean naLast) {
+            // compare real parts
+            boolean nax = RRuntime.isNA(x.getRealPart());
+            boolean nay = RRuntime.isNA(y.getRealPart());
+            if (nax && nay) {
+                return 0;
+            }
+            if (nax) {
+                return naLast ? 1 : -1;
+            }
+            if (nay) {
+                return naLast ? -1 : 1;
+            }
+            if (x.getRealPart() < y.getRealPart()) {
+                return -1;
+            }
+            if (x.getRealPart() > y.getRealPart()) {
+                return 1;
+            }
+
+            // compare real parts
+            nax = RRuntime.isNA(x.getImaginaryPart());
+            nay = RRuntime.isNA(y.getImaginaryPart());
+            if (nax && nay) {
+                return 0;
+            }
+            if (nax) {
+                return naLast ? 1 : -1;
+            }
+            if (nay) {
+                return naLast ? -1 : 1;
+            }
+            if (x.getImaginaryPart() < y.getImaginaryPart()) {
+                return -1;
+            }
+            if (x.getImaginaryPart() > y.getImaginaryPart()) {
+                return 1;
+            }
+            return 0; // equal
+        }
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 02ae51b88c..f8ebefb298 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -24984,6 +24984,18 @@ Error: unexpected symbol in "0.2, 18, 20, 20, 22.7, 16.3, 18.7, 21, 24.5, 17.8,
 #argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));is.symbol(argv[[1]]);
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isunsorted.testIsUnsorted
+#{ is.unsorted(c(1+1i,2+1i,2+1i), strictly=FALSE) }
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isunsorted.testIsUnsorted
+#{ is.unsorted(c(1+1i,2+1i,2+1i), strictly=TRUE) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isunsorted.testIsUnsorted
+#{ is.unsorted(c(1,2,2,3), strictly=TRUE) }
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_isunsorted.testIsUnsorted
 #{ is.unsorted(c(1,2,3,4)) }
 [1] FALSE
@@ -25091,6 +25103,14 @@ Error: unexpected symbol in "0.2, 18, 20, 20, 22.7, 16.3, 18.7, 21, 24.5, 17.8,
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_isvector.testIsVector
 #{ x<-list(1,3); }
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isvector.testIsVector
+#{is.vector(c(1,2), TRUE);}
+Error in is.vector(x, mode) : invalid 'mode' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isvector.testIsVector
+#{is.vector(c(1,2), c("sss", "dddd"));}
+Error in is.vector(x, mode) : invalid 'mode' argument
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_isvector.testIsVector
 #{is.vector(c(TRUE,FALSE),"logical");}
 [1] TRUE
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isunsorted.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isunsorted.java
index a1981e67d9..be6652d29a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isunsorted.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isunsorted.java
@@ -95,5 +95,8 @@ public class TestBuiltin_isunsorted extends TestBase {
     public void testIsUnsorted() {
         assertEval("{ is.unsorted(c(1,2,3,4)) }");
         assertEval("{ is.unsorted(c(1,2,6,4)) }");
+        assertEval("{ is.unsorted(c(1,2,2,3), strictly=TRUE) }");
+        assertEval("{ is.unsorted(c(1+1i,2+1i,2+1i), strictly=FALSE) }");
+        assertEval("{ is.unsorted(c(1+1i,2+1i,2+1i), strictly=TRUE) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isvector.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isvector.java
index 01442b5c23..4cfb24acda 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isvector.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isvector.java
@@ -199,5 +199,7 @@ public class TestBuiltin_isvector extends TestBase {
         assertEval("{is.vector(c(TRUE,FALSE),\"logical\");}");
         assertEval("{x<-1;class(x)<-\"a\";is.vector(x);}");
         assertEval("{x<-1;names(x)<-\"a\";is.vector(x);}");
+        assertEval("{is.vector(c(1,2), c(\"sss\", \"dddd\"));}");
+        assertEval("{is.vector(c(1,2), TRUE);}");
     }
 }
-- 
GitLab