Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 31451d222605
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: cad1c3c9d298
Choose a head ref
  • 2 commits
  • 5 files changed
  • 1 contributor

Commits on Apr 2, 2015

  1. Copy the full SHA
    9623cec View commit details
  2. Copy the full SHA
    cad1c3c View commit details
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/string/rindex_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:String#rindex with object tries to convert obj to a string via to_str
fails:String#rindex with String tries to convert start_offset to an integer via to_int
fails:String#rindex with Regexp behaves the same as String#rindex(string) for escaped string regexps
fails:String#rindex with Regexp returns the index of the first match from the end of string of regexp
fails:String#rindex with Regexp sets $~ to MatchData of match and nil when there's none
@@ -9,4 +7,3 @@ fails:String#rindex with Regexp supports \G which matches at the given start off
fails:String#rindex with Regexp tries to convert start_offset to an integer via to_int
fails:String#rindex with Regexp returns the reverse character index of a multibyte character
fails:String#rindex with Regexp returns the character index before the finish
fails:String#rindex with Regexp raises an Encoding::CompatibilityError if the encodings are incompatible
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@

package org.jruby.truffle.nodes.core;

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

@@ -23,4 +24,15 @@ public static boolean isAsciiCompatible(RubyString string) {
return string.getByteList().getEncoding().isAsciiCompatible();
}

public static boolean isSingleByteOptimizableOrAsciiCompatible(RubyString string) {
return isSingleByteOptimizable(string) || isAsciiCompatible(string);
}

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

public static boolean isValidUtf8(RubyString string) {
return string.isCodeRangeValid() && string.getByteList().getEncoding() instanceof UTF8Encoding;
}
}
Original file line number Diff line number Diff line change
@@ -1515,57 +1515,6 @@ public RubyString replace(RubyString string, RubyString other) {

}

@CoreMethod(names = "rindex", required = 1, optional = 1, lowerFixnumParameters = 1)
public abstract static class RindexNode extends CoreMethodNode {

@Child private SizeNode sizeNode;

public RindexNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
sizeNode = StringNodesFactory.SizeNodeFactory.create(context, sourceSection, new RubyNode[] { null });
}

public RindexNode(RindexNode prev) {
super(prev);
sizeNode = prev.sizeNode;
}

@Specialization
public Object rindex(VirtualFrame frame, RubyString string, RubyString subString, @SuppressWarnings("unused") UndefinedPlaceholder endPosition) {
notDesignedForCompilation();

return rindex(frame, string, subString, sizeNode.executeIntegerFixnum(frame, string));
}

@Specialization
public Object rindex(VirtualFrame frame, RubyString string, RubyString subString, int endPosition) {
notDesignedForCompilation();

final int stringLength = sizeNode.executeIntegerFixnum(frame, string);
int normalizedEndPosition = endPosition;

if (endPosition < 0) {
normalizedEndPosition = endPosition + stringLength;

if (normalizedEndPosition < 0) {
return nil();
}
} else if (endPosition > stringLength) {
normalizedEndPosition = stringLength;
}

int result = StringSupport.rindex(string.getBytes(), stringLength, subString.length(),
normalizedEndPosition, subString, string.getBytes().getEncoding()
);

if (result >= 0) {
return result;
} else {
return nil();
}
}
}

@CoreMethod(names = "rstrip!", raiseIfFrozenSelf = true)
@ImportGuards(StringGuards.class)
public abstract static class RstripBangNode extends CoreMethodNode {
@@ -1639,25 +1588,6 @@ private int prevCharHead(Encoding enc, byte[]bytes, int p, int s, int end) {
}
}

@CoreMethod(names = "swapcase", taintFromSelf = true)
public abstract static class SwapcaseNode extends CoreMethodNode {
public SwapcaseNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SwapcaseNode(SwapcaseNode prev) {
super(prev);
}

@Specialization
public RubyString swapcase(RubyString string) {
notDesignedForCompilation();

ByteList byteList = StringNodesHelper.swapcase(string);
return getContext().makeString(string.getLogicalClass(), byteList);
}
}

