diff --git a/.gitignore b/.gitignore
index c36a62fb8f..23e8c9656a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@ atlassian-ide-plugin.xml
*.o
*.gimple
.Rproj.user
+.gradle
\ No newline at end of file
diff --git a/packages/stats/pom.xml b/packages/stats/pom.xml
index a6f7c2cc03..69ee25953d 100644
--- a/packages/stats/pom.xml
+++ b/packages/stats/pom.xml
@@ -65,6 +65,9 @@
gnur-sources-compile
compile
+
+ true
+
build
diff --git a/packages/stats/src/main/c/apply_optim.c b/packages/stats/src/main/c/apply_optim.c
index f8afbed2fd..d72a555239 100644
--- a/packages/stats/src/main/c/apply_optim.c
+++ b/packages/stats/src/main/c/apply_optim.c
@@ -641,7 +641,9 @@ void cgmin(int n, double *Bvec, double *X, double *Fmin,
}
/* include setulb() */
-#include "lbfgsb.c"
+void setulb(int n, int m, double *x, double *l, double *u, int *nbd,
+ double *f, double *g, double factr, double *pgtol,
+ double *wa, int * iwa, char *task, int iprint, int *isave);
void lbfgsb(int n, int m, double *x, double *l, double *u, int *nbd,
double *Fmin, optimfn fminfn, optimgr fmingr, int *fail,
diff --git a/packages/stats/src/main/c/lbfgsb.c b/packages/stats/src/main/c/lbfgsb.c
index 3c2819f007..7679644050 100644
--- a/packages/stats/src/main/c/lbfgsb.c
+++ b/packages/stats/src/main/c/lbfgsb.c
@@ -123,7 +123,6 @@ static void prn3lb(int n, double *x, double *f, char *task, int iprint,
/* ================ L-BFGS-B (version 2.3) ========================== */
-static
void setulb(int n, int m, double *x, double *l, double *u, int *nbd,
double *f, double *g, double factr, double *pgtol,
double *wa, int * iwa, char *task, int iprint, int *isave)
diff --git a/packages/stats/src/main/c/lbfgsb.h b/packages/stats/src/main/c/lbfgsb.h
new file mode 100644
index 0000000000..4fc78dfd45
--- /dev/null
+++ b/packages/stats/src/main/c/lbfgsb.h
@@ -0,0 +1,69 @@
+
+static void active(int, double *, double *, int *, double *, int *,
+ int, int *, int *, int *);
+static void bmv(int, double *, double *, int *, double *, double *, int *);
+static void cauchy(int, double *, double *,
+ double *, int *, double *, int *, int *,
+ double *, double *, double *, int, double *,
+ double *, double *, double *, double *, int * ,
+ int *, double *, double *, double *, double *,
+ int *, int, double *, int *, double *);
+static void cmprlb(int, int, double *,
+ double *, double *, double *, double *,
+ double *, double *, double *, double *, int *,
+ double *, int *, int *, int *, int *,
+ int *);
+static void dcsrch(double *, double *, double *,
+ double, double, double,
+ double, double, char *);
+static void dcstep(double *, double *,
+ double *, double *, double *, double *,
+ double *, double *, double *, int *, double *,
+ double *);
+static void errclb(int, int, double,
+ double *, double *, int *, char *, int *, int *);
+static void formk(int, int *, int *, int *, int *, int *, int *,
+ int *, double *, double *, int, double *,
+ double *, double *, double *, int *, int *, int *);
+static void formt(int, double *, double *,
+ double *, int *, double *, int *);
+static void freev(int, int *, int *,
+ int *, int *, int *, int *, int *, int *,
+ int *, int, int *);
+static void hpsolb(int, double *, int *, int);
+static void lnsrlb(int, double *, double *,
+ int *, double *, double *, double *, double *,
+ double *, double *, double *, double *,
+ double *, double *, double *, double *,
+ double *, double *, double *, int *, int *,
+ int *, int *, int *, char *, int *, int *,
+ char *);
+static void mainlb(int, int, double *,
+ double *, double *, int *, double *, double *,
+ double, double *, double *, double *,
+ double *, double *, double *, double *,
+ double *, double *, double *, double *,
+ double *, double *, int *, int *, int *, char *,
+ int, char *, int *);
+static void matupd(int, int, double *, double *, double *,
+ double *, double *, double *, int *, int *,
+ int *, int *, double *, double *, double *,
+ double *, double *);
+static void projgr(int, double *, double *,
+ int *, double *, double *, double *);
+static void subsm(int, int, int *, int *, double *, double *,
+ int *, double *, double *, double *, double *,
+ double *, int *, int *, int *, double *,
+ double *, int, int *);
+
+static void prn1lb(int n, int m, double *l, double *u, double *x,
+ int iprint, double epsmch);
+static void prn2lb(int n, double *x, double *f, double *g, int iprint,
+ int iter, int nfgv, int nact, double sbgnrm,
+ int nint, char *word, int iword, int iback,
+ double stp, double xstep);
+static void prn3lb(int n, double *x, double *f, char *task, int iprint,
+ int info, int iter, int nfgv, int nintol, int nskip,
+ int nact, double sbgnrm, int nint,
+ char *word, int iback, double stp, double xstep,
+ int k);
\ No newline at end of file
diff --git a/script-engine/src/test/java/org/renjin/script/OptimMultiThreadTest.java b/script-engine/src/test/java/org/renjin/script/OptimMultiThreadTest.java
new file mode 100644
index 0000000000..babd45de1b
--- /dev/null
+++ b/script-engine/src/test/java/org/renjin/script/OptimMultiThreadTest.java
@@ -0,0 +1,90 @@
+/*
+ * Renjin : JVM-based interpreter for the R language for the statistical analysis
+ * Copyright © 2010-${$file.lastModified.year} BeDataDriven Groep B.V. and contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, a copy is available at
+ * https://www.gnu.org/licenses/gpl-2.0.txt
+ *
+ */
+
+package org.renjin.script;
+
+import org.junit.Test;
+import org.renjin.sexp.DoubleVector;
+import org.renjin.sexp.ListVector;
+
+import javax.script.ScriptEngine;
+
+public class OptimMultiThreadTest {
+ private static final ThreadLocal engines = new ThreadLocal<>();
+ private static final int RUNS = 20;
+ private static final int THREADS_NUMBER = 2;
+
+
+ @Test
+ public void testMultithread() throws InterruptedException {
+ Thread[] threads = new Thread[THREADS_NUMBER];
+ for (int i = 0; i < THREADS_NUMBER; i++) {
+ threads[i] = new Thread(this::task);
+ threads[i].start();
+ }
+ for (int i = 0; i < THREADS_NUMBER; i++) {
+ threads[i].join();
+
+ }
+ }
+
+ private void task() {
+ ScriptEngine engine = getEngine();
+ try {
+ // Rosenbrock Banana function
+ engine.eval("fr <- function(x) { " +
+ " x1 <- x[1]\n" +
+ " x2 <- x[2]\n" +
+ " 100 * (x2 - x1 * x1) ^ 2 + (1 - x1) ^ 2\n" +
+ "}");
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ }
+ for (int i = 0; i < RUNS; i++) {
+ try {
+ ListVector result = (ListVector) engine.eval("optim(c(-1.2,1), fr, method = \"L-BFGS\")");
+ System.out.println(result);
+
+ DoubleVector parameters = (DoubleVector) result.get("par");
+ double p0 = parameters.getElementAsDouble(0);
+ double p1 = parameters.getElementAsDouble(1);
+ if(Math.abs(p0 - 0.9998000) > 0.00001) {
+ throw new AssertionError("Incorrect result: p0 = " + String.format("%f", p0));
+ }
+ if(Math.abs(p1 - 0.9996001) > 0.00001) {
+ throw new AssertionError("Incorrect result: p1 = " + String.format("%f", p1));
+ }
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ }
+ }
+ }
+
+ private ScriptEngine getEngine() {
+ ScriptEngine engine = engines.get();
+ if (engine == null) {
+ RenjinScriptEngineFactory factory = new RenjinScriptEngineFactory();
+ engine = factory.getScriptEngine();
+ engines.set(engine);
+ }
+ return engine;
+ }
+
+}
diff --git a/tests/src/test/R/test.format.R b/tests/src/test/R/test.format.R
new file mode 100644
index 0000000000..45ff314352
--- /dev/null
+++ b/tests/src/test/R/test.format.R
@@ -0,0 +1,23 @@
+#
+# Renjin : JVM-based interpreter for the R language for the statistical analysis
+# Copyright © 2010-2019 BeDataDriven Groep B.V. and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, a copy is available at
+# https://www.gnu.org/licenses/gpl-2.0.txt
+#
+library(hamcrest)
+
+test.format.double <- function() {
+ assertThat(format(1/3), equalTo("0.3333333"))
+}
\ No newline at end of file
diff --git a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/FunctionGenerator.java b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/FunctionGenerator.java
index 80e0790aa7..68b10c0468 100644
--- a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/FunctionGenerator.java
+++ b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/FunctionGenerator.java
@@ -73,6 +73,7 @@ public class FunctionGenerator implements InvocationStrategy {
private TypeOracle typeOracle;
private FunctionOracle functionOracle;
private ExprFactory exprFactory;
+ private List globalVarTransformers;
private LocalStaticVarAllocator staticVarAllocator;
private LocalVariableTable localSymbolTable;
private LocalVariableTable localStaticSymbolTable;
@@ -85,7 +86,9 @@ public class FunctionGenerator implements InvocationStrategy {
private boolean compilationFailed = false;
public FunctionGenerator(String className, GimpleFunction function, TypeOracle typeOracle,
- GlobalVarAllocator globalVarAllocator, UnitSymbolTable symbolTable) {
+ GlobalVarAllocator globalVarAllocator,
+ List globalVarTransformers,
+ UnitSymbolTable symbolTable) {
this.className = className;
this.function = function;
this.typeOracle = typeOracle;
@@ -103,6 +106,7 @@ public FunctionGenerator(String className, GimpleFunction function, TypeOracle t
this.staticVarAllocator = new LocalStaticVarAllocator("$" + function.getSafeMangledName() + "$", globalVarAllocator);
this.localSymbolTable = new LocalVariableTable(symbolTable);
this.localStaticSymbolTable = new LocalVariableTable(symbolTable);
+ this.globalVarTransformers = globalVarTransformers;
}
@@ -375,15 +379,14 @@ private void scheduleLocalVariables() {
}
try {
- GExpr generator = functionOracle.variable(varDecl,
- varDecl.isStatic() ?
- staticVarAllocator :
- mv.getLocalVarAllocator());
-
- localSymbolTable.addVariable(varDecl.getId(), generator);
-
if(varDecl.isStatic()) {
+ GExpr generator = localStaticGenerator(varDecl);
+ localSymbolTable.addVariable(varDecl.getId(), generator);
localStaticSymbolTable.addVariable(varDecl.getId(), generator);
+
+ } else {
+ localSymbolTable.addVariable(varDecl.getId(),
+ functionOracle.variable(varDecl, mv.getLocalVarAllocator()));
}
} catch (Exception e) {
@@ -392,6 +395,15 @@ private void scheduleLocalVariables() {
}
}
+ private GExpr localStaticGenerator(GimpleVarDecl varDecl) {
+ for (GlobalVarTransformer globalVarTransformer : globalVarTransformers) {
+ if(globalVarTransformer.acceptLocalStaticVar(varDecl)) {
+ return globalVarTransformer.generator(typeOracle, function, varDecl);
+ }
+ }
+ return functionOracle.variable(varDecl, staticVarAllocator);
+ }
+
private void emitBasicBlock(GimpleBasicBlock basicBlock) {
mv.visitLabel(labels.of(basicBlock));
diff --git a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/GlobalVarTransformer.java b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/GlobalVarTransformer.java
index 5b30536d52..0ea66c6a9e 100644
--- a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/GlobalVarTransformer.java
+++ b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/GlobalVarTransformer.java
@@ -21,10 +21,17 @@
import org.renjin.gcc.codegen.expr.GExpr;
import org.renjin.gcc.codegen.type.TypeOracle;
import org.renjin.gcc.gimple.GimpleCompilationUnit;
+import org.renjin.gcc.gimple.GimpleFunction;
import org.renjin.gcc.gimple.GimpleVarDecl;
public interface GlobalVarTransformer {
- boolean accept(GimpleVarDecl decl);
+
+ boolean acceptGlobalVar(GimpleVarDecl decl);
+
+ boolean acceptLocalStaticVar(GimpleVarDecl decl);
GExpr generator(TypeOracle typeOracle, GimpleCompilationUnit unit, GimpleVarDecl decl);
+
+ GExpr generator(TypeOracle typeOracle, GimpleFunction function, GimpleVarDecl decl);
+
}
diff --git a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/ProvidedVarTransformer.java b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/ProvidedVarTransformer.java
index 265e4cb349..a7d5aae793 100644
--- a/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/ProvidedVarTransformer.java
+++ b/tools/gcc-bridge/compiler/src/main/java/org/renjin/gcc/codegen/ProvidedVarTransformer.java
@@ -22,6 +22,7 @@
import org.renjin.gcc.codegen.expr.GExpr;
import org.renjin.gcc.codegen.type.TypeOracle;
import org.renjin.gcc.gimple.GimpleCompilationUnit;
+import org.renjin.gcc.gimple.GimpleFunction;
import org.renjin.gcc.gimple.GimpleVarDecl;
import java.util.Map;
@@ -37,12 +38,22 @@ public ProvidedVarTransformer(TypeOracle typeOracle, Map globalVarTransfor
GimpleVarDecl decl) {
for (GlobalVarTransformer transformer : globalVarTransformers) {
- if(transformer.accept(decl)) {
+ if(transformer.acceptGlobalVar(decl)) {
return transformer.generator(typeOracle, this.unit, decl);
}
}
diff --git a/tools/gcc-bridge/runtime/src/main/java/org/renjin/gcc/runtime/PointerPtr.java b/tools/gcc-bridge/runtime/src/main/java/org/renjin/gcc/runtime/PointerPtr.java
index 25a7e30695..5499c7037a 100644
--- a/tools/gcc-bridge/runtime/src/main/java/org/renjin/gcc/runtime/PointerPtr.java
+++ b/tools/gcc-bridge/runtime/src/main/java/org/renjin/gcc/runtime/PointerPtr.java
@@ -25,7 +25,7 @@
*/
public class PointerPtr extends AbstractPtr {
- private static final int BYTES = 4;
+ public static final int BYTES = 4;
public static final PointerPtr NULL = new PointerPtr(null, 0);
diff --git a/tools/gnur-compiler/src/main/java/org/renjin/gnur/ContextVarAllocator.java b/tools/gnur-compiler/src/main/java/org/renjin/gnur/ContextVarAllocator.java
index c4e6e24588..7acbff28cf 100644
--- a/tools/gnur-compiler/src/main/java/org/renjin/gnur/ContextVarAllocator.java
+++ b/tools/gnur-compiler/src/main/java/org/renjin/gnur/ContextVarAllocator.java
@@ -22,6 +22,7 @@
import org.renjin.gcc.codegen.expr.JLValue;
import org.renjin.gcc.codegen.var.VarAllocator;
import org.renjin.gcc.gimple.GimpleCompilationUnit;
+import org.renjin.gcc.gimple.GimpleFunction;
import org.renjin.repackaged.asm.Type;
import java.util.ArrayList;
@@ -42,34 +43,39 @@ public ContextVarAllocator(Type contextClass) {
this.contextClass = contextClass;
}
+ public List getContextFields() {
+ return fields;
+ }
- public JLValue reserve(GimpleCompilationUnit unit, String name, Type type, Optional initialValue) {
-
- String varName = VarAllocator.toJavaSafeName(unit.getName()) + "$" + VarAllocator.toJavaSafeName(name);
- ContextField var = new ContextField(contextClass, varName, type, initialValue);
-
+ private JLValue reserve(String prefix, String varName, Type type, Optional initialValue) {
+ String qualifiedName = prefix + "$" + VarAllocator.toJavaSafeName(varName);
+ ContextField var = new ContextField(contextClass, qualifiedName, type, initialValue);
fields.add(var);
-
return var.jvalue();
}
-
public VarAllocator forUnit(GimpleCompilationUnit unit) {
+ return forPrefix(VarAllocator.toJavaSafeName(unit.getName()));
+ }
+
+ public VarAllocator forFunction(GimpleFunction function) {
+ return forPrefix(VarAllocator.toJavaSafeName(function.getUnit().getName()) + "$" +
+ VarAllocator.toJavaSafeName(function.getMangledName()));
+ }
+
+ private VarAllocator forPrefix(String prefix) {
return new VarAllocator() {
@Override
public JLValue reserve(String name, Type type) {
- return ContextVarAllocator.this.reserve(unit, name, type, Optional.empty());
+ return ContextVarAllocator.this.reserve(prefix, name, type, Optional.empty());
}
@Override
public JLValue reserve(String name, Type type, JExpr initialValue) {
- return ContextVarAllocator.this.reserve(unit, name, type, Optional.of(initialValue));
-
+ return ContextVarAllocator.this.reserve(prefix, name, type, Optional.of(initialValue));
}
};
}
- public List getContextFields() {
- return fields;
- }
+
}
diff --git a/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarPlugin.java b/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarPlugin.java
index 34fd1760b4..61cd70275d 100644
--- a/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarPlugin.java
+++ b/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarPlugin.java
@@ -79,7 +79,7 @@ public void writeClasses(CodeGenerationContext generationContext) throws IOExcep
writer.writeFields(globalVarRewriter.getContextFields());
writer.writeConstructor(generationContext,
globalVarRewriter.getContextFields(),
- globalVarRewriter.getContextVars());
+ globalVarRewriter.getGlobalVariables());
writer.writeTo(generationContext);
}
diff --git a/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarRewriter.java b/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarRewriter.java
index 4b3d730166..7c44482e12 100644
--- a/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarRewriter.java
+++ b/tools/gnur-compiler/src/main/java/org/renjin/gnur/GlobalVarRewriter.java
@@ -19,10 +19,14 @@
package org.renjin.gnur;
import org.renjin.gcc.codegen.GlobalVarTransformer;
+import org.renjin.gcc.codegen.expr.ConstantValue;
import org.renjin.gcc.codegen.expr.GExpr;
import org.renjin.gcc.codegen.type.TypeOracle;
import org.renjin.gcc.gimple.GimpleCompilationUnit;
+import org.renjin.gcc.gimple.GimpleFunction;
import org.renjin.gcc.gimple.GimpleVarDecl;
+import org.renjin.gcc.gimple.expr.GimpleConstant;
+import org.renjin.gcc.gimple.expr.GimplePrimitiveConstant;
import org.renjin.repackaged.asm.Type;
import java.util.ArrayList;
@@ -36,14 +40,14 @@ public class GlobalVarRewriter implements GlobalVarTransformer {
private final ContextVarAllocator allocator;
- private List contextVars = new ArrayList<>();
+ private List globalVariables = new ArrayList<>();
public GlobalVarRewriter(Type contextClass) {
allocator = new ContextVarAllocator(contextClass);
}
@Override
- public boolean accept(GimpleVarDecl decl) {
+ public boolean acceptGlobalVar(GimpleVarDecl decl) {
// Do not include C++ run-time type information in the per-thread context.
// It does not change after initialization.
@@ -55,19 +59,41 @@ public boolean accept(GimpleVarDecl decl) {
return true;
}
+ @Override
+ public boolean acceptLocalStaticVar(GimpleVarDecl decl) {
+ return true;
+ }
+
@Override
public GExpr generator(TypeOracle typeOracle, GimpleCompilationUnit unit, GimpleVarDecl decl) {
- contextVars.add(decl);
+ globalVariables.add(decl);
return typeOracle.forType(decl.getType()).variable(decl, allocator.forUnit(unit));
}
+ @Override
+ public GExpr generator(TypeOracle typeOracle, GimpleFunction function, GimpleVarDecl decl) {
+ if(!hasSafeInitialValue(decl)) {
+ throw new UnsupportedOperationException(String.format("TODO: %s in %s in %s has initial value %s",
+ decl.getName(),
+ function.getName(),
+ function.getUnit().getSourceName(),
+ decl.getValue().toString()));
+ }
+ globalVariables.add(decl);
+ return typeOracle.forType(decl.getType()).variable(decl, allocator.forFunction(function));
+ }
+
+ private boolean hasSafeInitialValue(GimpleVarDecl decl) {
+ return decl.getValue() == null || decl.getValue() instanceof GimpleConstant;
+ }
+
public List getContextFields() {
return allocator.getContextFields();
}
- public List getContextVars() {
- return contextVars;
+ public List getGlobalVariables() {
+ return globalVariables;
}
}
diff --git a/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/GnuStringVector.java b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/GnuStringVector.java
index e46c5d517d..85a4d13a83 100644
--- a/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/GnuStringVector.java
+++ b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/GnuStringVector.java
@@ -18,6 +18,7 @@
*/
package org.renjin.gnur.api;
+import org.renjin.gcc.runtime.PointerPtr;
import org.renjin.sexp.AttributeMap;
import org.renjin.sexp.StringVector;
@@ -92,4 +93,5 @@ public void set(int index, GnuCharSexp charValue) {
public GnuCharSexp getElementAsCharSexp(int index) {
return values[index];
}
+
}
diff --git a/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java
index b94f2b13d0..b24ceafa4f 100644
--- a/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java
+++ b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java
@@ -567,13 +567,17 @@ public static int SETLEVELS(SEXP x, int v) {
public static Object DATAPTR(SEXP x) {
if (x instanceof IntVector || x instanceof LogicalVector) {
- return INTEGER(x);
+ return Rinternals2.INTEGER(x);
} else if(x instanceof DoubleVector) {
- return REAL(x);
+ return Rinternals2.REAL(x);
} else if(x instanceof ComplexVector) {
return COMPLEX(x);
} else if(x instanceof RawVector) {
return RAW(x);
+// } else if(x instanceof GnuStringVector) {
+// throw new UnsupportedOperationException("TODO");
+ } else if(x instanceof StringVector) {
+ return new StringVectorPtr((StringVector) x, 0);
} else {
throw new UnsupportedOperationException("DATAPTR on type " + x.getClass().getName());
}
diff --git a/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/StringVectorPtr.java b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/StringVectorPtr.java
new file mode 100644
index 0000000000..9ffe12316b
--- /dev/null
+++ b/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/StringVectorPtr.java
@@ -0,0 +1,91 @@
+/*
+ * Renjin : JVM-based interpreter for the R language for the statistical analysis
+ * Copyright © 2010-2019 BeDataDriven Groep B.V. and contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, a copy is available at
+ * https://www.gnu.org/licenses/gpl-2.0.txt
+ */
+package org.renjin.gnur.api;
+
+import org.renjin.gcc.runtime.*;
+import org.renjin.repackaged.guava.base.Charsets;
+import org.renjin.sexp.StringVector;
+
+public class StringVectorPtr extends AbstractPtr {
+
+ private StringVector vector;
+ private int offset;
+
+ public StringVectorPtr(StringVector vector, int offset) {
+ this.vector = vector;
+ this.offset = offset;
+ }
+
+ @Override
+ public Object getArray() {
+ return vector;
+ }
+
+ @Override
+ public int getOffsetInBytes() {
+ return offset * PointerPtr.BYTES;
+ }
+
+ @Override
+ public Ptr realloc(int newSizeInBytes) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ @Override
+ public Ptr pointerPlus(int bytes) {
+ if(bytes == 0) {
+ return this;
+ }
+ if(bytes % PointerPtr.BYTES == 0) {
+ return new StringVectorPtr(this.vector, this.offset + (bytes / PointerPtr.BYTES));
+ }
+ return new OffsetPtr(this, bytes);
+ }
+
+ @Override
+ public byte getByte(int offset) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ @Override
+ public Ptr getAlignedPointer(int index) {
+ String element = vector.getElementAsString(offset + index);
+ if(element == null) {
+ return BytePtr.NULL;
+ } else {
+ return BytePtr.nullTerminatedString(element, Charsets.UTF_8);
+ }
+ }
+
+ @Override
+ public void setByte(int offset, byte value) {
+ throw new UnsupportedOperationException("Illegal modification of a shared vector! " +
+ "Mis-behaving C/C++ code has tried to modify a vector that it should not.");
+ }
+
+ @Override
+ public int toInt() {
+ return getOffsetInBytes();
+ }
+
+ @Override
+ public boolean isNull() {
+ return false;
+ }
+}