Skip to content

Commit

Permalink
Showing 1 changed file with 1 addition and 747 deletions.
748 changes: 1 addition & 747 deletions truffle/src/main/ruby/core/rubinius/common/string.rb
Original file line number Diff line number Diff line change
@@ -31,25 +31,6 @@
class String
include Comparable

Truffle.omit("We do our own allocation in Java") do
def self.__allocate__
Rubinius.primitive :string_allocate
raise PrimitiveFailure, "String.allocate primitive failed"
end

def self.allocate
str = __allocate__
str.__data__ = Rubinius::ByteArray.allocate_sized(1)
str.num_bytes = 0
str
end
end

attr_accessor :data

alias_method :__data__, :data
alias_method :__data__=, :data=

##
# Creates a new string from copying _count_ bytes from the
# _start_ of _bytes_.
@@ -62,23 +43,6 @@ def self.try_convert(obj)
Rubinius::Type.try_convert obj, String, :to_str
end

Truffle.omit("Rubinius prevents cloning String, but MRI expects to be able to to run its test suite") do
class << self
def clone
raise TypeError, "Unable to clone/dup String class"
end

alias_method :dup, :clone
end
end

def initialize(arg = undefined)
replace arg unless undefined.equal?(arg)
self
end

private :initialize

def %(args)
*args = args
ret = Rubinius::Sprinter.get(self).call(*args)
@@ -87,43 +51,6 @@ def %(args)
return ret
end

def *(num)
num = Rubinius::Type.coerce_to(num, Integer, :to_int) unless num.kind_of? Integer

if num.kind_of? Bignum
raise RangeError, "bignum too big to convert into `long' (#{num})"
end

if num < 0
raise ArgumentError, "unable to multiple negative times (#{num})"
end

str = self.class.pattern num * bytesize, self
return str
end

def +(other)
other = StringValue(other)
Rubinius::Type.compatible_encoding self, other
String.new(self) << other
end

def ==(other)
Rubinius.primitive :string_equal

# Use #=== rather than #kind_of? because other might redefine kind_of?
unless String === other
if other.respond_to?(:to_str)
return other == self
end
return false
end

return false unless bytesize == other.bytesize
return false unless Encoding.compatible?(self, other)
return @data.compare_bytes(other.__data__, bytesize, other.bytesize) == 0
end

def =~(pattern)
case pattern
when Regexp
@@ -189,55 +116,6 @@ def [](index, other = undefined)
end
alias_method :slice, :[]

def capitalize
return dup if bytesize == 0

str = transform(Rubinius::CType::Lowered)

str.modify!

# Now do the actual capitalization
ba = str.__data__
ba[0] = Rubinius::CType.toupper(ba[0])

return str
end

def capitalize!
Rubinius.check_frozen

cap = capitalize()
return nil if cap == self

replace(cap)
return self
end

def casecmp(to)
to = StringValue(to)
order = bytesize - to.num_bytes
size = order < 0 ? bytesize : to.num_bytes

ctype = Rubinius::CType

i = 0
while i < size
a = @data[i]
b = to.__data__[i]
i += 1

a = ctype.toupper!(a) if ctype.islower(a)
b = ctype.toupper!(b) if ctype.islower(b)
r = a - b

next if r == 0
return r < 0 ? -1 : 1
end

return 0 if order == 0
return order < 0 ? -1 : 1
end

def chomp(separator=$/)
str = dup
str.chomp!(separator) || str
@@ -248,111 +126,16 @@ def chop
str.chop! || str
end

def count(*strings)
raise ArgumentError, "wrong number of Arguments" if strings.empty?

return 0 if bytesize == 0

table = count_table(*strings).__data__

count = bytes = 0
while bytes < bytesize
count += 1 if table[@data[bytes]] == 1
bytes += find_character(bytes).num_bytes
end

count
end

def crypt(other_str)
other_str = StringValue(other_str)

if other_str.size < 2
raise ArgumentError, "salt must be at least 2 characters"
end

hash = __crypt__(other_str)
hash.taint if tainted? || other_str.tainted?
hash
end

def delete(*strings)
str = dup
str.delete!(*strings) || str
end

def delete!(*strings)
raise ArgumentError, "wrong number of arguments" if strings.empty?

table = count_table(*strings).__data__

self.modify!

i = 0
j = -1

while i < bytesize
c = @data[i]
unless table[c] == 1
@data[j+=1] = c
end
i += 1
end

if (j += 1) < bytesize
self.num_bytes = j
self
else
nil
end
end

def downcase
return dup if bytesize == 0
transform(Rubinius::CType::Lowered)
end

