Skip to content

Commit 80bbe8d

Browse files
committed
Ruby 2.7: Better support of Integer#[] with range arguments
1 parent 9bd1204 commit 80bbe8d

File tree

3 files changed

+68
-16
lines changed

3 files changed

+68
-16
lines changed
Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1 @@
1-
fails:Integer#[] fixnum when index and length passed returns specified number of bits from specified position
2-
fails:Integer#[] fixnum when index and length passed ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)
3-
fails:Integer#[] fixnum when index and length passed moves start position to the most significant bits when negative index passed
4-
fails:Integer#[] fixnum when index and length passed ignores negative length
5-
fails:Integer#[] fixnum when range passed returns bits specified by range
6-
fails:Integer#[] fixnum when range passed ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)
7-
fails:Integer#[] fixnum when range passed ensures n[i..] equals to (n >> i)
8-
fails:Integer#[] fixnum when range passed moves lower boundary to the most significant bits when negative value passed
9-
fails:Integer#[] fixnum when range passed ignores negative upper boundary
10-
fails:Integer#[] fixnum when range passed ignores upper boundary smaller than lower boundary
111
fails:Integer#[] fixnum when range passed raises FloatDomainError if any boundary is infinity
12-
fails:Integer#[] fixnum when range passed when passed (..i) returns 0 if all i bits equal 0
13-
fails:Integer#[] fixnum when range passed when passed (..i) raises ArgumentError if any of i bit equals 1

src/main/ruby/truffleruby/core/integer.rb

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
Object.deprecate_constant :Fixnum, :Bignum
3939

4040
class Integer < Numeric
41+
FIXNUM_MAX = 0x3fffffff
4142

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

62-
def [](index)
63-
index = Primitive.rb_to_int(index)
64-
index < 0 ? 0 : (self >> index) & 1
63+
def [](index, len = undefined)
64+
def cmp(a, b)
65+
return FIXNUM_MAX if Primitive.nil?(b)
66+
return a - b
67+
end
68+
def fix_aref(num, idx)
69+
val = Primitive.rb_num2long(num)
70+
idx = Primitive.rb_to_int idx
71+
if !Truffle::Type.fits_into_long?(idx)
72+
if idx < 0 || val >= 0
73+
return 0
74+
else
75+
return 1
76+
end
77+
end
78+
return 0 if idx < 0
79+
return 1 if (val & (1 << idx) > 0)
80+
return 0
81+
end
82+
if index.kind_of?(Range)
83+
exclude_end = index.exclude_end?
84+
lm = index.begin
85+
rm = index.end
86+
if Primitive.nil?(lm)
87+
if !Primitive.nil?(rm) && rm >= 0
88+
rm += 1 if !exclude_end
89+
mask = (1 << rm) - 1
90+
if (self & mask) == 0
91+
return 0
92+
else
93+
raise ArgumentError,
94+
"The beginless range for Integer#[] results in infinity"
95+
end
96+
else
97+
return 0
98+
end
99+
end
100+
num = self >> lm
101+
cmp = cmp(lm, rm)
102+
if !Primitive.nil?(rm) && cmp < 0
103+
len = rm - lm
104+
105+
len += 1 if !exclude_end
106+
107+
mask = (1 << len) - 1
108+
num = num & mask
109+
elsif cmp == 0
110+
return 0 if exclude_end
111+
num = self
112+
arg = lm
113+
return Truffle::Type.fits_into_long?(num) ? fix_aref(num, arg) : self[lm]
114+
115+
end
116+
num
117+
118+
else
119+
index = Primitive.rb_to_int(index)
120+
if Primitive.undefined?(len)
121+
122+
return index < 0 ? 0 : (self >> index) & 1
123+
else
124+
num = self >> index
125+
mask = (1 << len) - 1
126+
127+
return num & mask
128+
end
129+
end
65130
end
66131

67132
def allbits?(mask)

test/mri/excludes/TestInteger.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@
1212
exclude :test_pow, "needs investigation"
1313
exclude :test_truncate, "needs investigation"
1414
exclude :test_Integer_with_invalid_exception, "needs investigation"
15-
exclude :test_aref, "needs investigation"

0 commit comments

Comments
 (0)