1 37 package org.jruby; 38 39 import java.lang.reflect.Array ; 40 import java.io.IOException ; 41 import java.util.Arrays ; 42 import java.util.Collection ; 43 import java.util.Comparator ; 44 import java.util.HashSet ; 45 import java.util.Iterator ; 46 import java.util.List ; 47 import java.util.ListIterator ; 48 import java.util.Set ; 49 import org.jruby.javasupport.JavaUtil; 50 import org.jruby.runtime.Arity; 51 import org.jruby.runtime.Block; 52 import org.jruby.runtime.CallType; 53 import org.jruby.runtime.CallbackFactory; 54 import org.jruby.runtime.ClassIndex; 55 import org.jruby.runtime.ObjectAllocator; 56 import org.jruby.runtime.ThreadContext; 57 import org.jruby.runtime.builtin.IRubyObject; 58 import org.jruby.runtime.marshal.MarshalStream; 59 import org.jruby.runtime.marshal.UnmarshalStream; 60 import org.jruby.util.Pack; 61 62 65 public class RubyArray extends RubyObject implements List { 66 67 public static RubyClass createArrayClass(Ruby runtime) { 68 RubyClass arrayc = runtime.defineClass("Array", runtime.getObject(), ARRAY_ALLOCATOR); 69 arrayc.index = ClassIndex.ARRAY; 70 CallbackFactory callbackFactory = runtime.callbackFactory(RubyArray.class); 71 72 arrayc.includeModule(runtime.getModule("Enumerable")); 73 arrayc.getMetaClass().defineMethod("[]", callbackFactory.getOptSingletonMethod("create")); 74 75 arrayc.defineMethod("initialize", callbackFactory.getOptMethod("initialize")); 76 arrayc.defineFastMethod("initialize_copy", callbackFactory.getFastMethod("replace", RubyKernel.IRUBY_OBJECT)); 77 arrayc.defineFastMethod("to_s", callbackFactory.getFastMethod("to_s")); 78 arrayc.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect")); 79 arrayc.defineFastMethod("to_a", callbackFactory.getFastMethod("to_a")); 80 arrayc.defineFastMethod("to_ary", callbackFactory.getFastMethod("to_ary")); 81 arrayc.defineFastMethod("frozen?", callbackFactory.getFastMethod("frozen")); 82 83 arrayc.defineFastMethod("==", callbackFactory.getFastMethod("op_equal", RubyKernel.IRUBY_OBJECT)); 84 arrayc.defineFastMethod("eql?", callbackFactory.getFastMethod("eql", RubyKernel.IRUBY_OBJECT)); 85 arrayc.defineFastMethod("hash", callbackFactory.getFastMethod("hash")); 86 87 arrayc.defineFastMethod("[]", callbackFactory.getFastOptMethod("aref")); 88 arrayc.defineFastMethod("[]=", callbackFactory.getFastOptMethod("aset")); 89 arrayc.defineFastMethod("at", callbackFactory.getFastMethod("at", RubyKernel.IRUBY_OBJECT)); 90 arrayc.defineMethod("fetch", callbackFactory.getOptMethod("fetch")); 91 arrayc.defineFastMethod("first", callbackFactory.getFastOptMethod("first")); 92 arrayc.defineFastMethod("last", callbackFactory.getFastOptMethod("last")); 93 arrayc.defineFastMethod("concat", callbackFactory.getFastMethod("concat", RubyKernel.IRUBY_OBJECT)); 94 arrayc.defineFastMethod("<<", callbackFactory.getFastMethod("append", RubyKernel.IRUBY_OBJECT)); 95 arrayc.defineFastMethod("push", callbackFactory.getFastOptMethod("push_m")); 96 arrayc.defineFastMethod("pop", callbackFactory.getFastMethod("pop")); 97 arrayc.defineFastMethod("shift", callbackFactory.getFastMethod("shift")); 98 arrayc.defineFastMethod("unshift", callbackFactory.getFastOptMethod("unshift_m")); 99 arrayc.defineFastMethod("insert", callbackFactory.getFastOptMethod("insert")); 100 arrayc.defineMethod("each", callbackFactory.getMethod("each")); 101 arrayc.defineMethod("each_index", callbackFactory.getMethod("each_index")); 102 arrayc.defineMethod("reverse_each", callbackFactory.getMethod("reverse_each")); 103 arrayc.defineFastMethod("length", callbackFactory.getFastMethod("length")); 104 arrayc.defineAlias("size", "length"); 105 arrayc.defineFastMethod("empty?", callbackFactory.getFastMethod("empty_p")); 106 arrayc.defineFastMethod("index", callbackFactory.getFastMethod("index", RubyKernel.IRUBY_OBJECT)); 107 arrayc.defineFastMethod("rindex", callbackFactory.getFastMethod("rindex", RubyKernel.IRUBY_OBJECT)); 108 arrayc.defineFastMethod("indexes", callbackFactory.getFastOptMethod("indexes")); 109 arrayc.defineFastMethod("indices", callbackFactory.getFastOptMethod("indexes")); 110 arrayc.defineFastMethod("join", callbackFactory.getFastOptMethod("join_m")); 111 arrayc.defineFastMethod("reverse", callbackFactory.getFastMethod("reverse")); 112 arrayc.defineFastMethod("reverse!", callbackFactory.getFastMethod("reverse_bang")); 113 arrayc.defineMethod("sort", callbackFactory.getMethod("sort")); 114 arrayc.defineMethod("sort!", callbackFactory.getMethod("sort_bang")); 115 arrayc.defineMethod("collect", callbackFactory.getMethod("collect")); 116 arrayc.defineMethod("collect!", callbackFactory.getMethod("collect_bang")); 117 arrayc.defineMethod("map", callbackFactory.getMethod("collect")); 118 arrayc.defineMethod("map!", callbackFactory.getMethod("collect_bang")); 119 arrayc.defineMethod("select", callbackFactory.getMethod("select")); 120 arrayc.defineFastMethod("values_at", callbackFactory.getFastOptMethod("values_at")); 121 arrayc.defineMethod("delete", callbackFactory.getMethod("delete", RubyKernel.IRUBY_OBJECT)); 122 arrayc.defineFastMethod("delete_at", callbackFactory.getFastMethod("delete_at", RubyKernel.IRUBY_OBJECT)); 123 arrayc.defineMethod("delete_if", callbackFactory.getMethod("delete_if")); 124 arrayc.defineMethod("reject", callbackFactory.getMethod("reject")); 125 arrayc.defineMethod("reject!", callbackFactory.getMethod("reject_bang")); 126 arrayc.defineMethod("zip", callbackFactory.getOptMethod("zip")); 127 arrayc.defineFastMethod("transpose", callbackFactory.getFastMethod("transpose")); 128 arrayc.defineFastMethod("replace", callbackFactory.getFastMethod("replace", RubyKernel.IRUBY_OBJECT)); 129 arrayc.defineFastMethod("clear", callbackFactory.getFastMethod("rb_clear")); 130 arrayc.defineMethod("fill", callbackFactory.getOptMethod("fill")); 131 arrayc.defineFastMethod("include?", callbackFactory.getFastMethod("include_p", RubyKernel.IRUBY_OBJECT)); 132 arrayc.defineFastMethod("<=>", callbackFactory.getFastMethod("op_cmp", RubyKernel.IRUBY_OBJECT)); 133 134 arrayc.defineFastMethod("slice", callbackFactory.getFastOptMethod("aref")); 135 arrayc.defineFastMethod("slice!", callbackFactory.getFastOptMethod("slice_bang")); 136 137 arrayc.defineFastMethod("assoc", callbackFactory.getFastMethod("assoc", RubyKernel.IRUBY_OBJECT)); 138 arrayc.defineFastMethod("rassoc", callbackFactory.getFastMethod("rassoc", RubyKernel.IRUBY_OBJECT)); 139 140 arrayc.defineFastMethod("+", callbackFactory.getFastMethod("op_plus", RubyKernel.IRUBY_OBJECT)); 141 arrayc.defineFastMethod("*", callbackFactory.getFastMethod("op_times", RubyKernel.IRUBY_OBJECT)); 142 143 arrayc.defineFastMethod("-", callbackFactory.getFastMethod("op_diff", RubyKernel.IRUBY_OBJECT)); 144 arrayc.defineFastMethod("&", callbackFactory.getFastMethod("op_and", RubyKernel.IRUBY_OBJECT)); 145 arrayc.defineFastMethod("|", callbackFactory.getFastMethod("op_or", RubyKernel.IRUBY_OBJECT)); 146 147 arrayc.defineFastMethod("uniq", callbackFactory.getFastMethod("uniq")); 148 arrayc.defineFastMethod("uniq!", callbackFactory.getFastMethod("uniq_bang")); 149 arrayc.defineFastMethod("compact", callbackFactory.getFastMethod("compact")); 150 arrayc.defineFastMethod("compact!", callbackFactory.getFastMethod("compact_bang")); 151 152 arrayc.defineFastMethod("flatten", callbackFactory.getFastMethod("flatten")); 153 arrayc.defineFastMethod("flatten!", callbackFactory.getFastMethod("flatten_bang")); 154 155 arrayc.defineFastMethod("nitems", callbackFactory.getFastMethod("nitems")); 156 157 arrayc.defineFastMethod("pack", callbackFactory.getFastMethod("pack", RubyKernel.IRUBY_OBJECT)); 158 159 return arrayc; 160 } 161 162 private static ObjectAllocator ARRAY_ALLOCATOR = new ObjectAllocator() { 163 public IRubyObject allocate(Ruby runtime, RubyClass klass) { 164 return new RubyArray(runtime, klass); 165 } 166 }; 167 168 public static final byte OP_PLUS_SWITCHVALUE = 1; 169 public static final byte AREF_SWITCHVALUE = 2; 170 public static final byte ASET_SWITCHVALUE = 3; 171 public static final byte POP_SWITCHVALUE = 4; 172 public static final byte PUSH_SWITCHVALUE = 5; 173 public static final byte NIL_P_SWITCHVALUE = 6; 174 public static final byte EQUALEQUAL_SWITCHVALUE = 7; 175 public static final byte UNSHIFT_SWITCHVALUE = 8; 176 public static final byte OP_LSHIFT_SWITCHVALUE = 9; 177 public static final byte EMPTY_P_SWITCHVALUE = 10; 178 179 public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, byte switchvalue, 180 String name, IRubyObject[] args, CallType callType, Block block) { 181 switch (switchvalue) { 182 case OP_PLUS_SWITCHVALUE: 183 Arity.singleArgument().checkArity(context.getRuntime(), args); 184 return op_plus(args[0]); 185 case AREF_SWITCHVALUE: 186 Arity.optional().checkArity(context.getRuntime(), args); 187 return aref(args); 188 case ASET_SWITCHVALUE: 189 Arity.optional().checkArity(context.getRuntime(), args); 190 return aset(args); 191 case POP_SWITCHVALUE: 192 Arity.noArguments().checkArity(context.getRuntime(), args); 193 return pop(); 194 case PUSH_SWITCHVALUE: 195 Arity.optional().checkArity(context.getRuntime(), args); 196 return push_m(args); 197 case NIL_P_SWITCHVALUE: 198 Arity.noArguments().checkArity(context.getRuntime(), args); 199 return nil_p(); 200 case EQUALEQUAL_SWITCHVALUE: 201 Arity.singleArgument().checkArity(context.getRuntime(), args); 202 return op_equal(args[0]); 203 case UNSHIFT_SWITCHVALUE: 204 Arity.optional().checkArity(context.getRuntime(), args); 205 return unshift_m(args); 206 case OP_LSHIFT_SWITCHVALUE: 207 Arity.singleArgument().checkArity(context.getRuntime(), args); 208 return append(args[0]); 209 case EMPTY_P_SWITCHVALUE: 210 Arity.noArguments().checkArity(context.getRuntime(), args); 211 return empty_p(); 212 case 0: 213 default: 214 return super.callMethod(context, rubyclass, name, args, callType, block); 215 } 216 } 217 218 221 public static IRubyObject create(IRubyObject klass, IRubyObject[] args, Block block) { 222 RubyArray arr = (RubyArray) ((RubyClass) klass).allocate(); 223 arr.callInit(IRubyObject.NULL_ARRAY, block); 224 225 if (args.length > 0) { 226 arr.alloc(args.length); 227 System.arraycopy(args, 0, arr.values, 0, args.length); 228 arr.realLength = args.length; 229 } 230 return arr; 231 } 232 233 236 public static final RubyArray newArray(final Ruby runtime, final long len) { 237 return new RubyArray(runtime, len); 238 } 239 240 243 public static final RubyArray newArray(final Ruby runtime) { 244 return new RubyArray(runtime, ARRAY_DEFAULT_SIZE); 245 } 246 247 250 public static final RubyArray newArrayLight(final Ruby runtime) { 251 254 RubyArray arr = new RubyArray(runtime, false); 255 arr.alloc(ARRAY_DEFAULT_SIZE); 256 return arr; 257 } 258 259 public static RubyArray newArray(Ruby runtime, IRubyObject obj) { 260 return new RubyArray(runtime, new IRubyObject[] { obj }); 261 } 262 263 266 public static RubyArray newArray(Ruby runtime, IRubyObject car, IRubyObject cdr) { 267 return new RubyArray(runtime, new IRubyObject[] { car, cdr }); 268 } 269 270 273 public static RubyArray newArray(Ruby runtime, IRubyObject[] args) { 274 RubyArray arr = new RubyArray(runtime, args.length); 275 System.arraycopy(args, 0, arr.values, 0, args.length); 276 arr.realLength = args.length; 277 return arr; 278 } 279 280 public static RubyArray newArrayNoCopy(Ruby runtime, IRubyObject[] args) { 281 return new RubyArray(runtime, args); 282 } 283 284 public static RubyArray newArray(Ruby runtime, Collection collection) { 285 RubyArray arr = new RubyArray(runtime, collection.size()); 286 collection.toArray(arr.values); 287 arr.realLength = arr.values.length; 288 return arr; 289 } 290 291 public static final int ARRAY_DEFAULT_SIZE = 16; 292 293 private IRubyObject[] values; 294 private boolean tmpLock = false; 295 private boolean shared = false; 296 297 private int begin = 0; 298 private int realLength = 0; 299 300 303 public RubyArray(Ruby runtime, IRubyObject[]vals){ 304 super(runtime, runtime.getArray()); 305 values = vals; 306 realLength = vals.length; 307 } 308 309 312 private RubyArray(Ruby runtime, long length) { 313 super(runtime, runtime.getArray()); 314 checkLength(length); 315 alloc((int) length); 316 } 317 318 321 public RubyArray(Ruby runtime, long length, IRubyObject[] vals) { 322 super(runtime, runtime.getArray()); 323 checkLength(length); 324 int ilength = (int) length; 325 alloc(ilength); 326 if (ilength > 0 && vals.length > 0) System.arraycopy(vals, 0, values, 0, ilength); 327 328 realLength = ilength; 329 } 330 331 334 private RubyArray(Ruby runtime, long length, boolean objectSpace) { 335 super(runtime, runtime.getArray(), objectSpace); 336 checkLength(length); 337 alloc((int) length); 338 } 339 340 343 private RubyArray(Ruby runtime, final RubyArray original){ 344 super(runtime, runtime.getArray()); 345 realLength = original.realLength; 346 alloc(realLength); 347 System.arraycopy(original.values, original.begin, values, 0, realLength); 348 } 349 350 353 private RubyArray(Ruby runtime, boolean objectSpace) { 354 super(runtime, runtime.getArray(), objectSpace); 355 } 356 357 private RubyArray(Ruby runtime) { 358 super(runtime, runtime.getArray()); 359 alloc(ARRAY_DEFAULT_SIZE); 360 } 361 362 public RubyArray(Ruby runtime, RubyClass klass) { 363 super(runtime, klass); 364 alloc(ARRAY_DEFAULT_SIZE); 365 } 366 367 private final IRubyObject[] reserve(int length) { 368 return new IRubyObject[length]; 369 } 370 371 private final void alloc(int length) { 372 values = new IRubyObject[length]; 373 } 374 375 private final void realloc(int newLength) { 376 IRubyObject[] reallocated = new IRubyObject[newLength]; 377 System.arraycopy(values, 0, reallocated, 0, newLength > realLength ? realLength : newLength); 378 values = reallocated; 379 } 380 381 private final void checkLength(long length) { 382 if (length < 0) { 383 throw getRuntime().newArgumentError("negative array size (or size too big)"); 384 } 385 386 if (length >= Integer.MAX_VALUE) { 387 throw getRuntime().newArgumentError("array size too big"); 388 } 389 } 390 391 public int getNativeTypeIndex() { 392 return ClassIndex.ARRAY; 393 } 394 395 398 public List getList() { 399 return Arrays.asList(toJavaArray()); 400 } 401 402 public int getLength() { 403 return realLength; 404 } 405 406 public IRubyObject[] toJavaArray() { 407 IRubyObject[] copy = reserve(realLength); 408 System.arraycopy(values, begin, copy, 0, realLength); 409 return copy; 410 } 411 412 public IRubyObject[] toJavaArrayUnsafe() { 413 return !shared ? values : toJavaArray(); 414 } 415 416 public IRubyObject[] toJavaArrayMaybeUnsafe() { 417 return (!shared && begin == 0 && values.length == realLength) ? values : toJavaArray(); 418 } 419 420 423 private final RubyArray makeShared(int beg, int len){ 424 RubyArray sharedArray = new RubyArray(getRuntime(), true); 425 shared = true; 426 sharedArray.values = values; 427 sharedArray.shared = true; 428 sharedArray.begin = beg; 429 sharedArray.realLength = len; 430 return sharedArray; 431 } 432 433 436 private final void modifyCheck() { 437 testFrozen("array"); 438 439 if (tmpLock) { 440 throw getRuntime().newTypeError("can't modify array during iteration"); 441 } 442 if (!isTaint() && getRuntime().getSafeLevel() >= 4) { 443 throw getRuntime().newSecurityError("Insecure: can't modify array"); 444 } 445 } 446 447 450 private final void modify() { 451 modifyCheck(); 452 if (shared) { 453 IRubyObject[] vals = reserve(realLength); 454 shared = false; 455 System.arraycopy(values, begin, vals, 0, realLength); 456 begin = 0; 457 values = vals; 458 } 459 } 460 461 465 466 469 public IRubyObject initialize(IRubyObject[] args, Block block) { 470 int argc = checkArgumentCount(args, 0, 2); 471 Ruby runtime = getRuntime(); 472 473 if (argc == 0) { 474 realLength = 0; 475 if (block.isGiven()) runtime.getWarnings().warn("given block not used"); 476 477 return this; 478 } 479 480 if (argc == 1 && !(args[0] instanceof RubyFixnum)) { 481 IRubyObject val = args[0].checkArrayType(); 482 if (!val.isNil()) { 483 replace(val); 484 return this; 485 } 486 } 487 488 long len = RubyNumeric.num2long(args[0]); 489 490 if (len < 0) throw runtime.newArgumentError("negative array size"); 491 492 if (len >= Integer.MAX_VALUE) throw runtime.newArgumentError("array size too big"); 493 494 int ilen = (int) len; 495 496 modify(); 497 498 if (ilen > values.length) values = reserve(ilen); 499 500 if (block.isGiven()) { 501 if (argc == 2) { 502 runtime.getWarnings().warn("block supersedes default value argument"); 503 } 504 505 ThreadContext context = runtime.getCurrentContext(); 506 for (int i = 0; i < ilen; i++) { 507 store(i, context.yield(new RubyFixnum(runtime, i), block)); 508 realLength = i + 1; 509 } 510 } else { 511 Arrays.fill(values, 0, ilen, (argc == 2) ? args[1] : runtime.getNil()); 512 realLength = ilen; 513 } 514 return this; 515 } 516 517 520 public IRubyObject replace(IRubyObject orig) { 521 modifyCheck(); 522 523 RubyArray origArr = orig.convertToArray(); 524 525 if (this == orig) return this; 526 527 origArr.shared = true; 528 values = origArr.values; 529 realLength = origArr.realLength; 530 begin = origArr.begin; 531 shared = true; 532 533 return this; 534 } 535 536 539 public IRubyObject to_s() { 540 if (realLength == 0) return getRuntime().newString(""); 541 542 return join(getRuntime().getGlobalVariables().get("$,")); 543 } 544 545 public boolean includes(IRubyObject item) { 546 final ThreadContext context = getRuntime().getCurrentContext(); 547 int begin = this.begin; 548 549 for (int i = begin; i < begin + realLength; i++) { 550 if (item.equalInternal(context, values[i]).isTrue()) return true; 551 } 552 553 return false; 554 } 555 556 559 public RubyFixnum hash() { 560 int h = realLength; 561 562 Ruby runtime = getRuntime(); 563 ThreadContext context = runtime.getCurrentContext(); 564 int begin = this.begin; 565 for (int i = begin; i < begin + realLength; i++) { 566 h = (h << 1) | (h < 0 ? 1 : 0); 567 h ^= RubyNumeric.num2long(values[i].callMethod(context, "hash")); 568 } 569 570 return runtime.newFixnum(h); 571 } 572 573 576 private final IRubyObject store(long index, IRubyObject value) { 577 if (index < 0) { 578 index += realLength; 579 if (index < 0) { 580 throw getRuntime().newIndexError("index " + (index - realLength) + " out of array"); 581 } 582 } 583 584 modify(); 585 586 if (index >= realLength) { 587 if (index >= values.length) { 588 long newLength = values.length >> 1; 589 590 if (newLength < ARRAY_DEFAULT_SIZE) newLength = ARRAY_DEFAULT_SIZE; 591 592 newLength += index; 593 if (newLength >= Integer.MAX_VALUE) { 594 throw getRuntime().newArgumentError("index too big"); 595 } 596 realloc((int) newLength); 597 } 598 if(index != realLength) Arrays.fill(values, realLength, (int) index + 1, getRuntime().getNil()); 599 600 realLength = (int) index + 1; 601 } 602 603 values[(int) index] = value; 604 return value; 605 } 606 607 610 private final IRubyObject elt(long offset) { 611 if (realLength == 0 || offset < 0 || offset >= realLength) return getRuntime().getNil(); 612 613 return values[begin + (int) offset]; 614 } 615 616 619 private final IRubyObject elt(int offset) { 620 if (realLength == 0 || offset < 0 || offset >= realLength) return getRuntime().getNil(); 621 622 return values[begin + offset]; 623 } 624 625 628 private final IRubyObject elt_f(long offset) { 629 if (realLength == 0 || offset >= realLength) return getRuntime().getNil(); 630 631 return values[begin + (int) offset]; 632 } 633 634 637 private final IRubyObject elt_f(int offset) { 638 if (realLength == 0 || offset >= realLength) return getRuntime().getNil(); 639 640 return values[begin + offset]; 641 } 642 643 646 public final IRubyObject entry(long offset) { 647 return (offset < 0 ) ? elt(offset + realLength) : elt_f(offset); 648 } 649 650 651 654 public final IRubyObject entry(int offset) { 655 return (offset < 0 ) ? elt(offset + realLength) : elt_f(offset); 656 } 657 658 public final IRubyObject eltInternal(int offset) { 659 return values[begin + offset]; 660 } 661 662 665 public IRubyObject fetch(IRubyObject[] args, Block block) { 666 if (checkArgumentCount(args, 1, 2) == 2 && block.isGiven()) { 667 getRuntime().getWarnings().warn("block supersedes default value argument"); 668 } 669 670 long index = RubyNumeric.num2long(args[0]); 671 672 if (index < 0) index += realLength; 673 674 if (index < 0 || index >= realLength) { 675 if (block.isGiven()) return getRuntime().getCurrentContext().yield(args[0], block); 676 677 if (args.length == 1) { 678 throw getRuntime().newIndexError("index " + index + " out of array"); 679 } 680 681 return args[1]; 682 } 683 684 return values[begin + (int) index]; 685 } 686 687 690 private static RubyArray aryToAry(IRubyObject obj) { 691 if (obj instanceof RubyArray) return (RubyArray) obj; 692 693 if (obj.respondsTo("to_ary")) return obj.convertToArray(); 694 695 RubyArray arr = new RubyArray(obj.getRuntime(), false); arr.alloc(1); 697 arr.values[0] = obj; 698 arr.realLength = 1; 699 return arr; 700 } 701 702 705 private final void splice(long beg, long len, IRubyObject rpl) { 706 int rlen; 707 708 if (len < 0) throw getRuntime().newIndexError("negative length (" + len + ")"); 709 710 if (beg < 0) { 711 beg += realLength; 712 if (beg < 0) { 713 beg -= realLength; 714 throw getRuntime().newIndexError("index " + beg + " out of array"); 715 } 716 } 717 718 if (beg + len > realLength) len = realLength - beg; 719 720 RubyArray rplArr; 721 if (rpl == null || rpl.isNil()) { 722 rplArr = null; 723 rlen = 0; 724 } else { 725 rplArr = aryToAry(rpl); 726 rlen = rplArr.realLength; 727 } 728 729 modify(); 730 731 if (beg >= realLength) { 732 len = beg + rlen; 733 734 if (len >= values.length) { 735 int tryNewLength = values.length + (values.length >> 1); 736 737 realloc(len > tryNewLength ? (int)len : tryNewLength); 738 } 739 740 Arrays.fill(values, realLength, (int) beg, getRuntime().getNil()); 741 if (rlen > 0) { 742 System.arraycopy(rplArr.values, rplArr.begin, values, (int) beg, rlen); 743 } 744 realLength = (int) len; 745 } else { 746 long alen; 747 748 if (beg + len > realLength) len = realLength - beg; 749 750 alen = realLength + rlen - len; 751 if (alen >= values.length) { 752 int tryNewLength = values.length + (values.length >> 1); 753 754 realloc(alen > tryNewLength ? (int)alen : tryNewLength); 755 } 756 757 if (len != rlen) { 758 System.arraycopy(values, (int) (beg + len), values, (int) beg + rlen, realLength - (int) (beg + len)); 759 realLength = (int) alen; 760 } 761 762 if (rlen > 0) { 763 System.arraycopy(rplArr.values, rplArr.begin, values, (int) beg, rlen); 764 } 765 } 766 } 767 768 771 public IRubyObject insert(IRubyObject[] args) { 772 if (args.length == 1) return this; 773 774 if (args.length < 1) { 775 throw getRuntime().newArgumentError("wrong number of arguments (at least 1)"); 776 } 777 778 long pos = RubyNumeric.num2long(args[0]); 779 780 if (pos == -1) pos = realLength; 781 if (pos < 0) pos++; 782 783 RubyArray inserted = new RubyArray(getRuntime(), false); 784 inserted.values = args; 785 inserted.begin = 1; 786 inserted.realLength = args.length - 1; 787 788 splice(pos, 0, inserted); 790 return this; 791 } 792 793 public final IRubyObject dup() { 794 return aryDup(); 795 } 796 797 800 private final RubyArray aryDup() { 801 RubyArray dup = new RubyArray(getRuntime(), this); 802 dup.setTaint(isTaint()); return dup; 805 } 806 807 810 public RubyArray transpose() { 811 RubyArray tmp, result = null; 812 813 int alen = realLength; 814 if (alen == 0) return aryDup(); 815 816 Ruby runtime = getRuntime(); 817 int elen = -1; 818 int end = begin + alen; 819 for (int i = begin; i < end; i++) { 820 tmp = elt(i).convertToArray(); 821 if (elen < 0) { 822 elen = tmp.realLength; 823 result = new RubyArray(runtime, elen); 824 for (int j = 0; j < elen; j++) { 825 result.store(j, new RubyArray(runtime, alen)); 826 } 827 } else if (elen != tmp.realLength) { 828 throw runtime.newIndexError("element size differs (" + tmp.realLength 829 + " should be " + elen + ")"); 830 } 831 for (int j = 0; j < elen; j++) { 832 ((RubyArray) result.elt(j)).store(i - begin, tmp.elt(j)); 833 } 834 } 835 return result; 836 } 837 838 841 private final IRubyObject values_at(long olen, IRubyObject[] args) { 842 RubyArray result = new RubyArray(getRuntime(), args.length); 843 844 for (int i = 0; i < args.length; i++) { 845 if (args[i] instanceof RubyFixnum) { 846 result.append(entry(((RubyFixnum)args[i]).getLongValue())); 847 continue; 848 } 849 850 long beglen[]; 851 if (!(args[i] instanceof RubyRange)) { 852 } else if ((beglen = ((RubyRange) args[i]).begLen(olen, 0)) == null) { 853 continue; 854 } else { 855 int beg = (int) beglen[0]; 856 int len = (int) beglen[1]; 857 int end = begin + len; 858 for (int j = begin; j < end; j++) { 859 result.append(entry(j + beg)); 860 } 861 continue; 862 } 863 result.append(entry(RubyNumeric.num2long(args[i]))); 864 } 865 866 return result; 867 } 868 869 872 public IRubyObject values_at(IRubyObject[] args) { 873 return values_at(realLength, args); 874 } 875 876 879 public IRubyObject subseq(long beg, long len) { 880 if (beg > realLength || beg < 0 || len < 0) return getRuntime().getNil(); 881 882 if (beg + len > realLength) { 883 len = realLength - beg; 884 885 if (len < 0) len = 0; 886 } 887 888 if (len == 0) return new RubyArray(getRuntime(), 0); 890 891 return makeShared(begin + (int) beg, (int) len); 892 } 893 894 897 public RubyFixnum length() { 898 return getRuntime().newFixnum(realLength); 899 } 900 901 904 public RubyArray append(IRubyObject item) { 905 modify(); 906 907 if (realLength == values.length) { 908 if (realLength == Integer.MAX_VALUE) throw getRuntime().newArgumentError("index too big"); 909 910 long newLength = values.length + (values.length >> 1); 911 if ( newLength > Integer.MAX_VALUE ) { 912 newLength = Integer.MAX_VALUE; 913 }else if ( newLength < ARRAY_DEFAULT_SIZE ) { 914 newLength = ARRAY_DEFAULT_SIZE; 915 } 916 917 realloc((int) newLength); 918 } 919 920 values[realLength++] = item; 921 return this; 922 } 923 924 927 public RubyArray push_m(IRubyObject[] items) { 928 for (int i = 0; i < items.length; i++) { 929 append(items[i]); 930 } 931 932 return this; 933 } 934 935 938 public IRubyObject pop() { 939 modifyCheck(); 940 941 if (realLength == 0) return getRuntime().getNil(); 942 943 if (!shared) { 944 int index = begin + --realLength; 945 IRubyObject obj = values[index]; 946 values[index] = null; 947 return obj; 948 } 949 950 return values[begin + --realLength]; 951 } 952 953 956 public IRubyObject shift() { 957 modifyCheck(); 958 959 if (realLength == 0) return getRuntime().getNil(); 960 961 IRubyObject obj = values[begin]; 962 963 if (!shared) shared = true; 964 965 begin++; 966 realLength--; 967 968 return obj; 969 } 970 971 974 public RubyArray unshift(IRubyObject item) { 975 modify(); 976 977 if (realLength == values.length) { 978 int newLength = values.length >> 1; 979 if (newLength < ARRAY_DEFAULT_SIZE) newLength = ARRAY_DEFAULT_SIZE; 980 981 newLength += values.length; 982 realloc(newLength); 983 } 984 System.arraycopy(values, 0, values, 1, realLength); 985 986 realLength++; 987 values[0] = item; 988 989 return this; 990 } 991 992 995 public RubyArray unshift_m(IRubyObject[] items) { 996 long len = realLength; 997 998 if (items.length == 0) return this; 999 1000 store(len + items.length - 1, getRuntime().getNil()); 1001 1002 System.arraycopy(values, 0, values, items.length, (int) len); 1004 System.arraycopy(items, 0, values, 0, items.length); 1005 1006 return this; 1007 } 1008 1009 1012 public RubyBoolean include_p(IRubyObject item) { 1013 return getRuntime().newBoolean(includes(item)); 1014 } 1015 1016 1019 public RubyBoolean frozen() { 1020 return getRuntime().newBoolean(isFrozen() || tmpLock); 1021 } 1022 1023 1025 public IRubyObject aref(IRubyObject[] args) { 1026 long beg, len; 1027 if (args.length == 2) { 1028 if (args[0] instanceof RubySymbol) { 1029 throw getRuntime().newTypeError("Symbol as array index"); 1030 } 1031 beg = RubyNumeric.num2long(args[0]); 1032 len = RubyNumeric.num2long(args[1]); 1033 1034 if (beg < 0) beg += realLength; 1035 1036 return subseq(beg, len); 1037 } 1038 1039 if (args.length != 1) checkArgumentCount(args, 1, 2); 1040 1041 IRubyObject arg = args[0]; 1042 1043 if (arg instanceof RubyFixnum) return entry(((RubyFixnum)arg).getLongValue()); 1044 if (arg instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index"); 1045 1046 long[] beglen; 1047 if (!(arg instanceof RubyRange)) { 1048 } else if ((beglen = ((RubyRange) arg).begLen(realLength, 0)) == null) { 1049 return getRuntime().getNil(); 1050 } else { 1051 beg = beglen[0]; 1052 len = beglen[1]; 1053 return subseq(beg, len); 1054 } 1055 1056 return entry(RubyNumeric.num2long(arg)); 1057 } 1058 1059 1062 public IRubyObject aset(IRubyObject[] args) { 1063 if (args.length == 2) { 1064 if (args[0] instanceof RubyFixnum) { 1065 store(((RubyFixnum)args[0]).getLongValue(), args[1]); 1066 return args[1]; 1067 } 1068 if (args[0] instanceof RubyRange) { 1069 long[] beglen = ((RubyRange) args[0]).begLen(realLength, 1); 1070 splice(beglen[0], beglen[1], args[1]); 1071 return args[1]; 1072 } 1073 if (args[0] instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index"); 1074 1075 store(RubyNumeric.num2long(args[0]), args[1]); 1076 return args[1]; 1077 } 1078 1079 if (args.length == 3) { 1080 if (args[0] instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index"); 1081 if (args[1] instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as subarray length"); 1082 1083 splice(RubyNumeric.num2long(args[0]), RubyNumeric.num2long(args[1]), args[2]); 1084 return args[2]; 1085 } 1086 1087 throw getRuntime().newArgumentError("wrong number of arguments (" + args.length + " for 2)"); 1088 } 1089 1090 1093 public IRubyObject at(IRubyObject pos) { 1094 return entry(RubyNumeric.num2long(pos)); 1095 } 1096 1097 1100 public RubyArray concat(IRubyObject obj) { 1101 RubyArray ary = obj.convertToArray(); 1102 1103 if (ary.realLength > 0) splice(realLength, 0, ary); 1104 1105 return this; 1106 } 1107 1108 1111 public IRubyObject inspect() { 1112 if (realLength == 0) return getRuntime().newString("[]"); 1113 1114 if (!getRuntime().registerInspecting(this)) return getRuntime().newString("[...]"); 1115 1116 RubyString s; 1117 try { 1118 StringBuffer buffer = new StringBuffer ("["); 1119 Ruby runtime = getRuntime(); 1120 ThreadContext context = runtime.getCurrentContext(); 1121 boolean tainted = isTaint(); 1122 for (int i = 0; i < realLength; i++) { 1123 s = RubyString.objAsString(values[begin + i].callMethod(context, "inspect")); 1124 1125 if (s.isTaint()) tainted = true; 1126 1127 if (i > 0) buffer.append(", "); 1128 1129 buffer.append(s.toString()); 1130 } 1131 buffer.append("]"); 1132 if (tainted) setTaint(true); 1133 1134 return runtime.newString(buffer.toString()); 1135 } finally { 1136 getRuntime().unregisterInspecting(this); 1137 } 1138 } 1139 1140 1143 public IRubyObject first(IRubyObject[] args) { 1144 if (args.length == 0) { 1145 if (realLength == 0) return getRuntime().getNil(); 1146 1147 return values[begin]; 1148 } 1149 1150 checkArgumentCount(args, 0, 1); 1151 long n = RubyNumeric.num2long(args[0]); 1152 if (n > realLength) { 1153 n = realLength; 1154 } else if (n < 0) { 1155 throw getRuntime().newArgumentError("negative array size (or size too big)"); 1156 } 1157 1158 return makeShared(begin, (int) n); 1159 } 1160 1161 1164 public IRubyObject last(IRubyObject[] args) { 1165 if (args.length == 0) { 1166 if (realLength == 0) return getRuntime().getNil(); 1167 1168 return values[begin + realLength - 1]; 1169 } 1170 1171 checkArgumentCount(args, 0, 1); 1172 long n = RubyNumeric.num2long(args[0]); 1173 if (n > realLength) { 1174 n = realLength; 1175 } else if (n < 0) { 1176 throw getRuntime().newArgumentError("negative array size (or size too big)"); 1177 } 1178 1179 return makeShared(begin + realLength - (int) n, (int) n); 1180 } 1181 1182 1185 public IRubyObject each(Block block) { 1186 ThreadContext context = getRuntime().getCurrentContext(); 1187 if (shared) { 1188 for (int i = begin; i < begin + realLength; i++) { 1189 context.yield(values[i], block); 1190 } 1191 } else { 1192 for (int i = 0; i < realLength; i++) { 1193 context.yield(values[i], block); 1194 } 1195 } 1196 return this; 1197 } 1198 1199 1202 public IRubyObject each_index(Block block) { 1203 Ruby runtime = getRuntime(); 1204 ThreadContext context = runtime.getCurrentContext(); 1205 for (int i = 0; i < realLength; i++) { 1206 context.yield(runtime.newFixnum(i), block); 1207 } 1208 return this; 1209 } 1210 1211 1214 public IRubyObject reverse_each(Block block) { 1215 ThreadContext context = getRuntime().getCurrentContext(); 1216 1217 int len = realLength; 1218 1219 while(len-- > 0) { 1220 context.yield(values[begin + len], block); 1221 1222 if (realLength < len) len = realLength; 1223 } 1224 1225 return this; 1226 } 1227 1228 private final IRubyObject inspectJoin(IRubyObject sep) { 1229 IRubyObject result = join(sep); 1230 getRuntime().unregisterInspecting(this); 1231 return result; 1232 } 1233 1234 1237 public RubyString join(IRubyObject sep) { 1238 if (realLength == 0) return getRuntime().newString(""); 1239 1240 boolean taint = isTaint() || sep.isTaint(); 1241 1242 long len = 1; 1243 for (int i = begin; i < begin + realLength; i++) { 1244 IRubyObject tmp = values[i].checkStringType(); 1245 len += tmp.isNil() ? 10 : ((RubyString) tmp).getByteList().length(); 1246 } 1247 1248 if (!sep.isNil()) len += sep.convertToString().getByteList().length() * (realLength - 1); 1249 1250 StringBuffer buf = new StringBuffer ((int) len); 1251 Ruby runtime = getRuntime(); 1252 for (int i = begin; i < begin + realLength; i++) { 1253 IRubyObject tmp = values[i]; 1254 if (tmp instanceof RubyString) { 1255 } else if (tmp instanceof RubyArray) { 1257 if (!runtime.registerInspecting(tmp)) { 1258 tmp = runtime.newString("[...]"); 1259 } else { 1260 tmp = ((RubyArray) tmp).inspectJoin(sep); 1261 } 1262 } else { 1263 tmp = RubyString.objAsString(tmp); 1264 } 1265 1266 if (i > begin && !sep.isNil()) buf.append(sep.toString()); 1267 1268 buf.append(((RubyString) tmp).toString()); 1269 taint |= tmp.isTaint(); 1270 } 1271 1272 RubyString result = RubyString.newString(runtime, buf.toString()); 1273 1274 if (taint) result.setTaint(taint); 1275 1276 return result; 1277 } 1278 1279 1282 public RubyString join_m(IRubyObject[] args) { 1283 int argc = checkArgumentCount(args, 0, 1); 1284 IRubyObject sep = (argc == 1) ? args[0] : getRuntime().getGlobalVariables().get("$,"); 1285 1286 return join(sep); 1287 } 1288 1289 1292 public RubyArray to_a() { 1293 return this; 1294 } 1295 1296 public IRubyObject to_ary() { 1297 return this; 1298 } 1299 1300 public RubyArray convertToArray() { 1301 return this; 1302 } 1303 1304 public IRubyObject checkArrayType(){ 1305 return this; 1306 } 1307 1308 1311 public IRubyObject op_equal(IRubyObject obj) { 1312 if (this == obj) return getRuntime().getTrue(); 1313 1314 if (!(obj instanceof RubyArray)) { 1315 if (!obj.respondsTo("to_ary")) { 1316 return getRuntime().getFalse(); 1317 } else { 1318 return obj.equalInternal(getRuntime().getCurrentContext(), this); 1319 } 1320 } 1321 1322 RubyArray ary = (RubyArray) obj; 1323 if (realLength != ary.realLength) return getRuntime().getFalse(); 1324 1325 Ruby runtime = getRuntime(); 1326 final ThreadContext context = runtime.getCurrentContext(); 1327 for (long i = 0; i < realLength; i++) { 1328 if (!elt(i).equalInternal(context, ary.elt(i)).isTrue()) return runtime.getFalse(); 1329 } 1330 return runtime.getTrue(); 1331 } 1332 1333 1336 public RubyBoolean eql(IRubyObject obj) { 1337 if (this == obj) return getRuntime().getTrue(); 1338 if (!(obj instanceof RubyArray)) return getRuntime().getFalse(); 1339 1340 RubyArray ary = (RubyArray) obj; 1341 1342 if (realLength != ary.realLength) return getRuntime().getFalse(); 1343 1344 Ruby runtime = getRuntime(); 1345 final ThreadContext context = runtime.getCurrentContext(); 1346 for (long i = 0; i < realLength; i++) { 1347 if (!elt(i).callMethod(context, "eql?", ary.elt(i)).isTrue()) return runtime.getFalse(); 1348 } 1349 return runtime.getTrue(); 1350 } 1351 1352 1355 public IRubyObject compact_bang() { 1356 modify(); 1357 1358 int p = 0; 1359 int t = 0; 1360 int end = p + realLength; 1361 1362 while (t < end) { 1363 if (values[t].isNil()) { 1364 t++; 1365 } else { 1366 values[p++] = values[t++]; 1367 } 1368 } 1369 1370 if (realLength == p) return getRuntime().getNil(); 1371 1372 realloc(p); 1373 realLength = p; 1374 return this; 1375 } 1376 1377 1380 public IRubyObject compact() { 1381 RubyArray ary = aryDup(); 1382 ary.compact_bang(); 1383 return ary; 1384 } 1385 1386 1389 public IRubyObject empty_p() { 1390 return realLength == 0 ? getRuntime().getTrue() : getRuntime().getFalse(); 1391 } 1392 1393 1396 public IRubyObject rb_clear() { 1397 modifyCheck(); 1398 1399 if(shared){ 1400 alloc(ARRAY_DEFAULT_SIZE); 1401 shared = false; 1402 } else if (values.length > ARRAY_DEFAULT_SIZE << 1){ 1403 alloc(ARRAY_DEFAULT_SIZE << 1); 1404 } 1405 1406 begin = 0; 1407 realLength = 0; 1408 return this; 1409 } 1410 1411 1414 public IRubyObject fill(IRubyObject[] args, Block block) { 1415 IRubyObject item = null; 1416 IRubyObject begObj = null; 1417 IRubyObject lenObj = null; 1418 int argc = args.length; 1419 1420 if (block.isGiven()) { 1421 checkArgumentCount(args, 0, 2); 1422 item = null; 1423 begObj = argc > 0 ? args[0] : null; 1424 lenObj = argc > 1 ? args[1] : null; 1425 argc++; 1426 } else { 1427 checkArgumentCount(args, 1, 3); 1428 item = args[0]; 1429 begObj = argc > 1 ? args[1] : null; 1430 lenObj = argc > 2 ? args[2] : null; 1431 } 1432 1433 long beg = 0, end = 0, len = 0; 1434 switch (argc) { 1435 case 1: 1436 beg = 0; 1437 len = realLength; 1438 break; 1439 case 2: 1440 if (begObj instanceof RubyRange) { 1441 long[] beglen = ((RubyRange) begObj).begLen(realLength, 1); 1442 beg = (int) beglen[0]; 1443 len = (int) beglen[1]; 1444 break; 1445 } 1446 1447 case 3: 1448 beg = begObj.isNil() ? 0 : RubyNumeric.num2long(begObj); 1449 if (beg < 0) { 1450 beg = realLength + beg; 1451 if (beg < 0) beg = 0; 1452 } 1453 len = (lenObj == null || lenObj.isNil()) ? realLength - beg : RubyNumeric.num2long(lenObj); 1454 break; 1455 } 1456 1457 modify(); 1458 1459 end = beg + len; 1460 if (end > realLength) { 1461 if (end >= values.length) realloc((int) end); 1462 1463 Arrays.fill(values, realLength, (int) end, getRuntime().getNil()); 1464 realLength = (int) end; 1465 } 1466 1467 if (block.isGiven()) { 1468 Ruby runtime = getRuntime(); 1469 ThreadContext context = runtime.getCurrentContext(); 1470 for (int i = (int) beg; i < (int) end; i++) { 1471 IRubyObject v = context.yield(runtime.newFixnum(i), block); 1472 if (i >= realLength) break; 1473 1474 values[i] = v; 1475 } 1476 } else { 1477 if(len > 0) Arrays.fill(values, (int) beg, (int) (beg + len), item); 1478 } 1479 1480 return this; 1481 } 1482 1483 1486 public IRubyObject index(IRubyObject obj) { 1487 Ruby runtime = getRuntime(); 1488 final ThreadContext context = runtime.getCurrentContext(); 1489 for (int i = begin; i < begin + realLength; i++) { 1490 if (values[i].equalInternal(context, obj).isTrue()) return runtime.newFixnum(i - begin); 1491 } 1492 1493 return runtime.getNil(); 1494 } 1495 1496 1499 public IRubyObject rindex(IRubyObject obj) { 1500 Ruby runtime = getRuntime(); 1501 final ThreadContext context = runtime.getCurrentContext(); 1502 1503 int i = realLength; 1504 1505 while (i-- > 0) { 1506 if (i > realLength) { 1507 i = realLength; 1508 continue; 1509 } 1510 if (values[begin + i].equalInternal(context, obj).isTrue()) { 1511 return getRuntime().newFixnum(i); 1512 } 1513 } 1514 1515 return runtime.getNil(); 1516 } 1517 1518 1521 public IRubyObject indexes(IRubyObject[] args) { 1522 getRuntime().getWarnings().warn("Array#indexes is deprecated; use Array#values_at"); 1523 1524 RubyArray ary = new RubyArray(getRuntime(), args.length); 1525 1526 IRubyObject[] arefArgs = new IRubyObject[1]; 1527 for (int i = 0; i < args.length; i++) { 1528 arefArgs[0] = args[i]; 1529 ary.append(aref(arefArgs)); 1530 } 1531 1532 return ary; 1533 } 1534 1535 1538 public IRubyObject reverse_bang() { 1539 modify(); 1540 1541 IRubyObject tmp; 1542 if (realLength > 1) { 1543 int p1 = 0; 1544 int p2 = p1 + realLength - 1; 1545 1546 while (p1 < p2) { 1547 tmp = values[p1]; 1548 values[p1++] = values[p2]; 1549 values[p2--] = tmp; 1550 } 1551 } 1552 return this; 1553 } 1554 1555 1558 public IRubyObject reverse() { 1559 return aryDup().reverse_bang(); 1560 } 1561 1562 1565 public RubyArray collect(Block block) { 1566 if (!block.isGiven()) return new RubyArray(getRuntime(), this); 1567 1568 Ruby runtime = getRuntime(); 1569 ThreadContext context = runtime.getCurrentContext(); 1570 RubyArray collect = new RubyArray(runtime, realLength); 1571 1572 for (int i = begin; i < begin + realLength; i++) { 1573 collect.append(context.yield(values[i], block)); 1574 } 1575 1576 return collect; 1577 } 1578 1579 1582 public RubyArray collect_bang(Block block) { 1583 modify(); 1584 ThreadContext context = getRuntime().getCurrentContext(); 1585 for (int i = 0, len = realLength; i < len; i++) { 1586 store(i, context.yield(values[begin + i], block)); 1587 } 1588 return this; 1589 } 1590 1591 1594 public RubyArray select(Block block) { 1595 Ruby runtime = getRuntime(); 1596 RubyArray result = new RubyArray(runtime, realLength); 1597 1598 ThreadContext context = runtime.getCurrentContext(); 1599 if (shared) { 1600 for (int i = begin; i < begin + realLength; i++) { 1601 if (context.yield(values[i], block).isTrue()) result.append(elt(i - begin)); 1602 } 1603 } else { 1604 for (int i = 0; i < realLength; i++) { 1605 if (context.yield(values[i], block).isTrue()) result.append(elt(i)); 1606 } 1607 } 1608 return result; 1609 } 1610 1611 1614 public IRubyObject delete(IRubyObject item, Block block) { 1615 int i2 = 0; 1616 1617 Ruby runtime = getRuntime(); 1618 final ThreadContext context = runtime.getCurrentContext(); 1619 for (int i1 = 0; i1 < realLength; i1++) { 1620 IRubyObject e = values[begin + i1]; 1621 if (e.equalInternal(context, item).isTrue()) continue; 1622 if (i1 != i2) store(i2, e); 1623 i2++; 1624 } 1625 1626 if (realLength == i2) { 1627 if (block.isGiven()) return context.yield(item, block); 1628 1629 return runtime.getNil(); 1630 } 1631 1632 modify(); 1633 1634 if (realLength > i2) { 1635 realLength = i2; 1636 if (i2 << 1 < values.length && values.length > ARRAY_DEFAULT_SIZE) realloc(i2 << 1); 1637 } 1638 return item; 1639 } 1640 1641 1644 private final IRubyObject delete_at(int pos) { 1645 int len = realLength; 1646 1647 if (pos >= len) return getRuntime().getNil(); 1648 1649 if (pos < 0) pos += len; 1650 1651 if (pos < 0) return getRuntime().getNil(); 1652 1653 modify(); 1654 1655 IRubyObject obj = values[pos]; 1656 System.arraycopy(values, pos + 1, values, pos, len - (pos + 1)); 1657 1658 realLength--; 1659 1660 return obj; 1661 } 1662 1663 1666 public IRubyObject delete_at(IRubyObject obj) { 1667 return delete_at((int) RubyNumeric.num2long(obj)); 1668 } 1669 1670 1673 public IRubyObject reject(Block block) { 1674 RubyArray ary = aryDup(); 1675 ary.reject_bang(block); 1676 return ary; 1677 } 1678 1679 1682 public IRubyObject reject_bang(Block block) { 1683 int i2 = 0; 1684 modify(); 1685 1686 ThreadContext context = getRuntime().getCurrentContext(); 1687 for (int i1 = 0; i1 < realLength; i1++) { 1688 IRubyObject v = values[i1]; 1689 if (context.yield(v, block).isTrue()) continue; 1690 1691 if (i1 != i2) store(i2, v); 1692 i2++; 1693 } 1694 if (realLength == i2) return getRuntime().getNil(); 1695 1696 if (i2 < realLength) realLength = i2; 1697 1698 return this; 1699 } 1700 1701 1704 public IRubyObject delete_if(Block block) { 1705 reject_bang(block); 1706 return this; 1707 } 1708 1709 1712 public IRubyObject zip(IRubyObject[] args, Block block) { 1713 for (int i = 0; i < args.length; i++) { 1714 args[i] = args[i].convertToArray(); 1715 } 1716 1717 Ruby runtime = getRuntime(); 1718 ThreadContext context = runtime.getCurrentContext(); 1719 if (block.isGiven()) { 1720 for (int i = 0; i < realLength; i++) { 1721 RubyArray tmp = new RubyArray(runtime, args.length + 1); 1722 tmp.append(elt(i)); 1723 for (int j = 0; j < args.length; j++) { 1724 tmp.append(((RubyArray) args[j]).elt(i)); 1725 } 1726 context.yield(tmp, block); 1727 } 1728 return runtime.getNil(); 1729 } 1730 1731 int len = realLength; 1732 RubyArray result = new RubyArray(runtime, len); 1733 for (int i = 0; i < len; i++) { 1734 RubyArray tmp = new RubyArray(runtime, args.length + 1); 1735 tmp.append(elt(i)); 1736 for (int j = 0; j < args.length; j++) { 1737 tmp.append(((RubyArray) args[j]).elt(i)); 1738 } 1739 result.append(tmp); 1740 } 1741 return result; 1742 } 1743 1744 1747 public IRubyObject op_cmp(IRubyObject obj) { 1748 RubyArray ary2 = obj.convertToArray(); 1749 1750 int len = realLength; 1751 1752 if (len > ary2.realLength) len = ary2.realLength; 1753 1754 Ruby runtime = getRuntime(); 1755 ThreadContext context = runtime.getCurrentContext(); 1756 for (int i = 0; i < len; i++) { 1757 IRubyObject v = elt(i).callMethod(context, "<=>", ary2.elt(i)); 1758 if (!(v instanceof RubyFixnum) || ((RubyFixnum) v).getLongValue() != 0) return v; 1759 } 1760 len = realLength - ary2.realLength; 1761 1762 if (len == 0) return RubyFixnum.zero(runtime); 1763 if (len > 0) return RubyFixnum.one(runtime); 1764 1765 return RubyFixnum.minus_one(runtime); 1766 } 1767 1768 1771 public IRubyObject slice_bang(IRubyObject[] args) { 1772 if (checkArgumentCount(args, 1, 2) == 2) { 1773 long pos = RubyNumeric.num2long(args[0]); 1774 long len = RubyNumeric.num2long(args[1]); 1775 1776 if (pos < 0) pos = realLength + pos; 1777 1778 args[1] = subseq(pos, len); 1779 splice(pos, len, null); 1780 1781 return args[1]; 1782 } 1783 1784 IRubyObject arg = args[0]; 1785 if (arg instanceof RubyRange) { 1786 long[] beglen = ((RubyRange) arg).begLen(realLength, 1); 1787 long pos = beglen[0]; 1788 long len = beglen[1]; 1789 1790 if (pos < 0) { 1791 pos = realLength + pos; 1792 } 1793 arg = subseq(pos, len); 1794 splice(pos, len, null); 1795 return arg; 1796 } 1797 1798 return delete_at((int) RubyNumeric.num2long(args[0])); 1799 } 1800 1801 1804 public IRubyObject assoc(IRubyObject key) { 1805 Ruby runtime = getRuntime(); 1806 final ThreadContext context = runtime.getCurrentContext(); 1807 1808 for (int i = begin; i < begin + realLength; i++) { 1809 IRubyObject v = values[i]; 1810 if (v instanceof RubyArray && ((RubyArray) v).realLength > 0 1811 && ((RubyArray) v).values[0].equalInternal(context, key).isTrue()) { 1812 return v; 1813 } 1814 } 1815 return runtime.getNil(); 1816 } 1817 1818 1821 public IRubyObject rassoc(IRubyObject value) { 1822 Ruby runtime = getRuntime(); 1823 final ThreadContext context = runtime.getCurrentContext(); 1824 1825 for (int i = begin; i < begin + realLength; i++) { 1826 IRubyObject v = values[i]; 1827 if (v instanceof RubyArray && ((RubyArray) v).realLength > 1 1828 && ((RubyArray) v).values[1].equalInternal(context, value).isTrue()) { 1829 return v; 1830 } 1831 } 1832 1833 return runtime.getNil(); 1834 } 1835 1836 1839 private final int flatten(int index, RubyArray ary2, RubyArray memo) { 1840 int i = index; 1841 int n; 1842 int lim = index + ary2.realLength; 1843 1844 IRubyObject id = ary2.id(); 1845 1846 if (memo.includes(id)) throw getRuntime().newArgumentError("tried to flatten recursive array"); 1847 1848 memo.append(id); 1849 splice(index, 1, ary2); 1850 while (i < lim) { 1851 IRubyObject tmp = elt(i).checkArrayType(); 1852 if (!tmp.isNil()) { 1853 n = flatten(i, (RubyArray) tmp, memo); 1854 i += n; 1855 lim += n; 1856 } 1857 i++; 1858 } 1859 memo.pop(); 1860 return lim - index - 1; 1861 } 1862 1863 1866 public IRubyObject flatten_bang() { 1867 int i = 0; 1868 RubyArray memo = null; 1869 1870 while (i < realLength) { 1871 IRubyObject ary2 = values[begin + i]; 1872 IRubyObject tmp = ary2.checkArrayType(); 1873 if (!tmp.isNil()) { 1874 if (memo == null) { 1875 memo = new RubyArray(getRuntime(), false); 1876 memo.values = reserve(ARRAY_DEFAULT_SIZE); 1877 } 1878 1879 i += flatten(i, (RubyArray) tmp, memo); 1880 } 1881 i++; 1882 } 1883 if (memo == null) return getRuntime().getNil(); 1884 1885 return this; 1886 } 1887 1888 1891 public IRubyObject flatten() { 1892 RubyArray ary = aryDup(); 1893 ary.flatten_bang(); 1894 return ary; 1895 } 1896 1897 1900 public IRubyObject nitems() { 1901 int n = 0; 1902 1903 for (int i = begin; i < begin + realLength; i++) { 1904 if (!values[i].isNil()) n++; 1905 } 1906 1907 return getRuntime().newFixnum(n); 1908 } 1909 1910 1913 public IRubyObject op_plus(IRubyObject obj) { 1914 RubyArray y = obj.convertToArray(); 1915 int len = realLength + y.realLength; 1916 RubyArray z = new RubyArray(getRuntime(), len); 1917 System.arraycopy(values, begin, z.values, 0, realLength); 1918 System.arraycopy(y.values, y.begin, z.values, realLength, y.realLength); 1919 z.realLength = len; 1920 return z; 1921 } 1922 1923 1926 public IRubyObject op_times(IRubyObject times) { 1927 IRubyObject tmp = times.checkStringType(); 1928 1929 if (!tmp.isNil()) return join(tmp); 1930 1931 long len = RubyNumeric.num2long(times); 1932 if (len == 0) return new RubyArray(getRuntime(), 0); 1933 if (len < 0) throw getRuntime().newArgumentError("negative argument"); 1934 1935 if (Long.MAX_VALUE / len < realLength) { 1936 throw getRuntime().newArgumentError("argument too big"); 1937 } 1938 1939 len *= realLength; 1940 1941 RubyArray ary2 = new RubyArray(getRuntime(), len); 1942 ary2.realLength = (int) len; 1943 1944 for (int i = 0; i < len; i += realLength) { 1945 System.arraycopy(values, begin, ary2.values, i, realLength); 1946 } 1947 1948 ary2.infectBy(this); 1949 1950 return ary2; 1951 } 1952 1953 1956 private final Set makeSet(RubyArray ary2) { 1957 final Set set = new HashSet (); 1958 int begin = this.begin; 1959 for (int i = begin; i < begin + realLength; i++) { 1960 set.add(values[i]); 1961 } 1962 1963 if (ary2 != null) { 1964 begin = ary2.begin; 1965 for (int i = begin; i < begin + ary2.realLength; i++) { 1966 set.add(ary2.values[i]); 1967 } 1968 } 1969 return set; 1970 } 1971 1972 1975 public IRubyObject uniq_bang() { 1976 Set set = makeSet(null); 1977 1978 if (realLength == set.size()) return getRuntime().getNil(); 1979 1980 int j = 0; 1981 for (int i = 0; i < realLength; i++) { 1982 IRubyObject v = elt(i); 1983 if (set.remove(v)) store(j++, v); 1984 } 1985 realLength = j; 1986 return this; 1987 } 1988 1989 1992 public IRubyObject uniq() { 1993 RubyArray ary = aryDup(); 1994 ary.uniq_bang(); 1995 return ary; 1996 } 1997 1998 2001 public IRubyObject op_diff(IRubyObject other) { 2002 Set set = other.convertToArray().makeSet(null); 2003 RubyArray ary3 = new RubyArray(getRuntime()); 2004 2005 int begin = this.begin; 2006 for (int i = begin; i < begin + realLength; i++) { 2007 if (set.contains(values[i])) continue; 2008 2009 ary3.append(elt(i - begin)); 2010 } 2011 2012 return ary3; 2013 } 2014 2015 2018 public IRubyObject op_and(IRubyObject other) { 2019 RubyArray ary2 = other.convertToArray(); 2020 Set set = ary2.makeSet(null); 2021 RubyArray ary3 = new RubyArray(getRuntime(), 2022 realLength < ary2.realLength ? realLength : ary2.realLength); 2023 2024 for (int i = 0; i < realLength; i++) { 2025 IRubyObject v = elt(i); 2026 if (set.remove(v)) ary3.append(v); 2027 } 2028 2029 return ary3; 2030 } 2031 2032 2035 public IRubyObject op_or(IRubyObject other) { 2036 RubyArray ary2 = other.convertToArray(); 2037 Set set = makeSet(ary2); 2038 2039 RubyArray ary3 = new RubyArray(getRuntime(), realLength + ary2.realLength); 2040 2041 for (int i = 0; i < realLength; i++) { 2042 IRubyObject v = elt(i); 2043 if (set.remove(v)) ary3.append(v); 2044 } 2045 for (int i = 0; i < ary2.realLength; i++) { 2046 IRubyObject v = ary2.elt(i); 2047 if (set.remove(v)) ary3.append(v); 2048 } 2049 return ary3; 2050 } 2051 2052 2055 public RubyArray sort(Block block) { 2056 RubyArray ary = aryDup(); 2057 ary.sort_bang(block); 2058 return ary; 2059 } 2060 2061 2064 public RubyArray sort_bang(Block block) { 2065 modify(); 2066 if (realLength > 1) { 2067 tmpLock = true; 2068 try { 2069 if (block.isGiven()) { 2070 Arrays.sort(values, 0, realLength, new BlockComparator(block)); 2071 } else { 2072 Arrays.sort(values, 0, realLength, new DefaultComparator()); 2073 } 2074 } finally { 2075 tmpLock = false; 2076 } 2077 } 2078 return this; 2079 } 2080 2081 final class BlockComparator implements Comparator { 2082 private Block block; 2083 2084 public BlockComparator(Block block) { 2085 this.block = block; 2086 } 2087 2088 public int compare(Object o1, Object o2) { 2089 ThreadContext context = getRuntime().getCurrentContext(); 2090 IRubyObject obj1 = (IRubyObject) o1; 2091 IRubyObject obj2 = (IRubyObject) o2; 2092 IRubyObject ret = block.yield(context, getRuntime().newArray(obj1, obj2), null, null, true); 2093 int n = RubyComparable.cmpint(ret, obj1, obj2); 2094 return n; 2096 } 2097 } 2098 2099 final class DefaultComparator implements Comparator { 2100 public int compare(Object o1, Object o2) { 2101 if (o1 instanceof RubyFixnum && o2 instanceof RubyFixnum) { 2102 long a = ((RubyFixnum) o1).getLongValue(); 2103 long b = ((RubyFixnum) o2).getLongValue(); 2104 if (a > b) return 1; 2105 if (a < b) return -1; 2106 return 0; 2107 } 2108 if (o1 instanceof RubyString && o2 instanceof RubyString) { 2109 return ((RubyString) o1).cmp((RubyString) o2); 2110 } 2111 2112 IRubyObject obj1 = (IRubyObject) o1; 2113 IRubyObject obj2 = (IRubyObject) o2; 2114 2115 IRubyObject ret = obj1.callMethod(obj1.getRuntime().getCurrentContext(), "<=>", obj2); 2116 int n = RubyComparable.cmpint(ret, obj1, obj2); 2117 return n; 2119 } 2120 } 2121 2122 public static void marshalTo(RubyArray array, MarshalStream output) throws IOException { 2123 output.writeInt(array.getList().size()); 2124 for (Iterator iter = array.getList().iterator(); iter.hasNext();) { 2125 output.dumpObject((IRubyObject) iter.next()); 2126 } 2127 } 2128 2129 public static RubyArray unmarshalFrom(UnmarshalStream input) throws IOException { 2130 RubyArray result = input.getRuntime().newArray(); 2131 input.registerLinkTarget(result); 2132 int size = input.unmarshalInt(); 2133 for (int i = 0; i < size; i++) { 2134 result.append(input.unmarshalObject()); 2135 } 2136 return result; 2137 } 2138 2139 2142 public RubyString pack(IRubyObject obj) { 2143 RubyString iFmt = RubyString.objAsString(obj); 2144 return Pack.pack(getRuntime(), Arrays.asList(toJavaArrayMaybeUnsafe()), iFmt.getBytes()); 2145 } 2146 2147 public Class getJavaClass() { 2148 return List .class; 2149 } 2150 2151 2153 public int size() { 2154 return realLength; 2155 } 2156 2157 public boolean isEmpty() { 2158 return realLength == 0; 2159 } 2160 2161 public boolean contains(Object element) { 2162 return indexOf(element) != -1; 2163 } 2164 2165 public Object [] toArray() { 2166 Object [] array = new Object [realLength]; 2167 for (int i = begin; i < realLength; i++) { 2168 array[i - begin] = JavaUtil.convertRubyToJava(values[i]); 2169 } 2170 return array; 2171 } 2172 2173 public Object [] toArray(final Object [] arg) { 2174 Object [] array = arg; 2175 if (array.length < realLength) { 2176 Class type = array.getClass().getComponentType(); 2177 array = (Object []) Array.newInstance(type, realLength); 2178 } 2179 int length = realLength - begin; 2180 2181 for (int i = 0; i < length; i++) { 2182 array[i] = JavaUtil.convertRubyToJava(values[i + begin]); 2183 } 2184 return array; 2185 } 2186 2187 public boolean add(Object element) { 2188 append(JavaUtil.convertJavaToRuby(getRuntime(), element)); 2189 return true; 2190 } 2191 2192 public boolean remove(Object element) { 2193 IRubyObject deleted = delete(JavaUtil.convertJavaToRuby(getRuntime(), element), Block.NULL_BLOCK); 2194 return deleted.isNil() ? false : true; } 2196 2197 public boolean containsAll(Collection c) { 2198 for (Iterator iter = c.iterator(); iter.hasNext();) { 2199 if (indexOf(iter.next()) == -1) return false; 2200 } 2201 2202 return true; 2203 } 2204 2205 public boolean addAll(Collection c) { 2206 for (Iterator iter = c.iterator(); iter.hasNext();) { 2207 add(iter.next()); 2208 } 2209 return !c.isEmpty(); 2210 } 2211 2212 public boolean addAll(int index, Collection c) { 2213 Iterator iter = c.iterator(); 2214 for (int i = index; iter.hasNext(); i++) { 2215 add(i, iter.next()); 2216 } 2217 return !c.isEmpty(); 2218 } 2219 2220 public boolean removeAll(Collection c) { 2221 boolean listChanged = false; 2222 for (Iterator iter = c.iterator(); iter.hasNext();) { 2223 if (remove(iter.next())) { 2224 listChanged = true; 2225 } 2226 } 2227 return listChanged; 2228 } 2229 2230 public boolean retainAll(Collection c) { 2231 boolean listChanged = false; 2232 2233 for (Iterator iter = iterator(); iter.hasNext();) { 2234 Object element = iter.next(); 2235 if (!c.contains(element)) { 2236 remove(element); 2237 listChanged = true; 2238 } 2239 } 2240 return listChanged; 2241 } 2242 2243 public Object get(int index) { 2244 return JavaUtil.convertRubyToJava((IRubyObject) elt(index), Object .class); 2245 } 2246 2247 public Object set(int index, Object element) { 2248 return store(index, JavaUtil.convertJavaToRuby(getRuntime(), element)); 2249 } 2250 2251 public void add(int index, Object element) { 2253 insert(new IRubyObject[] { RubyFixnum.newFixnum(getRuntime(), index), JavaUtil.convertJavaToRuby(getRuntime(), element) }); 2254 } 2255 2256 public Object remove(int index) { 2257 return JavaUtil.convertRubyToJava(delete_at(index), Object .class); 2258 } 2259 2260 public int indexOf(Object element) { 2261 int begin = this.begin; 2262 2263 if (element == null) { 2264 for (int i = begin; i < begin + realLength; i++) { 2265 if (values[i] == null) return i; 2266 } 2267 } else { 2268 IRubyObject convertedElement = JavaUtil.convertJavaToRuby(getRuntime(), element); 2269 2270 for (int i = begin; i < begin + realLength; i++) { 2271 if (convertedElement.equals(values[i])) return i; 2272 } 2273 } 2274 return -1; 2275 } 2276 2277 public int lastIndexOf(Object element) { 2278 int begin = this.begin; 2279 2280 if (element == null) { 2281 for (int i = begin + realLength - 1; i >= begin; i--) { 2282 if (values[i] == null) return i; 2283 } 2284 } else { 2285 IRubyObject convertedElement = JavaUtil.convertJavaToRuby(getRuntime(), element); 2286 2287 for (int i = begin + realLength - 1; i >= begin; i--) { 2288 if (convertedElement.equals(values[i])) return i; 2289 } 2290 } 2291 2292 return -1; 2293 } 2294 2295 public class RubyArrayConversionIterator implements Iterator { 2296 protected int index = 0; 2297 protected int last = -1; 2298 2299 public boolean hasNext() { 2300 return index < realLength; 2301 } 2302 2303 public Object next() { 2304 IRubyObject element = elt(index); 2305 last = index++; 2306 return JavaUtil.convertRubyToJava(element, Object .class); 2307 } 2308 2309 public void remove() { 2310 if (last == -1) throw new IllegalStateException (); 2311 2312 delete_at(last); 2313 if (last < index) index--; 2314 2315 last = -1; 2316 2317 } 2318 } 2319 2320 public Iterator iterator() { 2321 return new RubyArrayConversionIterator(); 2322 } 2323 2324 final class RubyArrayConversionListIterator extends RubyArrayConversionIterator implements ListIterator { 2325 public RubyArrayConversionListIterator() { 2326 } 2327 2328 public RubyArrayConversionListIterator(int index) { 2329 this.index = index; 2330 } 2331 2332 public boolean hasPrevious() { 2333 return index >= 0; 2334 } 2335 2336 public Object previous() { 2337 return JavaUtil.convertRubyToJava((IRubyObject) elt(last = --index), Object .class); 2338 } 2339 2340 public int nextIndex() { 2341 return index; 2342 } 2343 2344 public int previousIndex() { 2345 return index - 1; 2346 } 2347 2348 public void set(Object obj) { 2349 if (last == -1) throw new IllegalStateException (); 2350 2351 store(last, JavaUtil.convertJavaToRuby(getRuntime(), obj)); 2352 } 2353 2354 public void add(Object obj) { 2355 insert(new IRubyObject[] { RubyFixnum.newFixnum(getRuntime(), index++), JavaUtil.convertJavaToRuby(getRuntime(), obj) }); 2356 last = -1; 2357 } 2358 } 2359 2360 public ListIterator listIterator() { 2361 return new RubyArrayConversionListIterator(); 2362 } 2363 2364 public ListIterator listIterator(int index) { 2365 return new RubyArrayConversionListIterator(index); 2366 } 2367 2368 public List subList(int fromIndex, int toIndex) { 2371 if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) { 2372 throw new IndexOutOfBoundsException (); 2373 } 2374 2375 IRubyObject subList = subseq(fromIndex, toIndex - fromIndex + 1); 2376 2377 return subList.isNil() ? null : (List ) subList; 2378 } 2379 2380 public void clear() { 2381 rb_clear(); 2382 } 2383} 2384 | Popular Tags |