def downcase!
Rubinius.check_frozen

return if bytesize == 0

str = transform(Rubinius::CType::Lowered)

return nil if str == self

replace(str)

return self
end

def each_char
return to_enum(:each_char) { size } unless block_given?

bytes = 0
while bytes < bytesize
char = find_character(bytes)
yield char
bytes += char.num_bytes
end

self
end

def each_byte
return to_enum(:each_byte) { bytesize } unless block_given?
i = 0
while i < bytesize do
yield @data.get_byte(i)
i += 1
end
self
end

def empty?
bytesize == 0
end

def end_with?(*suffixes)
suffixes.each do |suffix|
suffix = Rubinius::Type.check_convert_type suffix, String, :to_str
@@ -363,32 +146,10 @@ def end_with?(*suffixes)
false
end

def eql?(other)
Rubinius.primitive :string_equal

return false unless other.kind_of?(String) && other.bytesize == bytesize
return false unless Encoding.compatible?(self, other)
return @data.compare_bytes(other.__data__, bytesize, other.bytesize) == 0
end

# This method is specifically part of 1.9 but we enable it in 1.8 also
# because we need it internally.
def getbyte(index)
index = Rubinius::Type.coerce_to index, Fixnum, :to_int

index += bytesize if index < 0
return if index < 0 or index >= bytesize

@data[index]
end

def include?(needle)
!!find_string(StringValue(needle), 0)
end

ControlCharacters = [10, 9, 7, 11, 12, 13, 27, 8]
ControlPrintValue = ["\\n", "\\t", "\\a", "\\v", "\\f", "\\r", "\\e", "\\b"]

def lstrip
str = dup
str.lstrip! || str
@@ -507,23 +268,6 @@ def scan(pattern)
return ret
end

# This method is specifically part of 1.9 but we enable it in 1.8 also
# because we need it internally.
def setbyte(index, byte)
self.modify!

index = Rubinius::Type.coerce_to index, Fixnum, :to_int
byte = Rubinius::Type.coerce_to byte, Fixnum, :to_int

index += bytesize if index < 0
if index < 0 or index >= bytesize
raise IndexError, "byte index #{index} is outside bounds of String"
end

@ascii_only = @valid_encoding = nil
@data[index] = byte
end

def split(pattern=nil, limit=undefined)
Rubinius::Splitter.split(self, pattern, limit)
end
@@ -533,32 +277,6 @@ def squeeze(*strings)
str.squeeze!(*strings) || str
end

def squeeze!(*strings)
return if bytesize == 0

table = count_table(*strings).__data__
self.modify!

i = 1
j = 0
last = @data[0]

while i < bytesize
c = @data[i]
unless c == last and table[c] == 1
@data[j+=1] = last = c
end
i += 1
end

if (j += 1) < bytesize
self.num_bytes = j
self
else
nil
end
end

def start_with?(*prefixes)
prefixes.each do |prefix|
prefix = Rubinius::Type.check_convert_type prefix, String, :to_str
@@ -583,48 +301,11 @@ def succ
dup.succ!
end

def sum(bits=16)
bits = Rubinius::Type.coerce_to bits, Fixnum, :to_int
i = -1
sum = 0

sum += @data[i] while (i += 1) < bytesize
if bits > 0
sum & ((1 << bits) - 1)
else
sum
end
end

def swapcase
str = dup
str.swapcase! || str
end

def swapcase!
self.modify!
return if bytesize == 0

modified = false

ctype = Rubinius::CType

i = 0
while i < bytesize
c = @data[i]
if ctype.islower(c)
@data[i] = ctype.toupper!(c)
modified = true
elsif ctype.isupper(c)
@data[i] = ctype.tolower!(c)
modified = true
end
i += 1
end

modified ? self : nil
end

alias_method :intern, :to_sym

def to_i(base=10)
@@ -637,65 +318,21 @@ def to_i(base=10)
to_inum(base, false)
end

def to_s
instance_of?(String) ? self : "".replace(self)
end
alias_method :to_str, :to_s

def tr(source, replacement)
str = dup
str.tr!(source, replacement) || str
end

def tr!(source, replacement)
tr_trans(source, replacement, false)
end

def tr_s(source, replacement)
str = dup
str.tr_s!(source, replacement) || str
end

def tr_s!(source, replacement)
tr_trans(source, replacement, true)
end

def unpack(directives)
Rubinius.primitive :string_unpack

unless directives.kind_of? String
return unpack(StringValue(directives))
end

raise ArgumentError, "invalid directives string: #{directives}"
end

