From 8215381747d5e2ced9772947b5a6a9add0c32506 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Thu, 16 Nov 2017 16:06:56 +0100
Subject: [PATCH] convert rep_len to VectorAccess

---
 .../r/nodes/builtin/base/RepeatLength.java    | 107 ++++++-----------
 .../truffle/r/test/ExpectedTestOutput.test    | 108 ++++++++++--------
 .../r/test/builtins/TestBuiltin_rep_len.java  |  66 +++++------
 3 files changed, 128 insertions(+), 153 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
index cf0a608ef1..a66473e331 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
@@ -12,40 +12,44 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import java.util.Arrays;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "rep_len", kind = INTERNAL, parameterNames = {"x", "length.out"}, behavior = PURE)
 public abstract class RepeatLength extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(RepeatLength.class);
-        casts.arg("x").allowNull().mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
-        // with default error message, SHOW_CALLER does not work
-        casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA());
+        casts.arg("x").allowNull().mustBe(abstractVectorValue().or(instanceOf(RExpression.class)), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
+        casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(singleElement()).findFirst().mustNotBeNA().mustBe(gte0());
     }
 
     @Specialization
@@ -106,72 +110,33 @@ public abstract class RepeatLength extends RBuiltinNode.Arg2 {
         return RDataFactory.createLogicalVector(array, value != RRuntime.LOGICAL_NA);
     }
 
-    //
-    // Specialization for vector values
-    //
-    @Specialization
-    protected RIntVector repLen(RAbstractIntVector value, int length) {
-        int[] array = new int[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RAbstractVector repLenCached(RAbstractVector x, int length,
+                    @Cached("x.access()") VectorAccess xAccess,
+                    @Cached("createNew(xAccess.getType())") VectorAccess resultAccess,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile,
+                    @Cached("create()") VectorFactory factory) {
+        try (SequentialIterator xIter = xAccess.access(x)) {
+            if (emptyProfile.profile(xAccess.getLength(xIter) == 0)) {
+                return factory.createVector(xAccess.getType(), length, true);
+            }
+            RAbstractVector result = factory.createVector(xAccess.getType(), length, false);
+            try (SequentialIterator resultIter = resultAccess.access(result)) {
+                while (resultAccess.next(resultIter)) {
+                    xAccess.nextWithWrap(xIter);
+                    resultAccess.setFromSameType(resultIter, xAccess, xIter);
+                }
+            }
+            result.setComplete(x.isComplete());
+            return result;
         }
-        return RDataFactory.createIntVector(array, value.isComplete());
     }
 
-    @Specialization
-    protected RDoubleVector repLen(RDoubleVector value, int length) {
-        double[] array = new double[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
-        }
-        return RDataFactory.createDoubleVector(array, value.isComplete());
+    @Specialization(replaces = "repLenCached")
+    protected RAbstractVector repLenGeneric(RAbstractVector x, int length,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile,
+                    @Cached("create()") VectorFactory factory) {
+        return repLenCached(x, length, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()), emptyProfile, factory);
     }
 
-    @Specialization
-    protected RStringVector repLen(RStringVector vectorToRepeat, int length) {
-        String[] result = new String[length];
-        int vectorToRepeatLength = vectorToRepeat.getLength();
-        for (int i = 0; i < length; i++) {
-            result[i] = vectorToRepeat.getDataAt(i % vectorToRepeatLength);
-        }
-        return RDataFactory.createStringVector(result, vectorToRepeat.isComplete());
-    }
-
-    @Specialization
-    protected RRawVector repLen(RRawVector value, int length) {
-        byte[] array = new byte[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getRawDataAt(j);
-        }
-        return RDataFactory.createRawVector(array);
-    }
-
-    @Specialization
-    protected RComplexVector repLen(RComplexVector value, int length) {
-        final int resultLength = length * 2;
-        double[] array = new double[resultLength];
-        for (int i = 0, j = 0; i < resultLength; i += 2, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j).getRealPart();
-            array[i + 1] = value.getDataAt(j).getImaginaryPart();
-        }
-        return RDataFactory.createComplexVector(array, value.isComplete());
-    }
-
-    @Specialization
-    protected RLogicalVector repLen(RLogicalVector value, int length) {
-        byte[] array = new byte[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
-        }
-        return RDataFactory.createLogicalVector(array, value.isComplete());
-    }
-
-    @Specialization
-    protected RList repLen(RList list, int length) {
-        Object[] data = new Object[length];
-        for (int i = 0; i < length; i++) {
-            data[i] = list.getDataAt(i % list.getLength());
-        }
-        return RDataFactory.createList(data);
-    }
 }
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 a2c4cbdf10..a56d8071cf 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
@@ -51224,130 +51224,138 @@ logical(0)
 Levels: A B C D
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#rep_len(1L, 4L)
-[1] 1 1 1 1
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len("RepeatTest", 5) }
+#rep_len('RepeatTest', 5)
 [1] "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1, 2) }
