Skip to content

Commit

Permalink
Ruby 2.7: Better support of Integer#[] with range arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
gogainda committed Dec 8, 2020
1 parent 9bd1204 commit 80bbe8d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 16 deletions.
12 changes: 0 additions & 12 deletions spec/tags/core/integer/element_reference_tags.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1 @@
fails:Integer#[] fixnum when index and length passed returns specified number of bits from specified position
fails:Integer#[] fixnum when index and length passed ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)
fails:Integer#[] fixnum when index and length passed moves start position to the most significant bits when negative index passed
fails:Integer#[] fixnum when index and length passed ignores negative length
fails:Integer#[] fixnum when range passed returns bits specified by range
fails:Integer#[] fixnum when range passed ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)
fails:Integer#[] fixnum when range passed ensures n[i..] equals to (n >> i)
fails:Integer#[] fixnum when range passed moves lower boundary to the most significant bits when negative value passed
fails:Integer#[] fixnum when range passed ignores negative upper boundary
fails:Integer#[] fixnum when range passed ignores upper boundary smaller than lower boundary
fails:Integer#[] fixnum when range passed raises FloatDomainError if any boundary is infinity
fails:Integer#[] fixnum when range passed when passed (..i) returns 0 if all i bits equal 0
fails:Integer#[] fixnum when range passed when passed (..i) raises ArgumentError if any of i bit equals 1
71 changes: 68 additions & 3 deletions src/main/ruby/truffleruby/core/integer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
Object.deprecate_constant :Fixnum, :Bignum

class Integer < Numeric
FIXNUM_MAX = 0x3fffffff

# Have a copy in Integer of the Numeric version, as MRI does
alias_method :remainder, :remainder
Expand All @@ -59,9 +60,73 @@ def **(o)
redo_coerced :**, o
end

def [](index)
index = Primitive.rb_to_int(index)
index < 0 ? 0 : (self >> index) & 1
def [](index, len = undefined)
def cmp(a, b)
return FIXNUM_MAX if Primitive.nil?(b)
return a - b
end
def fix_aref(num, idx)
val = Primitive.rb_num2long(num)
idx = Primitive.rb_to_int idx
if !Truffle::Type.fits_into_long?(idx)
if idx < 0 || val >= 0
return 0
else
return 1
end
end
return 0 if idx < 0
return 1 if (val & (1 << idx) > 0)
return 0
end
if index.kind_of?(Range)
exclude_end = index.exclude_end?
lm = index.begin
rm = index.end
if Primitive.nil?(lm)
if !Primitive.nil?(rm) && rm >= 0
rm += 1 if !exclude_end
mask = (1 << rm) - 1
if (self & mask) == 0
return 0
else
raise ArgumentError,
"The beginless range for Integer#[] results in infinity"
end
else
return 0
end
end
num = self >> lm
cmp = cmp(lm, rm)
if !Primitive.nil?(rm) && cmp < 0
len = rm - lm

len += 1 if !exclude_end

mask = (1 << len) - 1
num = num & mask
elsif cmp == 0
return 0 if exclude_end
num = self
arg = lm
return Truffle::Type.fits_into_long?(num) ? fix_aref(num, arg) : self[lm]

end
num

else
index = Primitive.rb_to_int(index)
if Primitive.undefined?(len)

return index < 0 ? 0 : (self >> index) & 1
else
num = self >> index
mask = (1 << len) - 1

return num & mask
end
end
end

def allbits?(mask)
Expand Down
1 change: 0 additions & 1 deletion test/mri/excludes/TestInteger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@
exclude :test_pow, "needs investigation"
exclude :test_truncate, "needs investigation"
exclude :test_Integer_with_invalid_exception, "needs investigation"
exclude :test_aref, "needs investigation"

0 comments on commit 80bbe8d

Please sign in to comment.