def upcase
str = dup
str.upcase! || str
end

def upcase!
return if bytesize == 0
self.modify!

modified = false

ctype = Rubinius::CType

i = 0
while i < bytesize
c = @data[i]
if ctype.islower(c)
@data[i] = ctype.toupper!(c)
modified = true
end
i += 1
end

modified ? self : nil
end

def to_sub_replacement(result, match)
data = bytes
index = 0
@@ -774,55 +411,7 @@ def compare_substring(other, start, size)
end
raise PrimitiveFailure, "String#compare_substring primitive failed"
end

def count_table(*strings)
table = String.pattern 256, 1

i = 0
size = strings.size
while i < size
str = StringValue(strings[i]).dup
if str.bytesize > 1 && str.getbyte(0) == 94 # ?^
pos = 0
neg = 1
str.slice!(0)
else
pos = 1
neg = 0
end

set = String.pattern 256, neg
set_data = set.__data__
str.tr_expand! nil, true
str_data = str.__data__
j = -1
chars = str.bytesize
set_data[str_data[j]] = pos while (j += 1) < chars

table.apply_and! set
i += 1
end
table
end

def tr_expand!(limit, invalid_as_empty)
Rubinius.primitive :string_tr_expand
raise PrimitiveFailure, "String#tr_expand primitive failed"
end

# Unshares shared strings.
def modify!
Rubinius.check_frozen

if @shared
@data = @data.dup
@shared = nil
end

@ascii_only = @valid_encoding = nil
@hash_value = nil # reset the hash value
end


def subpattern(pattern, capture)
match = pattern.match(self)

@@ -857,31 +446,13 @@ def shorten!(size)
self.num_bytes -= size
end

def shared!
@shared = true
end

def each_codepoint
return to_enum(:each_codepoint) { size } unless block_given?

each_char { |c| yield c.ord }
self
end

def b
dup.force_encoding Encoding::ASCII_8BIT
end

def bytes
if block_given?
each_byte do |byte|
yield byte
end
else
each_byte.to_a
end
end

def chars
if block_given?
each_char do |char|
@@ -1005,19 +576,6 @@ def end_with?(*suffixes)
false
end

def force_encoding(enc)
@encoding = Rubinius::Type.coerce_to_encoding enc
unless @ascii_only && @encoding.ascii_compatible?
@ascii_only = @valid_encoding = @num_chars = nil
end
if bytesize == 0 && @encoding.ascii_compatible?
@ascii_only = true
@valid_encoding = true
@num_chars = 0
end
self
end

def inspect
result_encoding = Encoding.default_internal || Encoding.default_external
unless result_encoding.ascii_compatible?
@@ -1357,66 +915,6 @@ def slice!(one, two=undefined)
result
end

# TODO: make encoding aware.
def succ!
self.modify!

return self if bytesize == 0

carry = nil
last_alnum = 0
start = bytesize - 1

ctype = Rubinius::CType

while start >= 0
s = @data[start]
if ctype.isalnum(s)
carry = 0
if (48 <= s && s < 57) ||
(97 <= s && s < 122) ||
(65 <= s && s < 90)
@data[start] += 1
elsif s == 57
@data[start] = 48
carry = 49
elsif s == 122
@data[start] = carry = 97
elsif s == 90
@data[start] = carry = 65
end

break if carry == 0
last_alnum = start
end

start -= 1
end

if carry.nil?
start = length - 1
carry = 1

while start >= 0
if @data[start] >= 255
@data[start] = 0
else
@data[start] += 1
break
end

start -= 1
end
end

if start < 0
m = Rubinius::Mirror.reflect self
m.splice last_alnum, 1, carry.chr + @data[last_alnum].chr
end

return self
end

alias_method :next, :succ
alias_method :next!, :succ!

@@ -1428,45 +926,6 @@ def to_r
Rationalizer.new(self).convert
end

def rstrip!
Rubinius.check_frozen
return if bytesize == 0

stop = bytesize - 1

ctype = Rubinius::CType

while stop >= 0 && (@data[stop] == 0 || ctype.isspace(@data[stop]))
stop -= 1
end

return if (stop += 1) == bytesize

modify!
self.num_bytes = stop
self
end

def lstrip!
Rubinius.check_frozen
return if bytesize == 0

start = 0

ctype = Rubinius::CType

while start < bytesize && ctype.isspace(@data[start])
start += 1
end

return if start == 0

modify!
self.num_bytes -= start
@data.move_bytes start, bytesize, 0
self
end

def chop!
Rubinius.check_frozen