+#rep_len(1, 2)
 [1] 1 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 10) }
+#rep_len(1:4, 10)
  [1] 1 2 3 4 1 2 3 4 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 3) }
+#rep_len(1:4, 3)
 [1] 1 2 3
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 4) }
+#rep_len(1:4, 4)
 [1] 1 2 3 4
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(2+6i, 4) }
+#rep_len(1L, 4L)
+[1] 1 1 1 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#rep_len(2+6i, 4)
 [1] 2+6i 2+6i 2+6i 2+6i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(3.14159, 3) }
+#rep_len(3.14159, 3)
 [1] 3.14159 3.14159 3.14159
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, "7") }
+#rep_len(4, x='text')
+[1] "text" "text" "text" "text"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#rep_len(7, '7')
 [1] 7 7 7 7 7 7 7
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, NA) }
+#rep_len(7, NA)
 Error in rep_len(7, NA) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, NULL) }
+#rep_len(7, NULL)
 Error in rep_len(7, NULL) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, c(7, 42)) }
+#rep_len(7, c(7, 42))
 Error in rep_len(7, c(7, 42)) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, integer()) }
+#rep_len(7, integer())
 Error in rep_len(7, integer()) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(TRUE, 2) }
+#rep_len(TRUE, 2)
 [1] TRUE TRUE
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(c(2i+3, 4+2i), 4) }
-[1] 3+2i 4+2i 3+2i 4+2i
+#rep_len(c('abcd', 'efg'), 0)
+character(0)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(c(3.1415, 0.8), 1) }
-[1] 3.1415
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext#
-#{ rep_len(function() 42, 7) }
-Error in rep_len(function() 42, 7) : attempt to replicate non-vector
+#rep_len(c('abcd', 'efg'), 1)
+[1] "abcd"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ x<-as.raw(16); rep_len(x, 2) }
-[1] 10 10
+#rep_len(c('abcd', 'efg'), 14)
+ [1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
+[11] "abcd" "efg"  "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) }
-[1] 10 05 10 05 10
+#rep_len(c('abcd', 'efg'), 2)
+[1] "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(4, x="text")}
-[1] "text" "text" "text" "text"
+#rep_len(c('abcd', 'efg'), 7)
+[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 0)}
-character(0)
+#rep_len(c('abcd', 'efg'), 8)
+[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 1)}
-[1] "abcd"
+#rep_len(c(2i+3, 4+2i), 4)
+[1] 3+2i 4+2i 3+2i 4+2i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 14)}
- [1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
-[11] "abcd" "efg"  "abcd" "efg"
+#rep_len(c(3.1415, 0.8), 1)
+[1] 3.1415
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 2)}
-[1] "abcd" "efg"
+#rep_len(c(a=1,b=4), 4)
+[1] 1 4 1 4
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 7)}
-[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd"
+#rep_len(expression(1,4,'foo'), 7)
+expression(1, 4, "foo", 1, 4, "foo", 1)
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 8)}
-[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext#
+#rep_len(function() 42, 7)
+Error in rep_len(function() 42, 7) : attempt to replicate non-vector
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(length.out=4, "text")}
+#rep_len(length.out=4, 'text')
 [1] "text" "text" "text" "text"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(length.out=4, x=1:2)}
+#rep_len(length.out=4, x=1:2)
 [1] 1 2 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(x=1:2, length.out=4)}
+#rep_len(x=1:2, length.out=4)
 [1] 1 2 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{x<-"text"; length.out<-4; rep_len(length.out=length.out, x=x)}
+#x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x)
 [1] "text" "text" "text" "text"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{x<-"text"; length.out<-4; rep_len(x=x, length.out=length.out)}