@CoreMethod(names = "swapcase!", raiseIfFrozenSelf = true)
public abstract static class SwapcaseBangNode extends CoreMethodNode {
public SwapcaseBangNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -579,6 +579,7 @@ public Object stringToF(RubyString string) {
public static abstract class StringIndexPrimitiveNode extends RubiniusPrimitiveNode {

public StringIndexPrimitiveNode(RubyContext context, SourceSection sourceSection) {

super(context, sourceSection);
}

@@ -628,6 +629,7 @@ public int stringCharacterByteIndexMultiByteEncoding(RubyString string, int inde
}

@RubiniusPrimitive(name = "string_byte_character_index", needsSelf = false)
@ImportGuards(StringGuards.class)
public static abstract class StringByteCharacterIndexPrimitiveNode extends RubiniusPrimitiveNode {

public StringByteCharacterIndexPrimitiveNode(RubyContext context, SourceSection sourceSection) {
@@ -638,11 +640,46 @@ public StringByteCharacterIndexPrimitiveNode(StringByteCharacterIndexPrimitiveNo
super(prev);
}

@Specialization
public Object stringByteCharacterIndex(RubyString string, Object index, Object start) {
throw new UnsupportedOperationException("string_byte_character_index");
@Specialization(guards = { "isSingleByteOptimizableOrAsciiCompatible", "!isFixedWidthEncoding", "!isValidUtf8" })
public int stringByteCharacterIndexSingleByte(RubyString string, int index, int start) {
// Taken from Rubinius's String::find_byte_character_index.
return index;
}

@Specialization(guards = { "!isSingleByteOptimizableOrAsciiCompatible", "isFixedWidthEncoding", "!isValidUtf8" })
public int stringByteCharacterIndexFixedWidth(RubyString string, int index, int start) {
// Taken from Rubinius's String::find_byte_character_index.
return index / string.getByteList().getEncoding().minLength();
}

@Specialization(guards = { "!isSingleByteOptimizableOrAsciiCompatible", "!isFixedWidthEncoding", "isValidUtf8" })
public int stringByteCharacterIndexValidUtf8(RubyString string, int index, int start) {
// Taken from Rubinius's String::find_byte_character_index.

// TODO (nirvdrum 02-Apr-15) There's a way to optimize this for UTF-8, but porting all that code isn't necessary at the moment.
return stringByteCharacterIndex(string, index, start);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = { "!isSingleByteOptimizableOrAsciiCompatible", "!isFixedWidthEncoding", "!isValidUtf8" })
public int stringByteCharacterIndex(RubyString string, int index, int start) {
// Taken from Rubinius's String::find_byte_character_index and Encoding::find_byte_character_index.

final ByteList bytes = string.getByteList();
final Encoding encoding = bytes.getEncoding();
int p = bytes.begin() + start;
final int end = bytes.begin() + bytes.realSize();
int charIndex = 0;

while (p < end && index > 0) {
final int charLen = StringSupport.length(encoding, bytes.getUnsafeBytes(), p, end);
p += charLen;
index -= charLen;
charIndex++;
}

return charIndex;
}
}

@RubiniusPrimitive(name = "string_character_index", needsSelf = false)
@@ -944,6 +981,77 @@ public RubyString stringResizeCapacity(RubyString string, int capacity) {

}

@RubiniusPrimitive(name = "string_rindex")
public static abstract class StringRindexPrimitiveNode extends RubiniusPrimitiveNode {

public StringRindexPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public StringRindexPrimitiveNode(StringRindexPrimitiveNode prev) {
super(prev);
}

@Specialization
public Object stringRindex(RubyString string, RubyString pattern, int start) {
// Taken from Rubinius's String::rindex.

int pos = start;

if (pos < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("negative start given", this));
}

final ByteList buf = string.getByteList();
final int total = buf.getRealSize();
final int matchSize = pattern.getByteList().getRealSize();

if (pos >= total) {
pos = total - 1;
}

switch(matchSize) {
case 0: {
return start;
}

case 1: {
final int matcher = pattern.getByteList().get(0);

while (pos >= 0) {
if (buf.get(pos) == matcher) {
return pos;
}

pos--;
}

return nil();
}

default: {
if (total - pos < matchSize) {
pos = total - matchSize;
}

int cur = pos;

while (cur >= 0) {
if (ByteList.memcmp(string.getByteList().getUnsafeBytes(), cur, pattern.getByteList().getUnsafeBytes(), 0, matchSize) == 0) {
return cur;
}

cur--;
}
}
}

return nil();
}

}

@RubiniusPrimitive(name = "string_pattern")
public static abstract class StringPatternPrimitiveNode extends RubiniusPrimitiveNode {

5 changes: 5 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/string.rb
Original file line number Diff line number Diff line change
@@ -48,6 +48,11 @@ def find_string(pattern, start)
raise PrimitiveFailure, "String#find_string primitive failed"
end

def find_string_reverse(pattern, start)
Rubinius.primitive :string_rindex
raise PrimitiveFailure, "String#find_string_reverse primitive failed"
end

def chr_at(byte)
Rubinius.primitive :string_chr_at
raise ArgumentError, "String#chr_at primitive failed"