Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Truffle] Completed String#slice!.
  • Loading branch information
nirvdrum committed Apr 3, 2015
1 parent 25fe902 commit dfe59cc
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 19 deletions.
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/string/slice_tags.txt

This file was deleted.

Expand Up @@ -12,6 +12,7 @@

import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.util.CodeRangeSupport;
import org.jruby.util.StringSupport;

public class StringGuards {
Expand All @@ -28,6 +29,14 @@ public static boolean isSingleByteOptimizableOrAsciiCompatible(RubyString string
return isSingleByteOptimizable(string) || isAsciiCompatible(string);
}

public static boolean isSingleByte(RubyString string) {
return string.getByteList().getEncoding().isSingleByte();
}

public static boolean isValidOr7BitEncoding(RubyString string) {
return string.isCodeRangeValid() || CodeRangeSupport.isCodeRangeAsciiOnly(string);
}

public static boolean isFixedWidthEncoding(RubyString string) {
return string.getByteList().getEncoding().isFixedWidth();
}
Expand Down
Expand Up @@ -483,21 +483,22 @@ public GetIndexNode(GetIndexNode prev) {
substringNode = prev.substringNode;
}

public Object getIndex(RubyString string, int index, UndefinedPlaceholder undefined) {
@Specialization
public Object getIndex(VirtualFrame frame, RubyString string, int index, UndefinedPlaceholder undefined) {
int normalizedIndex = string.normalizeIndex(index);
final ByteList bytes = string.getBytes();

if (normalizedIndex < 0 || normalizedIndex >= bytes.length()) {
outOfBounds.enter();
return nil();
} else {
return getContext().makeString(string.getLogicalClass(), bytes.charAt(normalizedIndex), string.getByteList().getEncoding());
return getSubstringNode().execute(frame, string, index, 1);
}
}

@Specialization(guards = { "!isRubyRange(arguments[1])", "!isRubyRegexp(arguments[1])", "!isRubyString(arguments[1])" })
public Object getIndex(VirtualFrame frame, RubyString string, Object index, UndefinedPlaceholder undefined) {
return getIndex(string, getToIntNode().executeIntegerFixnum(frame, index), undefined);
return getIndex(frame, string, getToIntNode().executeIntegerFixnum(frame, index), undefined);
}

@Specialization
Expand Down Expand Up @@ -1096,6 +1097,7 @@ public RubyString eachByte(VirtualFrame frame, RubyString string, RubyProc block
}

@CoreMethod(names = "each_char", needsBlock = true, returnsEnumeratorIfNoBlock = true)
@ImportGuards(StringGuards.class)
public abstract static class EachCharNode extends YieldingCoreMethodNode {

@Child private CallDispatchHeadNode toEnumNode;
Expand All @@ -1116,10 +1118,9 @@ public RubyString eachChar(VirtualFrame frame, RubyString string, RubyProc block
int len = strByteList.getRealSize();
Encoding enc = string.getBytes().getEncoding();

final int stringLength = string.getBytes().length();
int n;

for (int i = 0; i < stringLength; i += n) {
for (int i = 0; i < len; i += n) {
n = StringSupport.encFastMBCLen(ptrBytes, ptr + i, ptr + len, enc);

yield(frame, block, substr(string, i, n));
Expand All @@ -1136,10 +1137,9 @@ public RubyString eachCharMultiByteEncoding(VirtualFrame frame, RubyString strin
int len = strByteList.getRealSize();
Encoding enc = string.getBytes().getEncoding();

final int stringLength = string.getBytes().length();
int n;

for (int i = 0; i < stringLength; i += n) {
for (int i = 0; i < len; i += n) {
n = multiByteStringLength(enc, ptrBytes, ptr + i, ptr + len);

yield(frame, block, substr(string, i, n));
Expand All @@ -1148,10 +1148,6 @@ public RubyString eachCharMultiByteEncoding(VirtualFrame frame, RubyString strin
return string;
}

public static boolean isValidOr7BitEncoding(RubyString string) {
return string.isCodeRangeValid() || CodeRangeSupport.isCodeRangeAsciiOnly(string);
}

@TruffleBoundary
private int multiByteStringLength(Encoding enc, byte[] bytes, int p, int end) {
return StringSupport.length(enc, bytes, p, end);
Expand Down
Expand Up @@ -462,23 +462,78 @@ public boolean stringEqual(RubyString string, RubyString other) {
}

@RubiniusPrimitive(name = "string_find_character")
@ImportGuards(StringGuards.class)
public static abstract class StringFindCharacterPrimitiveNode extends RubiniusPrimitiveNode {

@Child private StringNodes.GetIndexNode getIndexNode;
@Child private TaintResultNode taintResultNode;

public StringFindCharacterPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
getIndexNode = StringNodesFactory.GetIndexNodeFactory.create(context, sourceSection, new RubyNode[]{});
}

public StringFindCharacterPrimitiveNode(StringFindCharacterPrimitiveNode prev) {
super(prev);
getIndexNode = prev.getIndexNode;
taintResultNode = prev.taintResultNode;
}

@Specialization
public Object stringFindCharacter(RubyString string, int index) {
return getIndexNode.getIndex(string, index, UndefinedPlaceholder.INSTANCE);
@Specialization(guards = "isSingleByte")
public Object stringFindCharacterSingleByte(RubyString string, int offset) {
// Taken from Rubinius's String::find_character.

if (offset < 0) {
return nil();
}

if (offset >= string.getByteList().getRealSize()) {
return nil();
}

final RubyString ret = getContext().makeString(string.getLogicalClass(), new ByteList(string.getByteList().unsafeBytes(), offset, 1));

ret.getByteList().setEncoding(string.getByteList().getEncoding());
ret.setCodeRange(string.getCodeRange());
getTaintResultNode().maybeTaint(string, ret);

return ret;
}

@Specialization(guards = "!isSingleByte")
public Object stringFindCharacter(RubyString string, int offset) {
// Taken from Rubinius's String::find_character.

if (offset < 0) {
return nil();
}

if (offset >= string.getByteList().getRealSize()) {
return nil();
}

final ByteList bytes = string.getByteList();
final Encoding enc = bytes.getEncoding();
final int clen = StringSupport.preciseLength(enc, bytes.getUnsafeBytes(), bytes.begin(), bytes.begin() + bytes.realSize());

final RubyString ret;
if (StringSupport.MBCLEN_CHARFOUND_P(clen)) {
ret = getContext().makeString(string.getLogicalClass(), new ByteList(string.getByteList().unsafeBytes(), offset, clen));
} else {
ret = getContext().makeString(string.getLogicalClass(), new ByteList(string.getByteList().unsafeBytes(), offset, 1));
}

ret.getByteList().setEncoding(string.getByteList().getEncoding());
ret.setCodeRange(string.getCodeRange());
getTaintResultNode().maybeTaint(string, ret);

return ret;
}

private TaintResultNode getTaintResultNode() {
if (taintResultNode == null) {
CompilerDirectives.transferToInterpreter();
taintResultNode = insert(new TaintResultNode(getContext(), getSourceSection(), true, new int[]{}));
}

return taintResultNode;
}

}
Expand Down

0 comments on commit dfe59cc

Please sign in to comment.