From 2b20964e2ace3d95b99b3d55c81c1f7a51851940 Mon Sep 17 00:00:00 2001
From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com>
Date: Thu, 6 Oct 2016 17:12:02 +0200
Subject: [PATCH] Complex and double numbers can be converted to String via
 static methods in Complex/DoubleVectorPrinter

---
 .../base/printer/ComplexVectorPrinter.java    | 63 ++++++++++++-------
 .../base/printer/DoubleVectorPrinter.java     | 60 +++++++++++++-----
 .../printer/ComplexVectorPrinterTest.java     | 38 +++++++++++
 .../base/printer/DoubleVectorPrinterTest.java | 36 +++++++++++
 4 files changed, 159 insertions(+), 38 deletions(-)
 create mode 100644 com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java
 create mode 100644 com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
index 56d6c09685..14a5015037 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 
 //Transcribed from GnuR, src/main/printutils.c
 
-final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
+public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
     static final ComplexVectorPrinter INSTANCE = new ComplexVectorPrinter();
 
@@ -74,6 +74,10 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
     }
 
     static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatComplexVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    }
+
+    static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
 
         int wr;
         int dr;
@@ -129,7 +133,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             } else {
                 /* real part */
 
-                tmp = zprecr(xi, pp.getDigits());
+                tmp = zprecr(xi, digits);
 
                 if (!RRuntime.isFinite(tmp.getRealPart())) {
                     if (RRuntime.isNAorNaN(tmp.getRealPart())) {
@@ -143,7 +147,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                     if (xi.getRealPart() != 0) {
                         allReZero = false;
                     }
-                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), pp);
+                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), digits);
 
                     left = sd.kpower + 1;
                     if (sd.roundingwidens) {
@@ -187,7 +191,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                     if (xi.getImaginaryPart() != 0) {
                         allImZero = false;
                     }
-                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), pp);
+                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), digits);
 
                     left = sd.kpower + 1;
                     if (sd.roundingwidens) {
@@ -221,7 +225,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* overall format for real part */
 
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             rt = 0;
         }
         if (mxl != RRuntime.INT_MIN_VALUE) {
@@ -245,7 +249,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* overall format for imaginary part */
 
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             irt = 0;
         }
         if (imxl != RRuntime.INT_MIN_VALUE) {
@@ -271,7 +275,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         if (allReZero) {
             er = dr = 0;
             wr = wF;
-            if (iwF <= wi + pp.getScipen()) {
+            if (iwF <= wi + sciPen) {
                 ei = 0;
                 if (nsmall > irt) {
                     irt = nsmall;
@@ -281,7 +285,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                 wi = iwF;
             }
         } else if (allImZero) {
-            if (wF <= wr + pp.getScipen()) {
+            if (wF <= wr + sciPen) {
                 er = 0;
                 if (nsmall > rt) {
                     rt = nsmall;
@@ -292,7 +296,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             }
             ei = di = 0;
             wi = iwF;
-        } else if (wF + iwF < wr + wi + 2 * pp.getScipen()) {
+        } else if (wF + iwF < wr + wi + 2 * sciPen) {
             er = 0;
             if (nsmall > rt) {
                 rt = nsmall;
@@ -335,8 +339,8 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* finally, ensure that there is space for NA */
 
-        if (naflag && wr + wi + 2 < pp.getNaWidth()) {
-            wr += (pp.getNaWidth() - (wr + wi + 2));
+        if (naflag && wr + wi + 2 < naWidth) {
+            wr += (naWidth - (wr + wi + 2));
         }
 
         return new ComplexVectorMetrics(wr, dr, er, wi, di, ei);
@@ -383,12 +387,29 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         }
     }
 
-    @TruffleBoundary
+    public static String encodeComplex(RComplex x) {
+        return encodeComplex(x, 15, 0, RRuntime.STRING_NA);
+    }
+
+    public static String encodeComplex(RComplex x, int digits) {
+        return encodeComplex(x, digits, 0, RRuntime.STRING_NA);
+    }
+
+    public static String encodeComplex(RComplex x, int digits, int sciPen, String naString) {
+        ComplexVectorMetrics cvm = formatComplexVector(x, 0, 1, 0, digits, sciPen, naString.length());
+        return encodeComplex(x, cvm, digits, naString);
+    }
+
     static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, PrintParameters pp) {
+        return encodeComplex(x, cvm, pp.getDigits(), pp.getNaString());
+    }
+
+    @TruffleBoundary
+    static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, int digits, String naString) {
         if (RRuntime.isNA(x.getRealPart()) || RRuntime.isNA(x.getImaginaryPart())) {
-            return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', pp);
+            return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', naString);
         } else {
-            String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', pp);
+            String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', digits, naString);
             int g = cvm.maxWidth - cvm.wr - cvm.wi - 2;
             if (g > 0) {
                 // fill the remaining space by blanks to fit the maxWidth
@@ -399,7 +420,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         }
     }
 
-    private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, PrintParameters pp) {
+    private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, int digits, String naString) {
         String buff;
         String im;
         String re;
@@ -422,27 +443,27 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             String fmt = "%" + Utils.asBlankArg(g) + "s";
             buff = Utils.snprintf(NB,
                             fmt, /* was "%*s%*s", R_print.gap, "", */
-                            pp.getNaString());
+                            naString);
         } else {
             /*
              * formatComplex rounded, but this does not, and we need to keep it that way so we don't
              * get strange trailing zeros. But we do want to avoid printing small exponentials that
              * are probably garbage.
              */
-            y = zprecr(x, pp.getDigits());
+            y = zprecr(x, digits);
             if (y.getRealPart() == 0.) {
-                re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, pp);
+                re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, naString);
             } else {
-                re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, pp);
+                re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, naString);
             }
             flagNegIm = xi < 0;
             if (flagNegIm) {
                 xi = -xi;
             }
             if (y.getImaginaryPart() == 0.) {
-                im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, pp);
+                im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, naString);
             } else {
-                im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, pp);
+                im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, naString);
             }
             buff = snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
index 9acc68d1a2..d01049d173 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
@@ -19,11 +19,12 @@ import java.text.DecimalFormat;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 //Transcribed from GnuR, src/main/format.c
 
-final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
+public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
 
     static final DoubleVectorPrinter INSTANCE = new DoubleVectorPrinter();
 
@@ -71,6 +72,10 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
     }
 
     static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatDoubleVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    }
+
+    static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
         int left;
         int right;
         int sleft;
@@ -116,7 +121,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                     neginf = true;
                 }
             } else {
-                ScientificDouble sd = scientific(xi, pp);
+                ScientificDouble sd = scientific(xi, digits);
                 sgn = sd.sgn;
                 nsig = sd.nsig;
                 kpower = sd.kpower;
@@ -167,7 +172,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
 
         /*-- These 'mxsl' & 'rgt' are used in F Format
          * AND in the ____ if(.) "F" else "E" ___ below: */
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             rgt = 0;
         }
         if (mxl < 0) {
@@ -185,7 +190,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         if (mxns != RRuntime.INT_MIN_VALUE) {
             d = mxns - 1;
             w = neg + (d != 0 ? 1 : 1) + d + 4 + e; /* width for E format */
-            if (wF <= w + pp.getScipen()) { /* Fixpoint if it needs less space */
+            if (wF <= w + sciPen) { /* Fixpoint if it needs less space */
                 e = 0;
                 if (nsmall > rgt) {
                     rgt = nsmall;
@@ -199,8 +204,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             d = 0;
             e = 0;
         }
-        if (naflag && w < pp.getNaWidth()) {
-            w = pp.getNaWidth();
+        if (naflag && w < naWidth) {
+            w = naWidth;
         }
         if (nanflag && w < 3) {
             w = 3;
@@ -244,6 +249,10 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
     }
 
     public static ScientificDouble scientific(double x, PrintParameters pp) {
+        return scientific(x, pp.getDigits());
+    }
+
+    public static ScientificDouble scientific(double x, int digits) {
         /*
          * for a number x , determine sgn = 1_{x < 0} {0/1} kpower = Exponent of 10; nsig =
          * min(R_print.digits, #{significant digits of alpha}) roundingwidens = 1 if rounding causes
@@ -277,7 +286,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                 r = x;
             }
 
-            if (pp.getDigits() >= DBL_DIG + 1) {
+            if (digits >= DBL_DIG + 1) {
                 // TODO:
                 // format_via_sprintf(r, pp.getDigits(), kpower, nsig);
                 roundingwidens = false;
@@ -285,8 +294,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                 throw new UnsupportedOperationException();
             }
 
-            kp = (int) Math.floor(Math.log10(r)) - pp.getDigits() + 1; // r = |x|;
-                                                                       // 10^(kp + digits - 1) <= r
+            kp = (int) Math.floor(Math.log10(r)) - digits + 1; // r = |x|;
+                                                               // 10^(kp + digits - 1) <= r
 
             double rPrec = r;
             /* use exact scaling factor in double precision, if possible */
@@ -307,7 +316,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             } else {
                 rPrec /= Math.pow(10, kp);
             }
-            if (rPrec < tbl[pp.getDigits()]) {
+            if (rPrec < tbl[digits]) {
                 rPrec *= 10.0;
                 kp--;
             }
@@ -317,8 +326,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
              */
             alpha = Math.round(rPrec);
 
-            nsig = pp.getDigits();
-            for (j = 1; j <= pp.getDigits(); j++) {
+            nsig = digits;
+            for (j = 1; j <= digits; j++) {
                 alpha /= 10.0;
                 if (alpha == Math.floor(alpha)) {
                     nsig--;
@@ -326,11 +335,11 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                     break;
                 }
             }
-            if (nsig == 0 && pp.getDigits() > 0) {
+            if (nsig == 0 && digits > 0) {
                 nsig = 1;
                 kp += 1;
             }
-            kpower = kp + pp.getDigits() - 1;
+            kpower = kp + digits - 1;
 
             /*
              * Scientific format may do more rounding than fixed format, e.g. 9996 with 3 digits is
@@ -339,7 +348,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
              * decimal place that will be cut off by rounding
              */
 
-            int rgt = pp.getDigits() - kpower;
+            int rgt = digits - kpower;
             /* bound rgt by 0 and KP_MAX */
             rgt = rgt < 0 ? 0 : rgt > KP_MAX ? KP_MAX : rgt;
             double fuzz = 0.5 / tbl[1 + rgt];
@@ -351,12 +360,29 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         return new ScientificDouble(sgn, kpower, nsig, roundingwidens);
     }
 
+    public static String encodeReal(double x) {
+        return encodeReal(x, 15, '.', 0, RRuntime.STRING_NA);
+    }
+
+    public static String encodeReal(double x, int digits) {
+        return encodeReal(x, digits, '.', 0, RRuntime.STRING_NA);
+    }
+
+    public static String encodeReal(double x, int digits, char cdec, int sciPen, String naString) {
+        DoubleVectorMetrics dm = formatDoubleVector(RDataFactory.createDoubleVectorFromScalar(x), 0, 1, 0, digits, sciPen, naString.length());
+        return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString);
+    }
+
+    static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) {
+        return encodeReal(initialX, w, d, e, cdec, pp.getNaString());
+    }
+
     static String encodeReal(double x, DoubleVectorMetrics dm, PrintParameters pp) {
         return encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', pp);
     }
 
     @TruffleBoundary
-    static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) {
+    static String encodeReal(double initialX, int w, int d, int e, char cdec, String naString) {
         final String buff;
         String fmt;
 
@@ -367,7 +393,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             int numBlanks = Math.min(w, (NB - 1));
             String naFmt = "%" + Utils.asBlankArg(numBlanks) + "s";
             if (RRuntime.isNA(x)) {
-                buff = snprintf(NB, naFmt, pp.getNaString());
+                buff = snprintf(NB, naFmt, naString);
             } else if (RRuntime.isNAorNaN(x)) {
                 buff = snprintf(NB, naFmt, "NaN");
             } else if (x > 0) {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java
new file mode 100644
index 0000000000..f95c7b59a4
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base.printer;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+
+import static org.junit.Assert.*;
+
+public class ComplexVectorPrinterTest {
+
+    @Test
+    public void testEncodeComplex() {
+        assertEquals("3.14159265358979e-05+3.1415926535898e-06i", ComplexVectorPrinter.encodeComplex(RDataFactory.createComplex(Math.PI / 100000, Math.PI / 1000000)));
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java
new file mode 100644
index 0000000000..4dcf54e8d8
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base.printer;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class DoubleVectorPrinterTest {
+
+    @Test
+    public void testEncodeReal() {
+        assertEquals("3.14159265358979e-06", DoubleVectorPrinter.encodeReal(Math.PI / 1000000));
+    }
+
+}
-- 
GitLab