1 35 package org.jruby; 36 37 import java.math.BigInteger ; 38 import org.jruby.runtime.Arity; 39 import org.jruby.runtime.Block; 40 import org.jruby.runtime.CallType; 41 import org.jruby.runtime.CallbackFactory; 42 import org.jruby.runtime.ClassIndex; 43 import org.jruby.runtime.ObjectAllocator; 44 import org.jruby.runtime.ThreadContext; 45 import org.jruby.runtime.builtin.IRubyObject; 46 import org.jruby.runtime.marshal.UnmarshalStream; 47 import org.jruby.util.Convert; 48 49 53 public class RubyFixnum extends RubyInteger { 54 55 public static RubyClass createFixnumClass(Ruby runtime) { 56 RubyClass fixnum = runtime.defineClass("Fixnum", runtime.getClass("Integer"), 57 ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); 58 fixnum.index = ClassIndex.FIXNUM; 59 CallbackFactory callbackFactory = runtime.callbackFactory(RubyFixnum.class); 60 61 fixnum.includeModule(runtime.getModule("Precision")); 62 fixnum.getMetaClass().defineFastMethod("induced_from", callbackFactory.getFastSingletonMethod( 63 "induced_from", RubyKernel.IRUBY_OBJECT)); 64 65 fixnum.defineFastMethod("to_s", callbackFactory.getFastOptMethod("to_s")); 66 67 fixnum.defineFastMethod("id2name", callbackFactory.getFastMethod("id2name")); 68 fixnum.defineFastMethod("to_sym", callbackFactory.getFastMethod("to_sym")); 69 70 fixnum.defineFastMethod("-@", callbackFactory.getFastMethod("uminus")); 71 fixnum.defineFastMethod("+", callbackFactory.getFastMethod("plus", RubyKernel.IRUBY_OBJECT)); 72 fixnum.defineFastMethod("-", callbackFactory.getFastMethod("minus", RubyKernel.IRUBY_OBJECT)); 73 fixnum.defineFastMethod("*", callbackFactory.getFastMethod("mul", RubyKernel.IRUBY_OBJECT)); 74 fixnum.defineFastMethod("/", callbackFactory.getFastMethod("div_slash", RubyKernel.IRUBY_OBJECT)); 75 fixnum.defineFastMethod("div", callbackFactory.getFastMethod("div_div", RubyKernel.IRUBY_OBJECT)); 76 fixnum.defineFastMethod("%", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT)); 77 fixnum.defineFastMethod("modulo", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT)); 78 fixnum.defineFastMethod("divmod", callbackFactory.getFastMethod("divmod", RubyKernel.IRUBY_OBJECT)); 79 fixnum.defineFastMethod("quo", callbackFactory.getFastMethod("quo", RubyKernel.IRUBY_OBJECT)); 80 fixnum.defineFastMethod("**", callbackFactory.getFastMethod("pow", RubyKernel.IRUBY_OBJECT)); 81 82 fixnum.defineFastMethod("abs", callbackFactory.getFastMethod("abs")); 83 84 fixnum.defineFastMethod("==", callbackFactory.getFastMethod("equal", RubyKernel.IRUBY_OBJECT)); 85 fixnum.defineFastMethod("<=>", callbackFactory.getFastMethod("cmp", RubyKernel.IRUBY_OBJECT)); 86 87 fixnum.defineFastMethod(">", callbackFactory.getFastMethod("gt", RubyKernel.IRUBY_OBJECT)); 88 fixnum.defineFastMethod(">=", callbackFactory.getFastMethod("ge", RubyKernel.IRUBY_OBJECT)); 89 fixnum.defineFastMethod("<", callbackFactory.getFastMethod("lt", RubyKernel.IRUBY_OBJECT)); 90 fixnum.defineFastMethod("<=", callbackFactory.getFastMethod("le", RubyKernel.IRUBY_OBJECT)); 91 92 fixnum.defineFastMethod("~", callbackFactory.getFastMethod("rev")); 93 fixnum.defineFastMethod("&", callbackFactory.getFastMethod("and", RubyKernel.IRUBY_OBJECT)); 94 fixnum.defineFastMethod("|", callbackFactory.getFastMethod("or", RubyKernel.IRUBY_OBJECT)); 95 fixnum.defineFastMethod("^", callbackFactory.getFastMethod("xor", RubyKernel.IRUBY_OBJECT)); 96 fixnum.defineFastMethod("[]", callbackFactory.getFastMethod("aref", RubyKernel.IRUBY_OBJECT)); 97 fixnum.defineFastMethod("<<", callbackFactory.getFastMethod("lshift", RubyKernel.IRUBY_OBJECT)); 98 fixnum.defineFastMethod(">>", callbackFactory.getFastMethod("rshift", RubyKernel.IRUBY_OBJECT)); 99 100 fixnum.defineFastMethod("to_f", callbackFactory.getFastMethod("to_f")); 101 fixnum.defineFastMethod("size", callbackFactory.getFastMethod("size")); 102 fixnum.defineFastMethod("zero?", callbackFactory.getFastMethod("zero_p")); 103 104 return fixnum; 105 } 106 107 private long value; 108 private static final int BIT_SIZE = 64; 109 private static final long SIGN_BIT = (1L << (BIT_SIZE - 1)); 110 public static final long MAX = (1L<<(BIT_SIZE - 1)) - 1; 111 public static final long MIN = -1 * MAX - 1; 112 public static final long MAX_MARSHAL_FIXNUM = (1L << 30) - 1; 113 114 public static final byte OP_PLUS_SWITCHVALUE = 1; 115 public static final byte OP_MINUS_SWITCHVALUE = 2; 116 public static final byte OP_LT_SWITCHVALUE = 3; 117 118 public RubyFixnum(Ruby runtime) { 119 this(runtime, 0); 120 } 121 122 public RubyFixnum(Ruby runtime, long value) { 123 super(runtime, runtime.getFixnum()); 124 this.value = value; 125 } 126 127 public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, byte switchvalue, String name, 128 IRubyObject[] args, CallType callType, Block block) { 129 switch (switchvalue) { 130 case OP_PLUS_SWITCHVALUE: 131 Arity.singleArgument().checkArity(context.getRuntime(), args); 132 return plus(args[0]); 133 case OP_MINUS_SWITCHVALUE: 134 Arity.singleArgument().checkArity(context.getRuntime(), args); 135 return minus(args[0]); 136 case OP_LT_SWITCHVALUE: 137 Arity.singleArgument().checkArity(context.getRuntime(), args); 138 return lt(args[0]); 139 case 0: 140 default: 141 return super.callMethod(context, rubyclass, name, args, callType, block); 142 } 143 } 144 public int getNativeTypeIndex() { 145 return ClassIndex.FIXNUM; 146 } 147 148 public boolean isImmediate() { 149 return true; 150 } 151 152 public Class getJavaClass() { 153 return Long.TYPE; 154 } 155 156 public double getDoubleValue() { 157 return value; 158 } 159 160 public long getLongValue() { 161 return value; 162 } 163 164 public static RubyFixnum newFixnum(Ruby runtime, long value) { 165 RubyFixnum fixnum; 166 RubyFixnum[] fixnumCache = runtime.getFixnumCache(); 167 168 if (value >= 0 && value < fixnumCache.length) { 169 fixnum = fixnumCache[(int) value]; 170 if (fixnum == null) { 171 fixnum = new RubyFixnum(runtime, value); 172 fixnumCache[(int) value] = fixnum; 173 } 174 } else { 175 fixnum = new RubyFixnum(runtime, value); 176 } 177 return fixnum; 178 } 179 180 public RubyFixnum newFixnum(long newValue) { 181 return newFixnum(getRuntime(), newValue); 182 } 183 184 public static RubyFixnum zero(Ruby runtime) { 185 return newFixnum(runtime, 0); 186 } 187 188 public static RubyFixnum one(Ruby runtime) { 189 return newFixnum(runtime, 1); 190 } 191 192 public static RubyFixnum minus_one(Ruby runtime) { 193 return newFixnum(runtime, -1); 194 } 195 196 public RubyFixnum hash() { 197 return newFixnum(hashCode()); 198 } 199 200 public int hashCode() { 201 return (int) value ^ (int) (value >> 32); 202 } 203 204 public boolean equals(Object other) { 205 if (other == this) { 206 return true; 207 } 208 209 if (other instanceof RubyFixnum) { 210 RubyFixnum num = (RubyFixnum)other; 211 212 if (num.value == value) { 213 return true; 214 } 215 } 216 217 return false; 218 } 219 220 224 225 228 public RubyString to_s(IRubyObject[] args) { 229 checkArgumentCount(args, 0, 1); 230 231 int base = args.length == 0 ? 10 : num2int(args[0]); 232 if (base < 2 || base > 36) { 233 throw getRuntime().newArgumentError("illegal radix " + base); 234 } 235 return getRuntime().newString(Convert.longToByteList(value, base)); 236 } 237 238 241 public IRubyObject id2name() { 242 String symbol = RubySymbol.getSymbol(getRuntime(), value); 243 if (symbol != null) { 244 return getRuntime().newString(symbol); 245 } 246 return getRuntime().getNil(); 247 } 248 249 252 public IRubyObject to_sym() { 253 String symbol = RubySymbol.getSymbol(getRuntime(), value); 254 if (symbol != null) { 255 return RubySymbol.newSymbol(getRuntime(), symbol); 256 } 257 return getRuntime().getNil(); 258 } 259 260 263 public IRubyObject uminus() { 264 if (value == MIN) { return RubyBignum.newBignum(getRuntime(), BigInteger.valueOf(value).negate()); 266 } 267 return RubyFixnum.newFixnum(getRuntime(), -value); 268 } 269 270 273 public IRubyObject plus(IRubyObject other) { 274 if (other instanceof RubyFixnum) { 275 long otherValue = ((RubyFixnum) other).value; 276 long result = value + otherValue; 277 if ((~(value ^ otherValue) & (value ^ result) & SIGN_BIT) != 0) { 278 return RubyBignum.newBignum(getRuntime(), value).plus(other); 279 } 280 return newFixnum(result); 281 } 282 if (other instanceof RubyBignum) { 283 return ((RubyBignum) other).plus(this); 284 } 285 if (other instanceof RubyFloat) { 286 return getRuntime().newFloat((double) value + ((RubyFloat) other).getDoubleValue()); 287 } 288 return coerceBin("+", other); 289 } 290 291 294 public IRubyObject minus(IRubyObject other) { 295 if (other instanceof RubyFixnum) { 296 long otherValue = ((RubyFixnum) other).value; 297 long result = value - otherValue; 298 if ((~(value ^ ~otherValue) & (value ^ result) & SIGN_BIT) != 0) { 299 return RubyBignum.newBignum(getRuntime(), value).minus(other); 300 } 301 return newFixnum(result); 302 } else if (other instanceof RubyBignum) { 303 return RubyBignum.newBignum(getRuntime(), value).minus(other); 304 } else if (other instanceof RubyFloat) { 305 return getRuntime().newFloat((double) value - ((RubyFloat) other).getDoubleValue()); 306 } 307 return coerceBin("-", other); 308 } 309 310 313 public IRubyObject mul(IRubyObject other) { 314 if (other instanceof RubyFixnum) { 315 long otherValue = ((RubyFixnum) other).value; 316 if (value == 0) { 317 return RubyFixnum.zero(getRuntime()); 318 } 319 long result = value * otherValue; 320 IRubyObject r = newFixnum(getRuntime(),result); 321 if(RubyNumeric.fix2long(r) != result || result/value != otherValue) { 322 return (RubyNumeric) RubyBignum.newBignum(getRuntime(), value).mul(other); 323 } 324 return r; 325 } else if (other instanceof RubyBignum) { 326 return ((RubyBignum) other).mul(this); 327 } else if (other instanceof RubyFloat) { 328 return getRuntime().newFloat((double) value * ((RubyFloat) other).getDoubleValue()); 329 } 330 return coerceBin("*", other); 331 } 332 333 343 public IRubyObject div_div(IRubyObject other) { 344 return idiv(other, "div"); 345 } 346 347 public IRubyObject div_slash(IRubyObject other) { 348 return idiv(other, "/"); 349 } 350 351 public IRubyObject idiv(IRubyObject other, String method) { 352 if (other instanceof RubyFixnum) { 353 long x = value; 354 long y = ((RubyFixnum) other).value; 355 356 if (y == 0) { 357 throw getRuntime().newZeroDivisionError(); 358 } 359 360 long div = x / y; 361 long mod = x % y; 362 363 if (mod < 0 && y > 0 || mod > 0 && y < 0) { 364 div -= 1; 365 } 366 367 return getRuntime().newFixnum(div); 368 } 369 return coerceBin(method, other); 370 } 371 372 375 public IRubyObject mod(IRubyObject other) { 376 if (other instanceof RubyFixnum) { 377 long x = value; 379 long y = ((RubyFixnum) other).value; 380 381 if (y == 0) { 382 throw getRuntime().newZeroDivisionError(); 383 } 384 385 long mod = x % y; 386 387 if (mod < 0 && y > 0 || mod > 0 && y < 0) { 388 mod += y; 389 } 390 391 return getRuntime().newFixnum(mod); 392 } 393 return coerceBin("%", other); 394 } 395 396 399 public IRubyObject divmod(IRubyObject other) { 400 if (other instanceof RubyFixnum) { 401 long x = value; 402 long y = ((RubyFixnum) other).value; 403 final Ruby runtime = getRuntime(); 404 405 if (y == 0) { 406 throw runtime.newZeroDivisionError(); 407 } 408 409 long div = x / y; 410 long mod = x % y; 411 412 if (mod < 0 && y > 0 || mod > 0 && y < 0) { 413 div -= 1; 414 mod += y; 415 } 416 417 IRubyObject fixDiv = RubyFixnum.newFixnum(getRuntime(), div); 418 IRubyObject fixMod = RubyFixnum.newFixnum(getRuntime(), mod); 419 420 return RubyArray.newArray(runtime, fixDiv, fixMod); 421 422 } 423 return coerceBin("divmod", other); 424 } 425 426 429 public IRubyObject quo(IRubyObject other) { 430 if (other instanceof RubyFixnum) { 431 return RubyFloat.newFloat(getRuntime(), (double) value 432 / (double) ((RubyFixnum) other).value); 433 } 434 return coerceBin("quo", other); 435 } 436 437 440 public IRubyObject pow(IRubyObject other) { 441 if(other instanceof RubyFixnum) { 442 long b = ((RubyFixnum) other).value; 443 if (b == 0) { 444 return RubyFixnum.one(getRuntime()); 445 } 446 if (b == 1) { 447 return this; 448 } 449 if (b > 0) { 450 return RubyBignum.newBignum(getRuntime(), value).pow(other); 451 } 452 return RubyFloat.newFloat(getRuntime(), Math.pow(value, b)); 453 } else if (other instanceof RubyFloat) { 454 return RubyFloat.newFloat(getRuntime(), Math.pow(value, ((RubyFloat) other) 455 .getDoubleValue())); 456 } 457 return coerceBin("**", other); 458 } 459 460 463 public IRubyObject abs() { 464 if (value < 0) { 465 return RubyFixnum.newFixnum(getRuntime(), -value); 466 } 467 return this; 468 } 469 470 473 public IRubyObject equal(IRubyObject other) { 474 if (other instanceof RubyFixnum) { 475 return RubyBoolean.newBoolean(getRuntime(), value == ((RubyFixnum) other).value); 476 } 477 return super.equal(other); 478 } 479 480 483 public IRubyObject cmp(IRubyObject other) { 484 if (other instanceof RubyFixnum) { 485 long otherValue = ((RubyFixnum) other).value; 486 if (value == otherValue) { 487 return RubyFixnum.zero(getRuntime()); 488 } 489 if (value > otherValue) { 490 return RubyFixnum.one(getRuntime()); 491 } 492 return RubyFixnum.minus_one(getRuntime()); 493 } 494 return coerceCmp("<=>", other); 495 } 496 497 500 public IRubyObject gt(IRubyObject other) { 501 if (other instanceof RubyFixnum) { 502 return RubyBoolean.newBoolean(getRuntime(), value > ((RubyFixnum) other).value); 503 } 504 return coerceRelOp(">", other); 505 } 506 507 510 public IRubyObject ge(IRubyObject other) { 511 if (other instanceof RubyFixnum) { 512 return RubyBoolean.newBoolean(getRuntime(), value >= ((RubyFixnum) other).value); 513 } 514 return coerceRelOp(">=", other); 515 } 516 517 520 public IRubyObject lt(IRubyObject other) { 521 if (other instanceof RubyFixnum) { 522 return RubyBoolean.newBoolean(getRuntime(), value < ((RubyFixnum) other).value); 523 } 524 return coerceRelOp("<", other); 525 } 526 527 530 public IRubyObject le(IRubyObject other) { 531 if (other instanceof RubyFixnum) { 532 return RubyBoolean.newBoolean(getRuntime(), value <= ((RubyFixnum) other).value); 533 } 534 return coerceRelOp("<=", other); 535 } 536 537 540 public IRubyObject rev() { 541 return newFixnum(~value); 542 } 543 544 547 public IRubyObject and(IRubyObject other) { 548 if (other instanceof RubyBignum) { 549 return ((RubyBignum) other).and(this); 550 } 551 return RubyFixnum.newFixnum(getRuntime(), value & num2long(other)); 552 } 553 554 557 public IRubyObject or(IRubyObject other) { 558 if (other instanceof RubyFixnum) { 559 return newFixnum(value | ((RubyFixnum) other).value); 560 } 561 if (other instanceof RubyBignum) { 562 return ((RubyBignum) other).or(this); 563 } 564 if (other instanceof RubyNumeric) { 565 return newFixnum(value | ((RubyNumeric) other).getLongValue()); 566 } 567 568 return or(RubyFixnum.newFixnum(getRuntime(), num2long(other))); 569 } 570 571 574 public IRubyObject xor(IRubyObject other) { 575 if(other instanceof RubyFixnum) { 576 return newFixnum(value ^ ((RubyFixnum) other).value); 577 } 578 if (other instanceof RubyBignum) { 579 return ((RubyBignum) other).xor(this); 580 } 581 if (other instanceof RubyNumeric) { 582 return newFixnum(value ^ ((RubyNumeric) other).getLongValue()); 583 } 584 585 return xor(RubyFixnum.newFixnum(getRuntime(), num2long(other))); 586 } 587 588 591 public IRubyObject aref(IRubyObject other) { 592 if(other instanceof RubyBignum) { 593 RubyBignum big = (RubyBignum) other; 594 RubyObject tryFix = RubyBignum.bignorm(getRuntime(), big.getValue()); 595 if (!(tryFix instanceof RubyFixnum)) { 596 if (big.getValue().signum() == 0 || value >= 0) { 597 return RubyFixnum.zero(getRuntime()); 598 } 599 return RubyFixnum.one(getRuntime()); 600 } 601 } 602 603 long otherValue = num2long(other); 604 605 if (otherValue < 0) { 606 return RubyFixnum.zero(getRuntime()); 607 } 608 609 if (BIT_SIZE - 1 < otherValue) { 610 if (value < 0) { 611 return RubyFixnum.one(getRuntime()); 612 } 613 return RubyFixnum.zero(getRuntime()); 614 } 615 616 return (value & (1L << otherValue)) == 0 ? RubyFixnum.zero(getRuntime()) : RubyFixnum.one(getRuntime()); 617 } 618 619 622 public IRubyObject lshift(IRubyObject other) { 623 long width = num2long(other); 624 625 if (width < 0) { 626 return rshift(RubyFixnum.newFixnum(getRuntime(), -width)); 627 } 628 629 if (width == 0) { 630 return this; 631 } 632 633 if (width > BIT_SIZE - 1 || ((~0L << BIT_SIZE - width - 1) & value) != 0) { 634 return RubyBignum.newBignum(getRuntime(), value).lshift(other); 635 } 636 637 return newFixnum(value << width); 638 } 639 640 643 public IRubyObject rshift(IRubyObject other) { 644 long width = num2long(other); 645 646 if (width < 0) { 647 return lshift(RubyFixnum.newFixnum(getRuntime(), -width)); 648 } 649 650 if (width == 0) { 651 return this; 652 } 653 654 if (width >= BIT_SIZE - 1) { 655 if (value < 0) { 656 return RubyFixnum.minus_one(getRuntime()); 657 } 658 return RubyFixnum.zero(getRuntime()); 659 } 660 661 return newFixnum(value >> width); 662 } 663 664 667 public IRubyObject to_f() { 668 return RubyFloat.newFloat(getRuntime(), (double) value); 669 } 670 671 674 public IRubyObject size() { 675 return newFixnum((long) ((BIT_SIZE + 7) / 8)); 676 } 677 678 681 public IRubyObject zero_p() { 682 return RubyBoolean.newBoolean(getRuntime(), value == 0); 683 } 684 685 public RubyFixnum id() { 686 return newFixnum(value * 2 + 1); 687 } 688 689 public IRubyObject taint() { 690 return this; 691 } 692 693 public IRubyObject freeze() { 694 return this; 695 } 696 697 public static RubyFixnum unmarshalFrom(UnmarshalStream input) throws java.io.IOException { 698 return input.getRuntime().newFixnum(input.unmarshalInt()); 699 } 700 701 705 706 709 710 public static IRubyObject induced_from(IRubyObject recv, IRubyObject other) { 711 return RubyNumeric.num2fix(other); 712 } 713 } 714 | Popular Tags |