core/integer.rb
class Integer < Numeric
def self.===(obj)
Rubinius.asm do
int = new_label
done = new_label
r0 = new_register
r_load_local r0, 0
b_if_int r0, r0, int
goto done
int.set!
r_load_true r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
# unary operators
def !
false
end
def ~
Rubinius.asm do
eint = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_self r0
n_promote r1, r0, r0
r_load_2 r2
n_ieq r3, r1, r2
b_if r3, eint
n_iinc r2, r2
n_ine r3, r1, r2
b_if r3, done
r_load_int r0, r0
n_inot r0, r0
r_store_int r0, r0
goto val
eint.set!
n_enot r0, r0
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
def -@
Rubinius.asm do
eint = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_self r0
n_promote r1, r0, r0
r_load_2 r2
n_ieq r3, r1, r2
b_if r3, eint
n_iinc r2, r2
n_ine r3, r1, r2
b_if r3, done
n_ineg_o r0, r0
goto val
eint.set!
n_eneg r0, r0
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
def bit_length
Rubinius.asm do
eint = new_label
bits = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_self r0
n_promote r1, r0, r0
r_load_2 r2
n_ieq r3, r1, r2
b_if r3, eint
n_iinc r2, r2
n_ine r3, r1, r2
b_if r3, done
r_load_int r0, r0
n_ibits r0, r0
r_store_int r0, r0
goto val
eint.set!
r_load_0 r1
r_store_int r1, r1
n_promote r2, r0, r1
r_load_2 r3
n_ine r3, r2, r3
b_if r3, done
n_egt r2, r0, r1
b_if r2, bits
n_enot r0, r0
bits.set!
n_ebits r0, r0
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
# binary math operators
def +(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_eadd r0, r0, r1
goto val
flt.set!
n_dadd r0, r0, r1
r_store_float r0, r0
goto val
int.set!
n_iadd_o r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :+, other
end
def -(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_esub r0, r0, r1
goto val
flt.set!
n_dsub r0, r0, r1
r_store_float r0, r0
goto val
int.set!
n_isub_o r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :-, other
end
def *(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_emul r0, r0, r1
goto val
flt.set!
n_dmul r0, r0, r1
r_store_float r0, r0
goto val
int.set!
n_imul_o r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :*, other
end
def /(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_ediv r0, r0, r1
goto val
flt.set!
n_ddiv r0, r0, r1
r_store_float r0, r0
goto val
int.set!
n_idiv_o r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :/, other
end
alias_method :divide, :/
def div(o)
if o.is_a?(Float) && o == 0.0
raise ZeroDivisionError, "division by zero"
end
(self / o).floor
end
def fdiv(other)
to_f / other
end
def %(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_emod r0, r0, r1
goto val
flt.set!
n_dmod r0, r0, r1
r_store_float r0, r0
goto val
int.set!
n_imod_o r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :%, other
end
alias_method :modulo, :%
def divmod(other)
Rubinius.asm do
int = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
n_edivmod r2, r0, r1
goto val
flt.set!
n_ddivmod r2, r0, r1
goto val
int.set!
n_idivmod r2, r0, r1
val.set!
r_store_stack r0
r_store_stack r1
make_array 2
ret
done.set!
# TODO: teach the bytecode compiler better
push_true
end
redo_coerced :divmod, other
end
def **(o)
Rubinius.asm do
int = new_label
eint = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_2 r3
n_ieq r3, r3, r2
b_if r3, eint
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
goto done
int.set!
r_load_0 r2
n_ilt r3, r1, r2
b_if r3, done
n_ipow_o r0, r0, r1
goto val
eint.set!
r_load_0 r2
r_store_int r2, r2
n_promote r3, r0, r2
n_elt r3, r1, r2
b_if r3, done
n_epow r0, r0, r1
val.set!
r_ret r0
flt.set!
# TODO: add n_dpow
r_store_float r0, r0
r_store_float r1, r1
r_store_stack r0
r_store_stack r1
send :**, 1
ret
done.set!
# TODO: teach the bytecode compiler better
push_true
end
if o.is_a?(Float) && self < 0 && o != o.round
return Complex.new(self, 0) ** o
elsif o.is_a?(Integer) && o < 0
return Rational.new(self, 1) ** o
end
redo_coerced :**, o
end
# comparison operators
def !=(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_ene r0, r0, r1
goto val
flt.set!
n_dne r0, r0, r1
goto val
cmp.set!
n_ine r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other != self ? true : false
end
def eql?(other)
other.is_a?(Integer) && self == other
end
def ==(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_eeq r0, r0, r1
goto val
flt.set!
n_deq r0, r0, r1
goto val
cmp.set!
n_ieq r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other == self ? true : false
end
alias_method :===, :==
def <(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_elt r0, r0, r1
goto val
flt.set!
n_dlt r0, r0, r1
goto val
cmp.set!
n_ilt r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
b, a = math_coerce other, :compare_error
a < b ? true : false
end
def <=(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_ele r0, r0, r1
goto val
flt.set!
n_dle r0, r0, r1
goto val
cmp.set!
n_ile r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
b, a = math_coerce other, :compare_error
a <= b ? true : false
end
def >(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_egt r0, r0, r1
goto val
flt.set!
n_dgt r0, r0, r1
goto val
cmp.set!
n_igt r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
b, a = math_coerce other, :compare_error
a > b ? true : false
end
def >=(other)
Rubinius.asm do
cmp = new_label
flt = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, cmp
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ieq r3, r3, r2
b_if r3, flt
n_ege r0, r0, r1
goto val
flt.set!
n_dge r0, r0, r1
goto val
cmp.set!
n_ige r0, r0, r1
val.set!
r_load_bool r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
b, a = math_coerce other, :compare_error
a >= b ? true : false
end
def <=>(other)
Rubinius.asm do
int = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_2 r3
n_ine r3, r2, r3
b_if r3, done
n_ecmp r0, r0, r1
goto val
int.set!
n_icmp r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
if other.kind_of? Float
return nil if other.nan?
return -1 if other.infinite? == 1
return 1 if other.infinite? == -1
end
begin
b, a = math_coerce other, :compare_error
return a <=> b
rescue ArgumentError, TypeError
return nil
end
end
# bitwise binary operators
def &(other)
Rubinius.asm do
int = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_1 r3
n_iadd r3, r3, r3
n_ine r2, r2, r3
b_if r2, done
n_eand r0, r0, r1
r_ret r0
int.set!
r_load_int r0, r0
r_load_int r1, r1
n_iand r0, r0, r1
r_store_int r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other = Rubinius::Type.coerce_to_bitwise_operand other
other & self
end
def |(other)
Rubinius.asm do
int = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_1 r3
n_iadd r3, r3, r3
n_ine r2, r2, r3
b_if r2, done
n_eor r0, r0, r1
r_ret r0
int.set!
r_load_int r0, r0
r_load_int r1, r1
n_ior r0, r0, r1
r_store_int r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other = Rubinius::Type.coerce_to_bitwise_operand other
other | self
end
def ^(other)
Rubinius.asm do
int = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
n_promote r2, r0, r1
r_load_1 r3
n_iadd r3, r3, r3
n_ine r2, r2, r3
b_if r2, done
n_exor r0, r0, r1
r_ret r0
int.set!
r_load_int r0, r0
r_load_int r1, r1
n_ixor r0, r0, r1
r_store_int r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other = Rubinius::Type.coerce_to_bitwise_operand other
other ^ self
end
def <<(other)
Rubinius.asm do
shl = new_label
neg = new_label
eint = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, neg
goto eint
neg.set!
r_load_int r2, r1
r_load_0 r3
n_ige r3, r2, r3
b_if r3, shl
n_ineg r1, r2
r_store_int r1, r1
n_ishr_o r0, r0, r1
r_ret r0
shl.set!
n_ishl_o r0, r0, r1
r_ret r0
eint.set!
n_promote r2, r0, r0
r_load_2 r3
n_ine r2, r2, r3
b_if r2, done
n_promote r2, r1, r1
n_iinc r3, r3
n_ine r2, r2, r3
b_if r2, done
r_load_int r1, r1
n_eshl r0, r0, r1
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other = Rubinius::Type.coerce_to other, Integer, :to_int
self >> -other if other < 0
unless other.kind_of? Fixnum
raise RangeError, "argument is out of range for a Fixnum"
end
self << other
end
def >>(other)
Rubinius.asm do
shr = new_label
neg = new_label
eint = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, neg
goto eint
neg.set!
r_load_int r2, r1
r_load_0 r3
n_ige r3, r2, r3
b_if r3, shr
n_ineg r1, r2
r_store_int r1, r1
n_ishl_o r0, r0, r1
r_ret r0
shr.set!
n_ishr_o r0, r0, r1
r_ret r0
eint.set!
n_promote r2, r0, r0
r_load_2 r3
n_ine r2, r2, r3
b_if r2, done
n_promote r2, r1, r1
n_iinc r3, r3
n_ine r2, r2, r3
b_if r2, done
r_load_int r1, r1
n_eshr r0, r0, r1
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
other = Rubinius::Type.coerce_to other, Integer, :to_int
self << -other if other < 0
unless other.kind_of? Fixnum
raise RangeError, "argument is out of range for a Fixnum"
end
self >> other
end
def to_i
self
end
alias_method :to_int, :to_i
alias_method :truncate, :to_i
alias_method :ceil, :to_i
alias_method :floor, :to_i
def chr(enc=undefined)
if self < 0 || (self & 0xffff_ffff) != self
raise RangeError, "#{self} is outside of the valid character range"
end
if undefined.equal? enc
if 0xff < self
enc = Encoding.default_internal
if enc.nil?
raise RangeError, "#{self} is outside of the valid character range"
end
elsif self < 0x80
enc = Encoding::US_ASCII
else
enc = Encoding::ASCII_8BIT
end
else
enc = Rubinius::Type.coerce_to_encoding enc
end
String.from_codepoint self, enc
end
def round(ndigits=undefined)
return self if undefined.equal? ndigits
if ndigits.kind_of? Numeric
if ndigits > Fixnum::MAX or ndigits <= Fixnum::MIN
raise RangeError, "precision is outside of the range of Fixnum"
end
end
ndigits = Rubinius::Type.coerce_to ndigits, Integer, :to_int
if ndigits > 0
to_f
elsif ndigits == 0
self
else
ndigits = -ndigits
# We want to return 0 if 10 ** ndigits / 2 > self.abs, or, taking
# log_256 of both sides, if log_256(10 ** ndigits / 2) > self.size.
# We have log_256(10) > 0.415241 and log_256(2) = 0.125, so:
return 0 if 0.415241 * ndigits - 0.125 > size
f = 10 ** ndigits
if kind_of? Fixnum and f.kind_of? Fixnum
x = self < 0 ? -self : self
x = (x + f / 2) / f * f
x = -x if self < 0
return x
end
return 0 if f.kind_of? Float
h = f / 2
r = self % f
n = self - r
unless self < 0 ? r <= h : r < h
n += f
end
n
end
end
def gcd(other)
raise TypeError, "Expected Integer but got #{other.class}" unless other.kind_of?(Integer)
min = self.abs
max = other.abs
while min > 0
tmp = min
min = max % min
max = tmp
end
max
end
def rationalize(eps = nil)
Rational(self, 1)
end
def numerator
self
end
def denominator
1
end
def to_r
Rational(self, 1)
end
def lcm(other)
raise TypeError, "Expected Integer but got #{other.class}" unless other.kind_of?(Integer)
if self.zero? or other.zero?
0
else
(self.div(self.gcd(other)) * other).abs
end
end
def gcdlcm(other)
gcd = self.gcd(other)
if self.zero? or other.zero?
[gcd, 0]
else
[gcd, (self.div(gcd) * other).abs]
end
end
def [](index)
index = Rubinius::Type.coerce_to(index, Integer, :to_int)
return 0 if index.is_a?(Bignum)
index < 0 ? 0 : (self >> index) & 1
end
def next
self + 1
end
alias_method :succ, :next
def integer?
true
end
def even?
self & 1 == 0
end
def odd?
self & 1 == 1
end
def ord
self
end
def pred
self - 1
end
def size
Rubinius.asm do
eint = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_self r0
n_promote r1, r0, r0
r_load_2 r2
n_ieq r3, r1, r2
b_if r3, eint
n_iinc r2, r2
n_ine r3, r1, r2
b_if r3, done
n_isize r0, r0
goto val
eint.set!
n_esize r0, r0
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
def times
return to_enum(:times) { self } unless block_given?
i = 0
while i < self
yield i
i += 1
end
self
end
def upto(val)
return to_enum(:upto, val) { self <= val ? val - self + 1 : 0 } unless block_given?
i = self
while i <= val
yield i
i += 1
end
self
end
def downto(val)
return to_enum(:downto, val) { self >= val ? self - val + 1 : 0 } unless block_given?
i = self
while i >= val
yield i
i -= 1
end
self
end
# conversions
def coerce(other)
Rubinius.asm do
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_m_binops r0, r1
n_promote r2, r0, r1
r_load_0 r3
n_ieq r3, r3, r2
b_if r3, done
r_load_1 r3
n_ine r3, r3, r2
b_if r3, val
r_store_float r0, r0
r_store_float r1, r1
val.set!
r_store_stack r1
r_store_stack r0
make_array 2
ret
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super other
end
def imaginary
0
end
def to_f
Rubinius.asm do
eint = new_label
done = new_label
r0 = new_register
r1 = new_register
r2 = new_register
r3 = new_register
r_load_self r0
n_promote r1, r0, r0
r_load_2 r2
n_ieq r3, r1, r2
b_if r3, eint
n_iinc r2, r2
n_ine r3, r1, r2
b_if r3, done
n_iflt r0, r0
r_store_float r0, r0
r_ret r0
eint.set!
n_eflt r0, r0
r_store_float r0, r0
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
def to_s(base=10)
Rubinius.asm do
int = new_label
eint = new_label
base = new_label
val = new_label
done = new_label
r0 = new_register
r1 = new_register
r_load_m_binops r0, r1
b_if_int r0, r1, int
b_if_eint r0, r0, base
goto done
base.set!
b_if_int r1, r1, eint
goto done
eint.set!
n_estr r0, r0, r1
goto val
int.set!
n_istr r0, r0, r1
val.set!
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super base
end
# We do not alias this to #to_s in case someone overrides #to_s.
def inspect
Rubinius.asm do
int = new_label
eint = new_label
done = new_label
r0 = new_register
r1 = new_register
r_load_literal r1, 10
r_load_self r0
b_if_int r0, r0, int
b_if_eint r0, r0, eint
goto done
int.set!
n_istr r0, r0, r1
r_ret r0
eint.set!
n_estr r0, r0, r1
r_ret r0
done.set!
# TODO: teach the bytecode compiler better
push_true
end
super
end
# predicates
def zero?
self == 0
end
end