Skip to content
Snippets Groups Projects
Commit ae5987a6 authored by Mick Jordan's avatar Mick Jordan
Browse files

Merge pull request #239 in G/fastr from ~LUKAS.STADLER_ORACLE.COM/fastr:feature/strtoi to master

* commit '4c2280f9':
  work on strtoi
parents 581a66d2 4c2280f9
Branches
No related tags found
No related merge requests found
...@@ -22,11 +22,19 @@ ...@@ -22,11 +22,19 @@
*/ */
package com.oracle.truffle.r.nodes.builtin.base; package com.oracle.truffle.r.nodes.builtin.base;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.eq;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
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.RBehavior.PURE;
import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.ExactMath;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.CastBuilder;
import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RRuntime;
...@@ -34,53 +42,108 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; ...@@ -34,53 +42,108 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDataFactory;
import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RIntVector;
import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
@RBuiltin(name = "strtoi", kind = INTERNAL, parameterNames = {"x", "base"}, behavior = PURE) @RBuiltin(name = "strtoi", kind = INTERNAL, parameterNames = {"x", "base"}, behavior = PURE)
public abstract class Strtoi extends RBuiltinNode { public abstract class Strtoi extends RBuiltinNode {
@Override @Override
protected void createCasts(CastBuilder casts) { protected void createCasts(CastBuilder casts) {
// TODO: not sure if the behavior is 100% compliant casts.arg("x").mustBe(stringValue()).asStringVector();
casts.arg("base").asIntegerVector().findFirst(); // base == 0 || (base >= 2 && base <= 36)
casts.arg("base").mustBe(integerValue()).asIntegerVector().findFirst().mustBe(eq(0).or(gte(2).and(lte(36))));
} }
@Specialization @Specialization
@TruffleBoundary protected RIntVector doStrtoi(RAbstractStringVector vec, int baseArg,
protected RIntVector doStrtoi(RAbstractStringVector vec, int baseArg) { @Cached("createBinaryProfile()") ConditionProfile emptyProfile,
int base = baseArg; @Cached("createBinaryProfile()") ConditionProfile baseZeroProfile,
@Cached("createBinaryProfile()") ConditionProfile negateProfile,
@Cached("createBinaryProfile()") ConditionProfile incompleteProfile,
@Cached("createEqualityProfile()") PrimitiveValueProfile baseProfile) {
int[] data = new int[vec.getLength()]; int[] data = new int[vec.getLength()];
boolean complete = RDataFactory.COMPLETE_VECTOR; boolean complete = true;
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
int dataValue = RRuntime.INT_NA; int dataValue;
try { String s = vec.getDataAt(i);
String s = vec.getDataAt(i); if (emptyProfile.profile(s.length() == 0)) {
if (s.length() == 0) { dataValue = RRuntime.INT_NA;
complete = RDataFactory.INCOMPLETE_VECTOR; } else {
boolean negate = false;
int pos = 0;
if (s.charAt(pos) == '+') {
// skip "+"
pos++;
} else if (s.charAt(pos) == '-') {
negate = true;
pos++;
}
int base = baseArg;
if (pos < s.length() && s.charAt(pos) == '0') {
// skip "0"
pos++;
if (pos < s.length() && (s.charAt(pos) == 'x' || s.charAt(pos) == 'X')) {
if (baseZeroProfile.profile(base == 0)) {
base = 16;
}
// skip "x" or "X"
pos++;
} else {
if (baseZeroProfile.profile(base == 0)) {
base = 8;
}
// go back (to parse the "0")
pos--;
}
} else {
if (baseZeroProfile.profile(base == 0)) {
base = 10;
}
}
base = baseProfile.profile(base);
if (pos == s.length()) {
// produce NA is no data is available
dataValue = RRuntime.INT_NA;
} else { } else {
if (base == 0) { dataValue = 0;
char ch0 = s.charAt(0); while (pos < s.length()) {
if (ch0 == '0') { char c = s.charAt(pos++);
if (s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) { int digit;
base = 16; if (base > 10) {
if (c >= '0' && c <= '9') {
digit = c - '0';
} else if (c >= 'a' && c < ('a' + base - 10)) {
digit = c - 'a' + 10;
} else if (c >= 'A' && c < ('A' + base - 10)) {
digit = c - 'A' + 10;
} else { } else {
base = 8; dataValue = RRuntime.INT_NA;
break;
} }
} else { } else {
base = 10; if (c >= '0' && c < ('0' + base)) {
digit = c - '0';
} else {
dataValue = RRuntime.INT_NA;
break;
}
}
try {
dataValue = ExactMath.addExact(ExactMath.multiplyExact(dataValue, base), digit);
} catch (ArithmeticException e) {
dataValue = RRuntime.INT_NA;
break;
} }
} }
long value = RFFIFactory.getRFFI().getBaseRFFI().strtol(s, base);
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
complete = RDataFactory.INCOMPLETE_VECTOR;
} else {
dataValue = (int) value;
}
} }
} catch (IllegalArgumentException ex) { if (negateProfile.profile(negate)) {
complete = RDataFactory.INCOMPLETE_VECTOR; // relies on -INT_NA == INT_NA
dataValue = -dataValue;
}
if (incompleteProfile.profile(dataValue == RRuntime.INT_NA)) {
complete = false;
}
data[i] = dataValue;
} }
data[i] = dataValue;
} }
return RDataFactory.createIntVector(data, complete); return RDataFactory.createIntVector(data, complete);
} }
......
...@@ -29,12 +29,12 @@ public class TestBuiltin_strtoi extends TestBase { ...@@ -29,12 +29,12 @@ public class TestBuiltin_strtoi extends TestBase {
@Test @Test
public void teststrtoi3() { public void teststrtoi3() {
assertEval(Ignored.Unknown, "argv <- list(c('0xff', '077', '123'), 0L); .Internal(strtoi(argv[[1]], argv[[2]]))"); assertEval("argv <- list(c('0xff', '077', '123'), 0L); .Internal(strtoi(argv[[1]], argv[[2]]))");
} }
@Test @Test
public void teststrtoi4() { public void teststrtoi4() {
assertEval(Ignored.Unknown, "argv <- list('1.3', 16L); .Internal(strtoi(argv[[1]], argv[[2]]))"); assertEval("argv <- list('1.3', 16L); .Internal(strtoi(argv[[1]], argv[[2]]))");
} }
@Test @Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment