package org.jruby;
import java.math.BigInteger;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.compiler.Constantizable;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.JavaSites;
import org.jruby.runtime.Signature;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import org.jruby.runtime.marshal.UnmarshalStream;
import org.jruby.runtime.opto.OptoFactory;
import org.jruby.util.ByteList;
import org.jruby.util.ConvertBytes;
import org.jruby.util.Numeric;
import org.jruby.util.cli.Options;
import static org.jruby.util.Numeric.f_odd_p;
public class RubyFixnum extends RubyInteger implements Constantizable {
public static RubyClass createFixnumClass(Ruby runtime) {
RubyClass fixnum = runtime.getInteger();
runtime.getObject().setConstant("Fixnum", fixnum);
runtime.getObject().deprecateConstant(runtime, "Fixnum");
runtime.setFixnum(fixnum);
for (int i = 0; i < runtime.fixnumCache.length; i++) {
runtime.fixnumCache[i] = new RubyFixnum(fixnum, i - CACHE_OFFSET);
}
return fixnum;
}
final long value;
private static final int BIT_SIZE = 64;
public static final long SIGN_BIT = (1L << (BIT_SIZE - 1));
public static final long MAX = (1L<<(BIT_SIZE - 1)) - 1;
public static final long MIN = -1 * MAX - 1;
public static final long MAX_MARSHAL_FIXNUM = (1L << 30) - 1;
public static final long MIN_MARSHAL_FIXNUM = - (1L << 30);
public static final boolean USE_CACHE = Options.USE_FIXNUM_CACHE.load();
public static final int CACHE_OFFSET;
static {
int cacheRange = 0;
if (USE_CACHE) {
cacheRange = Options.FIXNUM_CACHE_RANGE.load();
if (cacheRange < 0) cacheRange = 0;
}
CACHE_OFFSET = cacheRange;
}
private static IRubyObject fixCoerce(IRubyObject x) {
do {
x = x.convertToInteger();
} while (!(x instanceof RubyFixnum) && !(x instanceof RubyBignum));
return x;
}
public RubyFixnum(Ruby runtime) {
this(runtime, 0);
}
public RubyFixnum(Ruby runtime, long value) {
super(runtime.getFixnum());
this.value = value;
this.flags |= FROZEN_F;
}
private RubyFixnum(RubyClass klazz, long value) {
super(klazz);
this.value = value;
this.flags |= FROZEN_F;
}
@Override
public ClassIndex getNativeClassIndex() {
return ClassIndex.FIXNUM;
}
@Override
public Object constant() {
Object constant = null;
final long value = this.value;
if (value < CACHE_OFFSET && value >= -CACHE_OFFSET) {
Object[] fixnumConstants = metaClass.runtime.fixnumConstants;
constant = fixnumConstants[(int) value + CACHE_OFFSET];
if (constant == null) {
constant = OptoFactory.newConstantWrapper(IRubyObject.class, this);
fixnumConstants[(int) value + CACHE_OFFSET] = constant;
}
}
return constant;
}
@Override
public final boolean eql(IRubyObject other) {
return other instanceof RubyFixnum && value == ((RubyFixnum) other).value;
}
@Override
public IRubyObject equal_p(ThreadContext context, IRubyObject obj) {
return context.runtime.newBoolean(this == obj || eql(obj));
}
@Override
public boolean isImmediate() {
return true;
}
@Override
public RubyClass getSingletonClass() {
throw getRuntime().newTypeError("can't define singleton");
}
@Override
public Class<?> getJavaClass() {
return long.class;
}
@Override
public double getDoubleValue() {
return value;
}
@Override
public long getLongValue() {
return value;
}
@Override
public int getIntValue() { return (int) value; }
@Override
public BigInteger getBigIntegerValue() {
return BigInteger.valueOf(value);
}
@Override
public int signum() { return Long.signum(value); }
@Override
public RubyInteger negate() {
return negate(metaClass.runtime, value);
}
public static RubyFixnum newFixnum(Ruby runtime, long value) {
if (USE_CACHE && isInCacheRange(value)) {
return cachedFixnum(runtime, value);
}
return new RubyFixnum(runtime, value);
}
private static boolean isInCacheRange(long value) {
return value <= CACHE_OFFSET - 1 && value >= -CACHE_OFFSET;
}
private static RubyFixnum cachedFixnum(Ruby runtime, long value) {
return runtime.fixnumCache[(int) (value + CACHE_OFFSET)];
}
@Deprecated
public final RubyFixnum newFixnum(long newValue) {
return newFixnum(getRuntime(), newValue);
}
public static RubyFixnum zero(Ruby runtime) {
return CACHE_OFFSET > 0 ? runtime.fixnumCache[CACHE_OFFSET] : new RubyFixnum(runtime, 0);
}
public static RubyFixnum one(Ruby runtime) {
return CACHE_OFFSET > 1 ? runtime.fixnumCache[CACHE_OFFSET + 1] : new RubyFixnum(runtime, 1);
}
public static RubyFixnum two(Ruby runtime) {
return CACHE_OFFSET > 2 ? runtime.fixnumCache[CACHE_OFFSET + 2] : new RubyFixnum(runtime, 2);
}
public static RubyFixnum three(Ruby runtime) {
return CACHE_OFFSET > 3 ? runtime.fixnumCache[CACHE_OFFSET + 3] : new RubyFixnum(runtime, 3);
}
public static RubyFixnum four(Ruby runtime) {
return CACHE_OFFSET > 4 ? runtime.fixnumCache[CACHE_OFFSET + 4] : new RubyFixnum(runtime, 4);
}
public static RubyFixnum five(Ruby runtime) {
return CACHE_OFFSET > 5 ? runtime.fixnumCache[CACHE_OFFSET + 5] : new RubyFixnum(runtime, 5);
}
public static RubyFixnum minus_one(Ruby runtime) {
return -CACHE_OFFSET <= -1 ? runtime.fixnumCache[CACHE_OFFSET - 1] : new RubyFixnum(runtime, -1);
}
@Override
public RubyFixnum hash() {
return newFixnum(metaClass.runtime, hashCode());
}
@Override
public final int hashCode() {
return (int) (value ^ value >>> 32);
}
@Override
public IRubyObject times(ThreadContext context, Block block) {
if (block.isGiven()) {
final long value = this.value;
boolean checkArity = block.type.checkArity;
if (block.getSignature() == Signature.NO_ARGUMENTS) {
if (checkArity) {
final IRubyObject nil = context.nil;
for (long i = 0; i < value; i++) {
block.yieldSpecific(context, nil);
}
} else {
for (long i = 0; i < value; i++) {
block.yieldSpecific(context);
}
}
} else {
final Ruby runtime = context.runtime;
for (long i = 0; i < value; i++) {
block.yield(context, RubyFixnum.newFixnum(runtime, i));
}
}
return this;
}
return RubyEnumerator.enumeratorizeWithSize(context, this, "times", timesSizeFn(context.runtime));
}
@Override
public IRubyObject ceil(ThreadContext context, IRubyObject arg){
long ndigits = arg.convertToInteger().getLongValue();
if (ndigits >= 0) {
return this;
} else {
long self = this.value;
long posdigits = Math.abs(ndigits);
long exp = (long) Math.pow(10, posdigits);
long mod = (self % exp + exp) % exp;
long res = self;
if (mod != 0) {
res = self + (exp - (mod));
}
return newFixnum(context.runtime, res);
}
}
@Override
public IRubyObject floor(ThreadContext context, IRubyObject arg){
long ndigits = (arg).convertToInteger().getLongValue();
if (ndigits >= 0) {
return this;
} else {
long self = this.value;
long posdigits = Math.abs(ndigits);
long exp = (long) Math.pow(10, posdigits);
long mod = (self % exp + exp) % exp;
long res = self - mod;
return newFixnum(context.runtime, res);
}
}
@Override
public IRubyObject truncate(ThreadContext context, IRubyObject arg) {
long self = this.value;
if (self > 0){
return floor(context, arg);
} else if (self < 0){
return ceil(context, arg);
} else {
return this;
}
}
@Override
public RubyArray digits(ThreadContext context, IRubyObject base) {
final Ruby runtime = context.runtime;
long value = getLongValue();
if (value < 0) {
throw runtime.newMathDomainError("out of domain");
}
if (!(base instanceof RubyInteger)) {
try {
base = base.convertToInteger();
} catch (ClassCastException e) {
String cname = getMetaClass(base).getRealClass().getName();
throw runtime.newTypeError("wrong argument type " + cname + " (expected Integer)");
}
}
if (base instanceof RubyBignum){
return RubyArray.newArray(context.runtime, newFixnum(runtime, value));
}
long longBase = ((RubyFixnum) base).value;
if (longBase < 0) {
throw runtime.newArgumentError("negative radix");
}
if (longBase < 2) {
throw runtime.newArgumentError("invalid radix: " + longBase);
}
if (value == 0) {
return RubyArray.newArray(context.runtime, zero(runtime));
}
RubyArray res = RubyArray.newArray(context.runtime, 0);
while (value > 0) {
res.append(newFixnum(runtime, value % longBase));
value /= longBase;
}
return res;
}
public RubyString to_s(IRubyObject[] args) {
switch (args.length) {
case 0: return to_s();
case 1: return to_s(args[0]);
default: throw metaClass.runtime.newArgumentError(args.length, 1);
}
}
@Override
public RubyString to_s() {
ByteList bytes = ConvertBytes.longToByteList(value, 10);
return RubyString.newString(metaClass.runtime, bytes, USASCIIEncoding.INSTANCE);
}
@Override
public RubyString to_s(IRubyObject arg0) {
int base = num2int(arg0);
if (base < 2 || base > 36) {
throw metaClass.runtime.newArgumentError("illegal radix " + base);
}
ByteList bytes = ConvertBytes.longToByteList(value, base);
return RubyString.newString(metaClass.runtime, bytes, USASCIIEncoding.INSTANCE);
}
@Deprecated
public IRubyObject to_sym() {
RubySymbol symbol = RubySymbol.getSymbolLong(getRuntime(), value);
return symbol != null ? symbol : getRuntime().getNil();
}
@Override
public IRubyObject op_uminus(ThreadContext context) {
return negate(context.runtime, value);
}
private static RubyInteger negate(final Ruby runtime, final long value) {
if (value == MIN) {
return RubyBignum.newBignum(runtime, BigInteger.valueOf(value).negate());
}
return RubyFixnum.newFixnum(runtime, -value);
}
@Override
public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return addFixnum(context, (RubyFixnum) other);
}
return addOther(context, other);
}
@Override
public IRubyObject op_plus(ThreadContext context, long other) {
try {
return newFixnum(context.runtime, Math.addExact(value, other));
} catch (ArithmeticException ae) {
return addAsBignum(context, other);
}
}
public IRubyObject op_plus(ThreadContext context, double other) {
return context.runtime.newFloat((double) value + other);
}
public IRubyObject op_plus_one(ThreadContext context) {
try {
return newFixnum(context.runtime, Math.addExact(value, 1));
} catch (ArithmeticException ae) {
return addAsBignum(context, 1);
}
}
public IRubyObject op_plus_two(ThreadContext context) {
long result = value + 2;
if (result < value) {
return addAsBignum(context, 2);
}
return newFixnum(context.runtime, result);
}
private RubyInteger addFixnum(ThreadContext context, RubyFixnum other) {
try {
return newFixnum(context.runtime, Math.addExact(value, other.value));
} catch (ArithmeticException ae) {
return addAsBignum(context, other.value);
}
}
private RubyInteger addAsBignum(ThreadContext context, long other) {
return (RubyInteger) RubyBignum.newBignum(context.runtime, value).op_plus(context, other);
}
private IRubyObject addOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_plus(context, value);
}
if (other instanceof RubyFloat) {
return op_plus(context, ((RubyFloat) other).value);
}
return coerceBin(context, sites(context).op_plus, other);
}
@Override
public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return op_minus(context, ((RubyFixnum) other).value);
}
return subtractOther(context, other);
}
@Override
public IRubyObject op_minus(ThreadContext context, long other) {
try {
return newFixnum(context.runtime, Math.subtractExact(value, other));
} catch (ArithmeticException ae) {
return subtractAsBignum(context, other);
}
}
public IRubyObject op_minus(ThreadContext context, double other) {
return context.runtime.newFloat((double) value - other);
}
public IRubyObject op_minus_one(ThreadContext context) {
try {
return newFixnum(context.runtime, Math.subtractExact(value, 1));
} catch (ArithmeticException ae) {
return subtractAsBignum(context, 1);
}
}
public IRubyObject op_minus_two(ThreadContext context) {
try {
return newFixnum(context.runtime, Math.subtractExact(value, 2));
} catch (ArithmeticException ae) {
return subtractAsBignum(context, 2);
}
}
private RubyInteger subtractAsBignum(ThreadContext context, long other) {
return (RubyInteger) RubyBignum.newBignum(context.runtime, value).op_minus(context, other);
}
private IRubyObject subtractOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBignum.newBignum(context.runtime, value).op_minus(context, ((RubyBignum) other).value);
}
if (other instanceof RubyFloat) {
return op_minus(context, ((RubyFloat) other).value);
}
return coerceBin(context, sites(context).op_minus, other);
}
@Override
public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return op_mul(context, ((RubyFixnum) other).value);
}
return multiplyOther(context, other);
}
private IRubyObject multiplyOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_mul(context, this.value);
}
if (other instanceof RubyFloat) {
return op_mul(context, ((RubyFloat) other).value);
}
return coerceBin(context, sites(context).op_times, other);
}
@Override
public IRubyObject op_mul(ThreadContext context, long other) {
Ruby runtime = context.runtime;
try {
return newFixnum(runtime, Math.multiplyExact(value, other));
} catch (ArithmeticException ae) {
return RubyBignum.newBignum(runtime, value).op_mul(context, other);
}
}
public IRubyObject op_mul(ThreadContext context, double other) {
return context.runtime.newFloat((double) value * other);
}
@Override
public IRubyObject idiv(ThreadContext context, IRubyObject other) {
checkZeroDivisionError(context, other);
if (other instanceof RubyFixnum) {
return idivLong(context, value, ((RubyFixnum) other).value);
}
return coerceBin(context, sites(context).div, other);
}
@Override
public IRubyObject idiv(ThreadContext context, long other) {
return idivLong(context, value, other);
}
@Override
public IRubyObject op_div(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return idivLong(context, value, ((RubyFixnum) other).value);
}
return coerceBin(context, sites(context).op_quo, other);
}
public IRubyObject op_div(ThreadContext context, long other) {
return idivLong(context, value, other);
}
@Override
public RubyBoolean odd_p(ThreadContext context) {
return (value & 1) != 0 ? context.tru : context.fals;
}
@Override
public RubyBoolean even_p(ThreadContext context) {
return (value & 1) == 0 ? context.tru : context.fals;
}
public IRubyObject pred(ThreadContext context) {
return op_minus_one(context);
}
@Deprecated
public IRubyObject idiv(ThreadContext context, IRubyObject other, String method) {
if (other instanceof RubyFixnum) {
return idivLong(context, value, ((RubyFixnum) other).value);
}
return coerceBin(context, method, other);
}
public IRubyObject idiv(ThreadContext context, IRubyObject other, CallSite site) {
if (other instanceof RubyFixnum) {
return idivLong(context, value, ((RubyFixnum) other).value);
}
return coerceBin(context, site, other);
}
@Deprecated
public IRubyObject idiv(ThreadContext context, long y, String method) {
long x = value;
return idivLong(context, x, y);
}
private RubyInteger idivLong(ThreadContext context, long x, long y) {
final Ruby runtime = context.runtime;
if (y == 0) {
throw runtime.newZeroDivisionError();
}
long result;
if (y > 0) {
if (x >= 0) {
result = x / y;
} else {
result = (x + 1) / y - 1;
}
} else if (x > 0) {
result = (x - 1) / y - 1;
} else if (y == -1) {
if (x == MIN) {
return RubyBignum.newBignum(runtime, BigInteger.valueOf(x).negate());
}
result = -x;
} else {
result = x / y;
}
return runtime.newFixnum(result);
}
@Override
public IRubyObject op_mod(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return moduloFixnum(context, (RubyFixnum) other);
}
checkZeroDivisionError(context, other);
return coerceBin(context, sites(context).op_mod, other);
}
@Override
public IRubyObject op_mod(ThreadContext context, long other) {
return moduloFixnum(context, other);
}
@Override
public IRubyObject modulo(ThreadContext context, IRubyObject other) {
return op_mod(context, other);
}
@Override
IRubyObject modulo(ThreadContext context, long other) {
return op_mod(context, other);
}
private IRubyObject moduloFixnum(ThreadContext context, RubyFixnum other) {
return moduloFixnum(context, other.value);
}
private IRubyObject moduloFixnum(ThreadContext context, long other) {
long x = value;
long y = other;
if (y == 0) {
throw context.runtime.newZeroDivisionError();
}
long mod = x % y;
if (mod < 0 && y > 0 || mod > 0 && y < 0) {
mod += y;
}
return context.runtime.newFixnum(mod);
}
@Override
public IRubyObject divmod(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return divmodFixnum(context, (RubyFixnum) other);
}
checkZeroDivisionError(context, other);
return coerceBin(context, sites(context).divmod, other);
}
private IRubyObject divmodFixnum(ThreadContext context, RubyFixnum other) {
final Ruby runtime = context.runtime;
final long x = this.value;
final long y = other.value;
if (y == 0) {
throw runtime.newZeroDivisionError();
}
long mod; final RubyInteger integerDiv;
if (y == -1) {
if (x == MIN) {
integerDiv = RubyBignum.newBignum(runtime, BigInteger.valueOf(x).negate());
} else {
integerDiv = RubyFixnum.newFixnum(runtime, -x);
}
mod = 0;
} else {
long div = x / y;
mod = x - y * div;
if (mod < 0 && y > 0 || mod > 0 && y < 0) {
div -= 1;
mod += y;
}
integerDiv = RubyFixnum.newFixnum(runtime, div);
}
IRubyObject fixMod = RubyFixnum.newFixnum(runtime, mod);
return RubyArray.newArray(runtime, integerDiv, fixMod);
}
@Override
public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
if (other instanceof RubyNumeric) {
double d_other = ((RubyNumeric) other).getDoubleValue();
if (value < 0 && (d_other != Math.round(d_other))) {
RubyComplex complex = RubyComplex.newComplexRaw(context.runtime, this);
return numFuncall(context, complex, sites(context).op_exp_complex, other);
}
if (other instanceof RubyFixnum) {
return powerFixnum(context, (RubyFixnum) other);
}
}
return powerOther(context, other);
}
public IRubyObject op_pow(ThreadContext context, long other) {
return powerFixnum(context, RubyFixnum.newFixnum(context.runtime, other));
}
@Deprecated
public IRubyObject op_pow_19(ThreadContext context, IRubyObject other) {
return op_pow(context, other);
}
private IRubyObject powerOther(ThreadContext context, IRubyObject other) {
final Ruby runtime = context.runtime;
final long a = this.value;
if (other instanceof RubyBignum) {
if (sites(context).op_lt_bignum.call(context, other, other, RubyFixnum.zero(runtime)).isTrue()) {
RubyRational rational = RubyRational.newRationalRaw(runtime, this);
return numFuncall(context, rational, sites(context).op_exp_rational, other);
}
if (a == 0) return RubyFixnum.zero(runtime);
if (a == 1) return RubyFixnum.one(runtime);
if (a == -1) {
return ((RubyBignum) other).even_p(context).isTrue() ? RubyFixnum.one(runtime) : RubyFixnum.minus_one(runtime);
}
return RubyBignum.newBignum(runtime, RubyBignum.long2big(a)).op_pow(context, other);
}
if (other instanceof RubyFloat) {
double b = ((RubyFloat) other).value;
if (b == 0.0 || a == 1) return runtime.newFloat(1.0);
if (a == 0) return runtime.newFloat(b < 0 ? 1.0 / 0.0 : 0.0);
return RubyFloat.newFloat(runtime, Math.pow(a, b));
}
return coerceBin(context, sites(context).op_exp, other);
}
private RubyNumeric powerFixnum(ThreadContext context, RubyFixnum other) {
Ruby runtime = context.runtime;
long a = value;
long b = other.value;
if (b < 0) {
RubyRational rational = RubyRational.newRationalRaw(runtime, this);
return (RubyNumeric) numFuncall(context, rational, sites(context).op_exp_rational, other);
}
if (b == 0) {
return RubyFixnum.one(runtime);
}
if (b == 1) {
return this;
}
if (a == 0) {
return b > 0 ? RubyFixnum.zero(runtime) : RubyNumeric.dbl2ival(runtime, 1.0 / 0.0);
}
if (a == 1) {
return RubyFixnum.one(runtime);
}
if (a == -1) {
return b % 2 == 0 ? RubyFixnum.one(runtime) : RubyFixnum.minus_one(runtime);
}
return Numeric.int_pow(context, a, b);
}
protected IRubyObject intPowTmp1(ThreadContext context, RubyInteger y, long mm, boolean negaFlg) {
Ruby runtime = context.runtime;
long xx = this.value;
long tmp = 1L;
long yy;
for (; !(y instanceof RubyFixnum); y = (RubyInteger) sites(context).op_rshift.call(context, y, y, RubyFixnum.one(runtime))) {
if (f_odd_p(context, y)) {
tmp = (tmp * xx) % mm;
}
xx = (xx * xx) % mm;
}
for (yy = y.convertToInteger().getLongValue(); yy != 0L; yy >>= 1L) {
if ((yy & 1L) != 0L) {
tmp = (tmp * xx) % mm;
}
xx = (xx * xx) % mm;
}
if (negaFlg && (tmp != 0)) {
tmp -= mm;
}
return runtime.newFixnum(tmp);
}
@Deprecated
protected IRubyObject intPowTmp2(ThreadContext context, IRubyObject y, final long mm, boolean negaFlg) {
return intPowTmp2(context, (RubyInteger) y, mm, negaFlg);
}
IRubyObject intPowTmp2(ThreadContext context, RubyInteger y, final long mm, boolean negaFlg) {
Ruby runtime = context.runtime;
long tmp = 1L;
long yy;
RubyFixnum tmp2 = runtime.newFixnum(tmp);
RubyFixnum xx = this;
for (; !(y instanceof RubyFixnum); y = (RubyInteger) sites(context).op_rshift.call(context, y, y, RubyFixnum.one(runtime))) {
if (f_odd_p(context, y)) {
tmp2 = mulModulo(context, tmp2, xx, mm);
}
xx = mulModulo(context, xx, xx, mm);
}
for (yy = ((RubyFixnum) y).value; yy != 0; yy >>= 1L) {
if ((yy & 1L) != 0) {
tmp2 = mulModulo(context, tmp2, xx, mm);
}
xx = mulModulo(context, xx, xx, mm);
}
tmp = tmp2.value;
if (negaFlg && (tmp != 0)) {
tmp -= mm;
}
return runtime.newFixnum(tmp);
}
private static RubyFixnum mulModulo(ThreadContext context, RubyFixnum a, RubyFixnum b, long c) {
return (RubyFixnum) ((RubyInteger) a.op_mul(context, b.value)).modulo(context, c);
}
@Override
public IRubyObject abs(ThreadContext context) {
if (value < 0) {
if (value == Long.MIN_VALUE) {
return RubyBignum.newBignum(context.runtime, BigInteger.valueOf(value).negate());
}
return RubyFixnum.newFixnum(context.runtime, -value);
}
return this;
}
@Override
public IRubyObject magnitude(ThreadContext context) {
return abs(context);
}
@Override
public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
return other instanceof RubyFixnum ?
op_equal(context, ((RubyFixnum) other).value) : op_equalOther(context, other);
}
public IRubyObject op_equal(ThreadContext context, long other) {
return RubyBoolean.newBoolean(context.runtime, value == other);
}
public IRubyObject op_equal(ThreadContext context, double other) {
return RubyBoolean.newBoolean(context.runtime, (double) value == other);
}
public boolean op_equal_boolean(ThreadContext context, long other) {
return value == other;
}
public final boolean fastEqual(RubyFixnum other) {
return value == other.value;
}
private IRubyObject op_equalOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBoolean.newBoolean(context.runtime,
BigInteger.valueOf(this.value).compareTo(((RubyBignum) other).value) == 0);
}
if (other instanceof RubyFloat) {
return op_equal(context, ((RubyFloat) other).value);
}
return super.op_num_equal(context, other);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (other instanceof RubyFixnum) {
return value == ((RubyFixnum) other).value;
}
return false;
}
@Override
public final int compareTo(IRubyObject other) {
if (other instanceof RubyFixnum) {
long otherValue = ((RubyFixnum) other).value;
return value == otherValue ? 0 : value > otherValue ? 1 : -1;
}
return compareToOther(other);
}
private int compareToOther(IRubyObject other) {
if (other instanceof RubyBignum) return BigInteger.valueOf(value).compareTo(((RubyBignum) other).value);
if (other instanceof RubyFloat) return Double.compare((double) value, ((RubyFloat) other).value);
ThreadContext context = metaClass.runtime.getCurrentContext();
return (int) coerceCmp(context, sites(context).op_cmp, other).convertToInteger().getLongValue();
}
@Override
public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
return other instanceof RubyFixnum ?
op_cmp(context, ((RubyFixnum) other).value) : compareOther(context, other);
}
public IRubyObject op_cmp(ThreadContext context, long other) {
Ruby runtime = context.runtime;
return value == other ? RubyFixnum.zero(runtime) : value > other ?
RubyFixnum.one(runtime) : RubyFixnum.minus_one(runtime);
}
public IRubyObject op_cmp(ThreadContext context, double other) {
return dbl_cmp(context.runtime, (double) value, other);
}
private IRubyObject compareOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return newFixnum(context.runtime, BigInteger.valueOf(value).compareTo(((RubyBignum) other).value));
}
if (other instanceof RubyFloat) {
return dbl_cmp(context.runtime, (double) value, ((RubyFloat) other).value);
}
return coerceCmp(context, sites(context).op_cmp, other);
}
@Override
public IRubyObject op_gt(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return RubyBoolean.newBoolean(context.runtime, value > ((RubyFixnum) other).value);
}
return op_gtOther(context, other);
}
public IRubyObject op_gt(ThreadContext context, long other) {
return RubyBoolean.newBoolean(context.runtime, value > other);
}
public boolean op_gt_boolean(ThreadContext context, long other) {
return value > other;
}
private IRubyObject op_gtOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBoolean.newBoolean(context.runtime,
BigInteger.valueOf(value).compareTo(((RubyBignum) other).value) > 0);
}
if (other instanceof RubyFloat) {
return RubyBoolean.newBoolean(context.runtime, (double) value > ((RubyFloat) other).value);
}
return coerceRelOp(context, sites(context).op_gt, other);
}
@Override
public IRubyObject op_ge(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return RubyBoolean.newBoolean(context.runtime, value >= ((RubyFixnum) other).value);
}
return op_geOther(context, other);
}
public IRubyObject op_ge(ThreadContext context, long other) {
return RubyBoolean.newBoolean(context.runtime, value >= other);
}
public boolean op_ge_boolean(ThreadContext context, long other) {
return value >= other;
}
private IRubyObject op_geOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBoolean.newBoolean(context.runtime,
BigInteger.valueOf(value).compareTo(((RubyBignum) other).value) >= 0);
}
if (other instanceof RubyFloat) {
return RubyBoolean.newBoolean(context.runtime, (double) value >= ((RubyFloat) other).value);
}
return coerceRelOp(context, sites(context).op_ge, other);
}
@Override
public IRubyObject op_lt(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return op_lt(context, ((RubyFixnum) other).value);
}
return op_ltOther(context, other);
}
public IRubyObject op_lt(ThreadContext context, long other) {
return RubyBoolean.newBoolean(context.runtime, value < other);
}
public boolean op_lt_boolean(ThreadContext context, long other) {
return value < other;
}
private IRubyObject op_ltOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBoolean.newBoolean(context.runtime,
BigInteger.valueOf(value).compareTo(((RubyBignum) other).value) < 0);
}
if (other instanceof RubyFloat) {
return RubyBoolean.newBoolean(context.runtime, (double) value < ((RubyFloat) other).value);
}
return coerceRelOp(context, sites(context).op_lt, other);
}
@Override
public IRubyObject op_le(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return RubyBoolean.newBoolean(context.runtime, value <= ((RubyFixnum) other).value);
}
return op_leOther(context, other);
}
public IRubyObject op_le(ThreadContext context, long other) {
return RubyBoolean.newBoolean(context.runtime, value <= other);
}
public boolean op_le_boolean(ThreadContext context, long other) {
return value <= other;
}
private IRubyObject op_leOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return RubyBoolean.newBoolean(context.runtime,
BigInteger.valueOf(value).compareTo(((RubyBignum) other).value) <= 0);
}
if (other instanceof RubyFloat) {
return RubyBoolean.newBoolean(context.runtime, (double) value <= ((RubyFloat) other).value);
}
return coerceRelOp(context, sites(context).op_le, other);
}
@Override
public IRubyObject op_neg(ThreadContext context) {
return newFixnum(context.runtime, ~value);
}
@Override
public IRubyObject op_and(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return context.runtime.newFixnum(value & ((RubyFixnum) other).value);
}
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_and(context, this);
}
return coerceBit(context, sites(context).checked_op_and, other);
}
public IRubyObject op_and(ThreadContext context, long other) {
return newFixnum(context.runtime, value & other);
}
@Override
public IRubyObject op_or(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return context.runtime.newFixnum(value | ((RubyFixnum) other).value);
}
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_or(context, this);
}
return coerceBit(context, sites(context).checked_op_or, other);
}
public IRubyObject op_or(ThreadContext context, long other) {
return newFixnum(context.runtime, value | other);
}
@Override
public IRubyObject op_xor(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return context.runtime.newFixnum(value ^ ((RubyFixnum) other).value);
}
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_xor(context, this);
}
return coerceBit(context, sites(context).checked_op_xor, other);
}
public IRubyObject op_xor(ThreadContext context, long other) {
return newFixnum(context.runtime, value ^ other);
}
@Override
public IRubyObject op_aref(ThreadContext context, IRubyObject other) {
if (!(other instanceof RubyFixnum) && !((other = fixCoerce(other)) instanceof RubyFixnum)) {
BigInteger big = ((RubyBignum) other).value;
other = RubyBignum.bignorm(context.runtime, big);
if (!(other instanceof RubyFixnum)) {
return big.signum() == 0 || value >= 0 ? RubyFixnum.zero(context.runtime) : RubyFixnum.one(context.runtime);
}
}
long otherValue = fix2long(other);
if (otherValue < 0) return RubyFixnum.zero(context.runtime);
if (BIT_SIZE - 1 < otherValue) {
return value < 0 ? RubyFixnum.one(context.runtime) : RubyFixnum.zero(context.runtime);
}
return (value & (1L << otherValue)) == 0 ? RubyFixnum.zero(context.runtime) : RubyFixnum.one(context.runtime);
}
@Override
public IRubyObject op_lshift(ThreadContext context, IRubyObject other) {
if (!(other instanceof RubyFixnum)) {
return RubyBignum.newBignum(context.runtime, value).op_lshift(context, other);
}
return op_lshift(context, ((RubyFixnum) other).value);
}
@Override
public RubyInteger op_lshift(ThreadContext context, final long width) {
return width < 0 ? rshift(context, -width) : lshift(context, width);
}
private RubyInteger lshift(ThreadContext context, final long width) {
if (width > BIT_SIZE - 1 || ((~0L << BIT_SIZE - width - 1) & value) != 0) {
return RubyBignum.newBignum(context.runtime, value).op_lshift(context, width);
}
return RubyFixnum.newFixnum(context.runtime, value << width);
}
@Deprecated
public IRubyObject op_lshift(long width) {
return op_lshift(getRuntime().getCurrentContext(), width);
}
@Override
public IRubyObject op_rshift(ThreadContext context, IRubyObject other) {
if (!(other instanceof RubyFixnum)) {
return RubyBignum.newBignum(context.runtime, value).op_rshift(context, other);
}
return op_rshift(context, ((RubyFixnum) other).value);
}
@Override
public RubyInteger op_rshift(ThreadContext context, final long width) {
if (width == 0) return this;
return width < 0 ? lshift(context, -width) : rshift(context, width);
}
private RubyFixnum rshift(ThreadContext context, final long width) {
if (width >= BIT_SIZE - 1) {
return value < 0 ? RubyFixnum.minus_one(context.runtime) : RubyFixnum.zero(context.runtime);
}
return RubyFixnum.newFixnum(context.runtime, value >> width);
}
@Deprecated
public IRubyObject op_rshift(long width) {
return op_rshift(getRuntime().getCurrentContext(), width);
}
@Override
public IRubyObject to_f(ThreadContext context) {
return RubyFloat.newFloat(context.runtime, (double) value);
}
@Override
public IRubyObject to_f() {
return RubyFloat.newFloat(metaClass.runtime, (double) value);
}
@Override
public IRubyObject size(ThreadContext context) {
return newFixnum(context.runtime, (long) ((BIT_SIZE + 7) / 8));
}
@Deprecated
public IRubyObject zero_p() {
return zero_p(getRuntime().getCurrentContext());
}
@Override
public IRubyObject zero_p(ThreadContext context) {
return RubyBoolean.newBoolean(context.runtime, value == 0);
}
@Override
public final boolean isZero() {
return value == 0;
}
@Override
public IRubyObject nonzero_p(ThreadContext context) {
return isZero() ? context.nil : this;
}
@Override
final boolean isOne() {
return value == 1;
}
@Override
public IRubyObject succ(ThreadContext context) {
return op_plus_one(context);
}
@Override
public IRubyObject bit_length(ThreadContext context) {
long tmpValue = value;
if (value < 0) {
tmpValue = ~value;
}
return context.runtime.newFixnum(64 - Long.numberOfLeadingZeros(tmpValue));
}
@Override
public IRubyObject id() {
if (value <= Long.MAX_VALUE / 2 && value >= Long.MIN_VALUE / 2) {
return newFixnum(metaClass.runtime, 2 * value + 1);
}
return super.id();
}
@Override
public IRubyObject taint(ThreadContext context) {
return this;
}
@Override
public String asJavaString() {
throw metaClass.runtime.newTypeError(inspect().toString() + " is not a symbol");
}
public static RubyFixnum unmarshalFrom(UnmarshalStream input) throws java.io.IOException {
return input.getRuntime().newFixnum(input.unmarshalInt());
}
private void checkZeroDivisionError(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFloat && ((RubyFloat) other).value == 0.0d) {
throw context.runtime.newZeroDivisionError();
}
}
@Override
public RubyInteger convertToInteger(String method) {
return this;
}
@Override
public IRubyObject fdivDouble(ThreadContext context, IRubyObject y) {
if (y instanceof RubyFixnum) {
return context.runtime.newFloat(((double) value) / ((double) fix2long(y)));
}
if (y instanceof RubyBignum) {
return RubyBignum.newBignum(context.runtime, value).fdivDouble(context, (RubyBignum) y);
}
if (y instanceof RubyFloat) {
return context.runtime.newFloat(((double) value) / ((RubyFloat) y).value);
}
return coerceBin(context, sites(context).fdiv, y);
}
@Override
public IRubyObject isNegative(ThreadContext context) {
Ruby runtime = context.runtime;
CachingCallSite op_lt_site = sites(context).basic_op_lt;
if (op_lt_site.retrieveCache(metaClass).method.isBuiltin()) {
return runtime.newBoolean(value < 0);
}
return op_lt_site.call(context, this, this, RubyFixnum.zero(runtime));
}
@Override
public IRubyObject isPositive(ThreadContext context) {
Ruby runtime = context.runtime;
CachingCallSite op_gt_site = sites(context).basic_op_gt;
if (op_gt_site.retrieveCache(metaClass).method.isBuiltin()) {
return runtime.newBoolean(value > 0);
}
return op_gt_site.call(context, this, this, RubyFixnum.zero(runtime));
}
@Override
protected boolean int_round_zero_p(ThreadContext context, int ndigits) {
long bytes = 8;
return (-0.415241 * ndigits - 0.125 > bytes);
}
@Override
public IRubyObject numerator(ThreadContext context) {
return this;
}
@Override
public IRubyObject denominator(ThreadContext context) {
return one(context.runtime);
}
@Override
public RubyRational convertToRational() {
final Ruby runtime = metaClass.runtime;
return RubyRational.newRationalRaw(runtime, this, one(runtime));
}
@Override
public IRubyObject remainder(ThreadContext context, IRubyObject y) {
return numRemainder(context, y);
}
@Override
public IRubyObject sqrt(ThreadContext context) {
Ruby runtime = context.runtime;
if (isNegative()) {
throw runtime.newMathDomainError("Numerical argument is out of domain - isqrt");
}
long sq = floorSqrt(value);
return RubyFixnum.newFixnum(runtime, sq);
}
private static JavaSites.FixnumSites sites(ThreadContext context) {
return context.sites.Fixnum;
}
@Deprecated
public static IRubyObject induced_from(IRubyObject recv, IRubyObject other) {
return RubyNumeric.num2fix(other);
}
}