@@ -1560,35 +1019,6 @@ def chomp!(sep=undefined)
self
end

def clear
Rubinius.check_frozen
self.num_bytes = 0
self
end

def replace(other)
Rubinius.check_frozen

# If we're replacing with ourselves, then we have nothing to do
return self if Rubinius::Type.object_equal(self, other)

other = StringValue(other)

@shared = true
other.shared!
@data = other.__data__
self.num_bytes = other.num_bytes
@hash_value = nil
force_encoding(other.encoding)
@valid_encoding = other.valid_encoding?
@ascii_only = nil

Rubinius::Type.infect(self, other)
end

def initialize_copy(other)
end

def <<(other)
Rubinius.check_frozen

@@ -2358,180 +1788,4 @@ def start_with?(*prefixes)
false
end

def insert(index, other)
other = StringValue(other)

enc = Rubinius::Type.compatible_encoding self, other
index = Rubinius::Type.coerce_to index, Fixnum, :to_int
index = length + 1 + index if index < 0

if index > length or index < 0 then
raise IndexError, "index #{index} out of string"
end

osize = other.bytesize
size = bytesize + osize
str = self.class.pattern size, "\0"

self_m = Rubinius::Mirror.reflect self
index = self_m.character_to_byte_index index

Rubinius.check_frozen
@hash_value = nil

m = Rubinius::Mirror.reflect str
if index == bytesize
m.copy_from self, 0, bytesize, 0
m.copy_from other, 0, osize, bytesize
else
m.copy_from self, 0, index, 0 if index > 0
m.copy_from other, 0, osize, index
m.copy_from self, index, bytesize - index, index + osize
end

self.num_bytes = size
@data = str.__data__
Rubinius::Type.infect self, other
force_encoding enc

self
end

def tr_trans(source, replacement, squeeze)
source = StringValue(source).dup
replacement = StringValue(replacement).dup

return delete!(source) if replacement.empty?
return if bytesize == 0

invert = source[0] == ?^ && source.length > 1

source.slice!(0) if invert
source.tr_expand! nil, true
replacement.tr_expand! nil, false

multi_table = {}

if invert
r = replacement.__data__[replacement.size - 1]
table = Rubinius::Tuple.pattern 256, r

source.each_char do |chr|
if chr.bytesize > 1
multi_table[chr] = -1
else
table[chr.ord] = -1
end
end
else
repl = replacement.__data__
rsize = replacement.size
table = Rubinius::Tuple.pattern 256, -1

i = 0
source.each_char do |chr|
repl_char = replacement[i]

if repl_char && (chr.bytesize > 1 || repl_char.bytesize > 1)
multi_table[chr] = repl_char
else
r = repl[i] if i < rsize
table[chr.ord] = r
end

i += 1
end
end

destination = dup
modified = false

if squeeze
last = nil
byte_size = 0

i = 0
each_char do |chr|
c = -1
c = table[chr.ord] if chr.bytesize == 1

if c >= 0
c_char = c.chr
next if last == c_char
byte_size += 1
destination[i] = c_char
last = c_char
modified = true
elsif c = multi_table[chr]
next if last == c
destination[i] = c
last = c
modified = true
byte_size += c.bytesize
else
destination[i] = chr
byte_size += chr.bytesize
last = nil
end

i += 1
end

destination.num_bytes = byte_size if byte_size < bytesize
else
i = 0
each_char do |chr|
c = -1
c = table[chr.ord] if chr.bytesize == 1

if c >= 0
c_char = c.chr
destination[i] = c_char
modified = true
elsif c = multi_table[chr]
destination[i] = c
modified = true
end
i += 1
end
end

if modified
replace(destination)
else
nil
end
end

def <=>(other)
if other.kind_of?(String)
result = @data.compare_bytes(other.__data__, bytesize, other.bytesize)

if result == 0
if Encoding.compatible?(self, other)
0
else
Rubinius::Type.encoding_order(encoding, other.encoding)
end
else
result
end
else
if other.respond_to?(:<=>) && !other.respond_to?(:to_str)
return unless tmp = (other <=> self)
elsif other.respond_to?(:to_str)
return unless tmp = (other.to_str <=> self)
else
return
end
return -tmp # We're not supposed to convert to integer here
end
end

def dump
s = self.class.allocate
str = %{"#{transform(Rubinius::CType::Printed).force_encoding(Encoding::US_ASCII)}"}
str += ".force_encoding(\"#{encoding}\")" unless encoding.ascii_compatible?
s.replace(str)
end
end

0 comments on commit df050f2

Please sign in to comment.