+#x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out)
 [1] "text" "text" "text" "text"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#x<-as.raw(16); rep_len(x, 2)
+[1] 10 10
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5)
+[1] 10 05 10 05 10
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_repint.testRepInt#
 #{ rep.int("a",3) }
 [1] "a" "a" "a"
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
index 40ff969ca5..d41b15d4fb 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
@@ -20,41 +20,43 @@ public class TestBuiltin_rep_len extends TestBase {
 
     @Test
     public void testRepLen() {
-        assertEval("{ rep_len(1, 2) }");
-        assertEval("{ rep_len(3.14159, 3) }");
-        assertEval("{ rep_len(\"RepeatTest\", 5) }");
-        assertEval("{ rep_len(2+6i, 4) }");
-        assertEval("{ rep_len(TRUE, 2) }");
-        assertEval("{ x<-as.raw(16); rep_len(x, 2) }");
-
-        assertEval("{ rep_len(1:4, 10) }");
-        assertEval("{ rep_len(1:4, 3) }");
-        assertEval("{ rep_len(1:4, 4) }");
-        assertEval("{ rep_len(c(3.1415, 0.8), 1) }");
-        assertEval("{ rep_len(c(2i+3, 4+2i), 4) }");
-        assertEval("{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) }");
+        assertEval("rep_len(1, 2)");
+        assertEval("rep_len(3.14159, 3)");
+        assertEval("rep_len('RepeatTest', 5)");
+        assertEval("rep_len(2+6i, 4)");
+        assertEval("rep_len(TRUE, 2)");
+        assertEval("x<-as.raw(16); rep_len(x, 2)");
+
+        assertEval("rep_len(1:4, 10)");
+        assertEval("rep_len(1:4, 3)");
+        assertEval("rep_len(1:4, 4)");
+        assertEval("rep_len(c(3.1415, 0.8), 1)");
+        assertEval("rep_len(c(2i+3, 4+2i), 4)");
+        assertEval("x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5)");
         // cases with named arguments:
-        assertEval("{rep_len(x=1:2, length.out=4)}");
-        assertEval("{rep_len(length.out=4, x=1:2)}");
-        assertEval("{rep_len(length.out=4, \"text\")}");
-        assertEval("{rep_len(4, x=\"text\")}");
-        assertEval("{x<-\"text\"; length.out<-4; rep_len(x=x, length.out=length.out)}");
-        assertEval("{x<-\"text\"; length.out<-4; rep_len(length.out=length.out, x=x)}");
+        assertEval("rep_len(x=1:2, length.out=4)");
+        assertEval("rep_len(length.out=4, x=1:2)");
+        assertEval("rep_len(length.out=4, 'text')");
+        assertEval("rep_len(4, x='text')");
+        assertEval("x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out)");
+        assertEval("x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x)");
         // test string vector argument
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 7)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 14)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 8)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 0)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 1)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 2)}");
-
-        assertEval(Output.IgnoreErrorContext, "{ rep_len(function() 42, 7) }");
-        assertEval("{ rep_len(7, \"7\") }");
-        assertEval("{ rep_len(7, integer()) }");
-        assertEval("{ rep_len(7, NA) }");
-        assertEval("{ rep_len(7, NULL) }");
-        assertEval("{ rep_len(7, c(7, 42)) }");
+        assertEval("rep_len(c('abcd', 'efg'), 7)");
+        assertEval("rep_len(c('abcd', 'efg'), 14)");
+        assertEval("rep_len(c('abcd', 'efg'), 8)");
+        assertEval("rep_len(c('abcd', 'efg'), 0)");
+        assertEval("rep_len(c('abcd', 'efg'), 1)");
+        assertEval("rep_len(c('abcd', 'efg'), 2)");
+
+        assertEval(Output.IgnoreErrorContext, "rep_len(function() 42, 7)");
+        assertEval("rep_len(7, '7')");
+        assertEval("rep_len(7, integer())");
+        assertEval("rep_len(7, NA)");
+        assertEval("rep_len(7, NULL)");
+        assertEval("rep_len(7, c(7, 42))");
 
         assertEval("rep_len(1L, 4L)");
+        assertEval("rep_len(c(a=1,b=4), 4)");
+        assertEval("rep_len(expression(1,4,'foo'), 7)");
     }
 }
-- 
GitLab