0001: /***** BEGIN LICENSE BLOCK *****
0002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
0003: *
0004: * The contents of this file are subject to the Common Public
0005: * License Version 1.0 (the "License"); you may not use this file
0006: * except in compliance with the License. You may obtain a copy of
0007: * the License at http://www.eclipse.org/legal/cpl-v10.html
0008: *
0009: * Software distributed under the License is distributed on an "AS
0010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0011: * implied. See the License for the specific language governing
0012: * rights and limitations under the License.
0013: *
0014: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
0015: * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
0016: * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
0017: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
0018: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
0019: * Copyright (C) 2002-2005 Thomas E Enebo <enebo@acm.org>
0020: * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
0021: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
0022: * Copyright (C) 2006 Ola Bini <Ola.Bini@ki.se>
0023: * Copyright (C) 2006 Daniel Steer <damian.steer@hp.com>
0024: *
0025: * Alternatively, the contents of this file may be used under the terms of
0026: * either of the GNU General Public License Version 2 or later (the "GPL"),
0027: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
0028: * in which case the provisions of the GPL or the LGPL are applicable instead
0029: * of those above. If you wish to allow use of your version of this file only
0030: * under the terms of either the GPL or the LGPL, and not to allow others to
0031: * use your version of this file under the terms of the CPL, indicate your
0032: * decision by deleting the provisions above and replace them with the notice
0033: * and other provisions required by the GPL or the LGPL. If you do not delete
0034: * the provisions above, a recipient may use your version of this file under
0035: * the terms of any one of the CPL, the GPL or the LGPL.
0036: ***** END LICENSE BLOCK *****/package org.jruby;
0037:
0038: import java.lang.reflect.Array;
0039: import java.io.IOException;
0040: import java.util.Arrays;
0041: import java.util.Collection;
0042: import java.util.Comparator;
0043: import java.util.HashSet;
0044: import java.util.Iterator;
0045: import java.util.List;
0046: import java.util.ListIterator;
0047: import java.util.Set;
0048: import org.jruby.javasupport.JavaUtil;
0049: import org.jruby.runtime.Arity;
0050: import org.jruby.runtime.Block;
0051: import org.jruby.runtime.CallType;
0052: import org.jruby.runtime.CallbackFactory;
0053: import org.jruby.runtime.ClassIndex;
0054: import org.jruby.runtime.MethodIndex;
0055: import org.jruby.runtime.ObjectAllocator;
0056: import org.jruby.runtime.ThreadContext;
0057: import org.jruby.runtime.builtin.IRubyObject;
0058: import org.jruby.runtime.marshal.MarshalStream;
0059: import org.jruby.runtime.marshal.UnmarshalStream;
0060: import org.jruby.util.ByteList;
0061: import org.jruby.util.Pack;
0062:
0063: /**
0064: * The implementation of the built-in class Array in Ruby.
0065: */
0066: public class RubyArray extends RubyObject implements List {
0067:
0068: public static RubyClass createArrayClass(Ruby runtime) {
0069: RubyClass arrayc = runtime.defineClass("Array", runtime
0070: .getObject(), ARRAY_ALLOCATOR);
0071: arrayc.index = ClassIndex.ARRAY;
0072: CallbackFactory callbackFactory = runtime
0073: .callbackFactory(RubyArray.class);
0074:
0075: arrayc.includeModule(runtime.getModule("Enumerable"));
0076: arrayc.getMetaClass().defineMethod("[]",
0077: callbackFactory.getOptSingletonMethod("create"));
0078:
0079: arrayc.defineMethod("initialize", callbackFactory
0080: .getOptMethod("initialize"));
0081: arrayc.defineFastMethod("initialize_copy", callbackFactory
0082: .getFastMethod("replace", RubyKernel.IRUBY_OBJECT));
0083: arrayc.defineFastMethod("to_s", callbackFactory
0084: .getFastMethod("to_s"));
0085: arrayc.defineFastMethod("inspect", callbackFactory
0086: .getFastMethod("inspect"));
0087: arrayc.defineFastMethod("to_a", callbackFactory
0088: .getFastMethod("to_a"));
0089: arrayc.defineFastMethod("to_ary", callbackFactory
0090: .getFastMethod("to_ary"));
0091: arrayc.defineFastMethod("frozen?", callbackFactory
0092: .getFastMethod("frozen"));
0093:
0094: arrayc.defineFastMethod("==", callbackFactory.getFastMethod(
0095: "op_equal", RubyKernel.IRUBY_OBJECT));
0096: arrayc.defineFastMethod("eql?", callbackFactory.getFastMethod(
0097: "eql_p", RubyKernel.IRUBY_OBJECT));
0098: arrayc.defineFastMethod("hash", callbackFactory
0099: .getFastMethod("hash"));
0100:
0101: arrayc.defineFastMethod("[]", callbackFactory
0102: .getFastOptMethod("aref"));
0103: arrayc.defineFastMethod("[]=", callbackFactory
0104: .getFastOptMethod("aset"));
0105: arrayc.defineFastMethod("at", callbackFactory.getFastMethod(
0106: "at", RubyKernel.IRUBY_OBJECT));
0107: arrayc.defineMethod("fetch", callbackFactory
0108: .getOptMethod("fetch"));
0109: arrayc.defineFastMethod("first", callbackFactory
0110: .getFastOptMethod("first"));
0111: arrayc.defineFastMethod("last", callbackFactory
0112: .getFastOptMethod("last"));
0113: arrayc.defineFastMethod("concat", callbackFactory
0114: .getFastMethod("concat", RubyKernel.IRUBY_OBJECT));
0115: arrayc.defineFastMethod("<<", callbackFactory.getFastMethod(
0116: "append", RubyKernel.IRUBY_OBJECT));
0117: arrayc.defineFastMethod("push", callbackFactory
0118: .getFastOptMethod("push_m"));
0119: arrayc.defineFastMethod("pop", callbackFactory
0120: .getFastMethod("pop"));
0121: arrayc.defineFastMethod("shift", callbackFactory
0122: .getFastMethod("shift"));
0123: arrayc.defineFastMethod("unshift", callbackFactory
0124: .getFastOptMethod("unshift_m"));
0125: arrayc.defineFastMethod("insert", callbackFactory
0126: .getFastOptMethod("insert"));
0127: arrayc.defineMethod("each", callbackFactory.getMethod("each"));
0128: arrayc.defineMethod("each_index", callbackFactory
0129: .getMethod("each_index"));
0130: arrayc.defineMethod("reverse_each", callbackFactory
0131: .getMethod("reverse_each"));
0132: arrayc.defineFastMethod("length", callbackFactory
0133: .getFastMethod("length"));
0134: arrayc.defineAlias("size", "length");
0135: arrayc.defineFastMethod("empty?", callbackFactory
0136: .getFastMethod("empty_p"));
0137: arrayc.defineFastMethod("index", callbackFactory.getFastMethod(
0138: "index", RubyKernel.IRUBY_OBJECT));
0139: arrayc.defineFastMethod("rindex", callbackFactory
0140: .getFastMethod("rindex", RubyKernel.IRUBY_OBJECT));
0141: arrayc.defineFastMethod("indexes", callbackFactory
0142: .getFastOptMethod("indexes"));
0143: arrayc.defineFastMethod("indices", callbackFactory
0144: .getFastOptMethod("indexes"));
0145: arrayc.defineFastMethod("join", callbackFactory
0146: .getFastOptMethod("join_m"));
0147: arrayc.defineFastMethod("reverse", callbackFactory
0148: .getFastMethod("reverse"));
0149: arrayc.defineFastMethod("reverse!", callbackFactory
0150: .getFastMethod("reverse_bang"));
0151: arrayc.defineMethod("sort", callbackFactory.getMethod("sort"));
0152: arrayc.defineMethod("sort!", callbackFactory
0153: .getMethod("sort_bang"));
0154: arrayc.defineMethod("collect", callbackFactory
0155: .getMethod("collect"));
0156: arrayc.defineMethod("collect!", callbackFactory
0157: .getMethod("collect_bang"));
0158: arrayc
0159: .defineMethod("map", callbackFactory
0160: .getMethod("collect"));
0161: arrayc.defineMethod("map!", callbackFactory
0162: .getMethod("collect_bang"));
0163: arrayc.defineMethod("select", callbackFactory
0164: .getMethod("select"));
0165: arrayc.defineFastMethod("values_at", callbackFactory
0166: .getFastOptMethod("values_at"));
0167: arrayc.defineMethod("delete", callbackFactory.getMethod(
0168: "delete", RubyKernel.IRUBY_OBJECT));
0169: arrayc.defineFastMethod("delete_at", callbackFactory
0170: .getFastMethod("delete_at", RubyKernel.IRUBY_OBJECT));
0171: arrayc.defineMethod("delete_if", callbackFactory
0172: .getMethod("delete_if"));
0173: arrayc.defineMethod("reject", callbackFactory
0174: .getMethod("reject"));
0175: arrayc.defineMethod("reject!", callbackFactory
0176: .getMethod("reject_bang"));
0177: arrayc.defineMethod("zip", callbackFactory.getOptMethod("zip"));
0178: arrayc.defineFastMethod("transpose", callbackFactory
0179: .getFastMethod("transpose"));
0180: arrayc.defineFastMethod("replace", callbackFactory
0181: .getFastMethod("replace", RubyKernel.IRUBY_OBJECT));
0182: arrayc.defineFastMethod("clear", callbackFactory
0183: .getFastMethod("rb_clear"));
0184: arrayc.defineMethod("fill", callbackFactory
0185: .getOptMethod("fill"));
0186: arrayc.defineFastMethod("include?", callbackFactory
0187: .getFastMethod("include_p", RubyKernel.IRUBY_OBJECT));
0188: arrayc.defineFastMethod("<=>", callbackFactory.getFastMethod(
0189: "op_cmp", RubyKernel.IRUBY_OBJECT));
0190:
0191: arrayc.defineFastMethod("slice", callbackFactory
0192: .getFastOptMethod("aref"));
0193: arrayc.defineFastMethod("slice!", callbackFactory
0194: .getFastOptMethod("slice_bang"));
0195:
0196: arrayc.defineFastMethod("assoc", callbackFactory.getFastMethod(
0197: "assoc", RubyKernel.IRUBY_OBJECT));
0198: arrayc.defineFastMethod("rassoc", callbackFactory
0199: .getFastMethod("rassoc", RubyKernel.IRUBY_OBJECT));
0200:
0201: arrayc.defineFastMethod("+", callbackFactory.getFastMethod(
0202: "op_plus", RubyKernel.IRUBY_OBJECT));
0203: arrayc.defineFastMethod("*", callbackFactory.getFastMethod(
0204: "op_times", RubyKernel.IRUBY_OBJECT));
0205:
0206: arrayc.defineFastMethod("-", callbackFactory.getFastMethod(
0207: "op_diff", RubyKernel.IRUBY_OBJECT));
0208: arrayc.defineFastMethod("&", callbackFactory.getFastMethod(
0209: "op_and", RubyKernel.IRUBY_OBJECT));
0210: arrayc.defineFastMethod("|", callbackFactory.getFastMethod(
0211: "op_or", RubyKernel.IRUBY_OBJECT));
0212:
0213: arrayc.defineFastMethod("uniq", callbackFactory
0214: .getFastMethod("uniq"));
0215: arrayc.defineFastMethod("uniq!", callbackFactory
0216: .getFastMethod("uniq_bang"));
0217: arrayc.defineFastMethod("compact", callbackFactory
0218: .getFastMethod("compact"));
0219: arrayc.defineFastMethod("compact!", callbackFactory
0220: .getFastMethod("compact_bang"));
0221:
0222: arrayc.defineFastMethod("flatten", callbackFactory
0223: .getFastMethod("flatten"));
0224: arrayc.defineFastMethod("flatten!", callbackFactory
0225: .getFastMethod("flatten_bang"));
0226:
0227: arrayc.defineFastMethod("nitems", callbackFactory
0228: .getFastMethod("nitems"));
0229:
0230: arrayc.defineFastMethod("pack", callbackFactory.getFastMethod(
0231: "pack", RubyKernel.IRUBY_OBJECT));
0232:
0233: return arrayc;
0234: }
0235:
0236: private static ObjectAllocator ARRAY_ALLOCATOR = new ObjectAllocator() {
0237: public IRubyObject allocate(Ruby runtime, RubyClass klass) {
0238: return new RubyArray(runtime, klass);
0239: }
0240: };
0241:
0242: public static final byte OP_PLUS_SWITCHVALUE = 1;
0243: public static final byte AREF_SWITCHVALUE = 2;
0244: public static final byte ASET_SWITCHVALUE = 3;
0245: public static final byte POP_SWITCHVALUE = 4;
0246: public static final byte PUSH_SWITCHVALUE = 5;
0247: public static final byte NIL_P_SWITCHVALUE = 6;
0248: public static final byte EQUALEQUAL_SWITCHVALUE = 7;
0249: public static final byte UNSHIFT_SWITCHVALUE = 8;
0250: public static final byte OP_LSHIFT_SWITCHVALUE = 9;
0251: public static final byte EMPTY_P_SWITCHVALUE = 10;
0252: public static final byte TO_S_SWITCHVALUE = 11;
0253: public static final byte AT_SWITCHVALUE = 12;
0254: public static final byte TO_ARY_SWITCHVALUE = 13;
0255: public static final byte TO_A_SWITCHVALUE = 14;
0256: public static final byte HASH_SWITCHVALUE = 15;
0257: public static final byte OP_TIMES_SWITCHVALUE = 16;
0258: public static final byte OP_SPACESHIP_SWITCHVALUE = 17;
0259: public static final byte LENGTH_SWITCHVALUE = 18;
0260: public static final byte LAST_SWITCHVALUE = 19;
0261: public static final byte SHIFT_SWITCHVALUE = 20;
0262: public static final byte INSPECT_SWITCHVALUE = 21;
0263:
0264: public IRubyObject callMethod(ThreadContext context,
0265: RubyModule rubyclass, int methodIndex, String name,
0266: IRubyObject[] args, CallType callType, Block block) {
0267: // If tracing is on, don't do STI dispatch
0268: if (context.getRuntime().hasEventHooks())
0269: return super .callMethod(context, rubyclass, name, args,
0270: callType, block);
0271:
0272: switch (getRuntime().getSelectorTable().table[rubyclass.index][methodIndex]) {
0273: case OP_PLUS_SWITCHVALUE:
0274: if (args.length != 1)
0275: throw context.getRuntime().newArgumentError(
0276: "wrong number of arguments(" + args.length
0277: + " for " + 1 + ")");
0278: return op_plus(args[0]);
0279: case AREF_SWITCHVALUE:
0280: return aref(args);
0281: case ASET_SWITCHVALUE:
0282: return aset(args);
0283: case POP_SWITCHVALUE:
0284: if (args.length != 0)
0285: throw context.getRuntime().newArgumentError(
0286: "wrong number of arguments(" + args.length
0287: + " for " + 0 + ")");
0288: return pop();
0289: case PUSH_SWITCHVALUE:
0290: return push_m(args);
0291: case NIL_P_SWITCHVALUE:
0292: if (args.length != 0)
0293: throw context.getRuntime().newArgumentError(
0294: "wrong number of arguments(" + args.length
0295: + " for " + 0 + ")");
0296: return nil_p();
0297: case EQUALEQUAL_SWITCHVALUE:
0298: if (args.length != 1)
0299: throw context.getRuntime().newArgumentError(
0300: "wrong number of arguments(" + args.length
0301: + " for " + 1 + ")");
0302: return op_equal(args[0]);
0303: case UNSHIFT_SWITCHVALUE:
0304: return unshift_m(args);
0305: case OP_LSHIFT_SWITCHVALUE:
0306: if (args.length != 1)
0307: throw context.getRuntime().newArgumentError(
0308: "wrong number of arguments(" + args.length
0309: + " for " + 1 + ")");
0310: return append(args[0]);
0311: case EMPTY_P_SWITCHVALUE:
0312: if (args.length != 0)
0313: throw context.getRuntime().newArgumentError(
0314: "wrong number of arguments(" + args.length
0315: + " for " + 0 + ")");
0316: return empty_p();
0317: case TO_S_SWITCHVALUE:
0318: if (args.length != 0)
0319: throw context.getRuntime().newArgumentError(
0320: "wrong number of arguments(" + args.length
0321: + " for " + 0 + ")");
0322: return to_s();
0323: case AT_SWITCHVALUE:
0324: if (args.length != 1)
0325: throw context.getRuntime().newArgumentError(
0326: "wrong number of arguments(" + args.length
0327: + " for " + 1 + ")");
0328: return at(args[0]);
0329: case TO_ARY_SWITCHVALUE:
0330: if (args.length != 0)
0331: throw context.getRuntime().newArgumentError(
0332: "wrong number of arguments(" + args.length
0333: + " for " + 0 + ")");
0334: return to_ary();
0335: case TO_A_SWITCHVALUE:
0336: if (args.length != 0)
0337: throw context.getRuntime().newArgumentError(
0338: "wrong number of arguments(" + args.length
0339: + " for " + 0 + ")");
0340: return to_a();
0341: case HASH_SWITCHVALUE:
0342: if (args.length != 0)
0343: throw context.getRuntime().newArgumentError(
0344: "wrong number of arguments(" + args.length
0345: + " for " + 0 + ")");
0346: return hash();
0347: case OP_TIMES_SWITCHVALUE:
0348: if (args.length != 1)
0349: throw context.getRuntime().newArgumentError(
0350: "wrong number of arguments(" + args.length
0351: + " for " + 1 + ")");
0352: return op_times(args[0]);
0353: case OP_SPACESHIP_SWITCHVALUE:
0354: if (args.length != 1)
0355: throw context.getRuntime().newArgumentError(
0356: "wrong number of arguments(" + args.length
0357: + " for " + 1 + ")");
0358: return op_cmp(args[0]);
0359: case LENGTH_SWITCHVALUE:
0360: if (args.length != 0)
0361: throw context.getRuntime().newArgumentError(
0362: "wrong number of arguments(" + args.length
0363: + " for " + 0 + ")");
0364: return length();
0365: case LAST_SWITCHVALUE:
0366: return last(args);
0367: case SHIFT_SWITCHVALUE:
0368: if (args.length != 0)
0369: throw context.getRuntime().newArgumentError(
0370: "wrong number of arguments(" + args.length
0371: + " for " + 0 + ")");
0372: return shift();
0373: case INSPECT_SWITCHVALUE:
0374: if (args.length != 0)
0375: throw context.getRuntime().newArgumentError(
0376: "wrong number of arguments(" + args.length
0377: + " for " + 0 + ")");
0378: return inspect();
0379: case 0:
0380: default:
0381: return super .callMethod(context, rubyclass, name, args,
0382: callType, block);
0383: }
0384: }
0385:
0386: public int getNativeTypeIndex() {
0387: return ClassIndex.ARRAY;
0388: }
0389:
0390: /** rb_ary_s_create
0391: *
0392: */
0393: public static IRubyObject create(IRubyObject klass,
0394: IRubyObject[] args, Block block) {
0395: RubyArray arr = (RubyArray) ((RubyClass) klass).allocate();
0396: arr.callInit(IRubyObject.NULL_ARRAY, block);
0397:
0398: if (args.length > 0) {
0399: arr.alloc(args.length);
0400: System.arraycopy(args, 0, arr.values, 0, args.length);
0401: arr.realLength = args.length;
0402: }
0403: return arr;
0404: }
0405:
0406: /** rb_ary_new2
0407: *
0408: */
0409: public static final RubyArray newArray(final Ruby runtime,
0410: final long len) {
0411: return new RubyArray(runtime, len);
0412: }
0413:
0414: public static final RubyArray newArrayLight(final Ruby runtime,
0415: final long len) {
0416: return new RubyArray(runtime, len, false);
0417: }
0418:
0419: /** rb_ary_new
0420: *
0421: */
0422: public static final RubyArray newArray(final Ruby runtime) {
0423: return new RubyArray(runtime, ARRAY_DEFAULT_SIZE);
0424: }
0425:
0426: /** rb_ary_new
0427: *
0428: */
0429: public static final RubyArray newArrayLight(final Ruby runtime) {
0430: /* Ruby arrays default to holding 16 elements, so we create an
0431: * ArrayList of the same size if we're not told otherwise
0432: */
0433: RubyArray arr = new RubyArray(runtime, false);
0434: arr.alloc(ARRAY_DEFAULT_SIZE);
0435: return arr;
0436: }
0437:
0438: public static RubyArray newArray(Ruby runtime, IRubyObject obj) {
0439: return new RubyArray(runtime, new IRubyObject[] { obj });
0440: }
0441:
0442: /** rb_assoc_new
0443: *
0444: */
0445: public static RubyArray newArray(Ruby runtime, IRubyObject car,
0446: IRubyObject cdr) {
0447: return new RubyArray(runtime, new IRubyObject[] { car, cdr });
0448: }
0449:
0450: /** rb_ary_new4, rb_ary_new3
0451: *
0452: */
0453: public static RubyArray newArray(Ruby runtime, IRubyObject[] args) {
0454: RubyArray arr = new RubyArray(runtime, args.length);
0455: System.arraycopy(args, 0, arr.values, 0, args.length);
0456: arr.realLength = args.length;
0457: return arr;
0458: }
0459:
0460: public static RubyArray newArrayNoCopy(Ruby runtime,
0461: IRubyObject[] args) {
0462: return new RubyArray(runtime, args);
0463: }
0464:
0465: public static RubyArray newArrayNoCopyLight(Ruby runtime,
0466: IRubyObject[] args) {
0467: RubyArray arr = new RubyArray(runtime, false);
0468: arr.values = args;
0469: arr.realLength = args.length;
0470: return arr;
0471: }
0472:
0473: public static RubyArray newArray(Ruby runtime, Collection collection) {
0474: RubyArray arr = new RubyArray(runtime, collection.size());
0475: collection.toArray(arr.values);
0476: arr.realLength = arr.values.length;
0477: return arr;
0478: }
0479:
0480: public static final int ARRAY_DEFAULT_SIZE = 16;
0481:
0482: private IRubyObject[] values;
0483: private boolean tmpLock = false;
0484: private boolean shared = false;
0485:
0486: private int begin = 0;
0487: private int realLength = 0;
0488:
0489: /*
0490: * plain internal array assignment
0491: */
0492: private RubyArray(Ruby runtime, IRubyObject[] vals) {
0493: super (runtime, runtime.getArray());
0494: values = vals;
0495: realLength = vals.length;
0496: }
0497:
0498: /* rb_ary_new2
0499: * just allocates the internal array
0500: */
0501: private RubyArray(Ruby runtime, long length) {
0502: super (runtime, runtime.getArray());
0503: checkLength(length);
0504: alloc((int) length);
0505: }
0506:
0507: private RubyArray(Ruby runtime, long length, boolean objectspace) {
0508: super (runtime, runtime.getArray(), objectspace);
0509: checkLength(length);
0510: alloc((int) length);
0511: }
0512:
0513: /* rb_ary_new3, rb_ary_new4
0514: * allocates the internal array of size length and copies the 'length' elements
0515: */
0516: public RubyArray(Ruby runtime, long length, IRubyObject[] vals) {
0517: super (runtime, runtime.getArray());
0518: checkLength(length);
0519: int ilength = (int) length;
0520: alloc(ilength);
0521: if (ilength > 0 && vals.length > 0)
0522: System.arraycopy(vals, 0, values, 0, ilength);
0523:
0524: realLength = ilength;
0525: }
0526:
0527: /* NEWOBJ and OBJSETUP equivalent
0528: * fastest one, for shared arrays, optional objectspace
0529: */
0530: private RubyArray(Ruby runtime, boolean objectSpace) {
0531: super (runtime, runtime.getArray(), objectSpace);
0532: }
0533:
0534: private RubyArray(Ruby runtime) {
0535: super (runtime, runtime.getArray());
0536: alloc(ARRAY_DEFAULT_SIZE);
0537: }
0538:
0539: public RubyArray(Ruby runtime, RubyClass klass) {
0540: super (runtime, klass);
0541: alloc(ARRAY_DEFAULT_SIZE);
0542: }
0543:
0544: /* Array constructors taking the MetaClass to fulfil MRI Array subclass behaviour
0545: *
0546: */
0547: private RubyArray(Ruby runtime, RubyClass klass, int length) {
0548: super (runtime, klass);
0549: alloc(length);
0550: }
0551:
0552: private RubyArray(Ruby runtime, RubyClass klass, long length) {
0553: super (runtime, klass);
0554: checkLength(length);
0555: alloc((int) length);
0556: }
0557:
0558: private RubyArray(Ruby runtime, RubyClass klass, long length,
0559: boolean objectspace) {
0560: super (runtime, klass, objectspace);
0561: checkLength(length);
0562: alloc((int) length);
0563: }
0564:
0565: private RubyArray(Ruby runtime, RubyClass klass, boolean objectSpace) {
0566: super (runtime, klass, objectSpace);
0567: }
0568:
0569: private RubyArray(Ruby runtime, RubyClass klass, RubyArray original) {
0570: super (runtime, klass);
0571: realLength = original.realLength;
0572: alloc(realLength);
0573: System.arraycopy(original.values, original.begin, values, 0,
0574: realLength);
0575: }
0576:
0577: private final IRubyObject[] reserve(int length) {
0578: return new IRubyObject[length];
0579: }
0580:
0581: private final void alloc(int length) {
0582: values = new IRubyObject[length];
0583: }
0584:
0585: private final void realloc(int newLength) {
0586: IRubyObject[] reallocated = new IRubyObject[newLength];
0587: System.arraycopy(values, 0, reallocated, 0,
0588: newLength > realLength ? realLength : newLength);
0589: values = reallocated;
0590: }
0591:
0592: private final void checkLength(long length) {
0593: if (length < 0) {
0594: throw getRuntime().newArgumentError(
0595: "negative array size (or size too big)");
0596: }
0597:
0598: if (length >= Integer.MAX_VALUE) {
0599: throw getRuntime().newArgumentError("array size too big");
0600: }
0601: }
0602:
0603: /** Getter for property list.
0604: * @return Value of property list.
0605: */
0606: public List getList() {
0607: return Arrays.asList(toJavaArray());
0608: }
0609:
0610: public int getLength() {
0611: return realLength;
0612: }
0613:
0614: public IRubyObject[] toJavaArray() {
0615: IRubyObject[] copy = reserve(realLength);
0616: System.arraycopy(values, begin, copy, 0, realLength);
0617: return copy;
0618: }
0619:
0620: public IRubyObject[] toJavaArrayUnsafe() {
0621: return !shared ? values : toJavaArray();
0622: }
0623:
0624: public IRubyObject[] toJavaArrayMaybeUnsafe() {
0625: return (!shared && begin == 0 && values.length == realLength) ? values
0626: : toJavaArray();
0627: }
0628:
0629: /** rb_ary_make_shared
0630: *
0631: */
0632: private final RubyArray makeShared(int beg, int len,
0633: RubyClass klass, boolean objectSpace) {
0634: RubyArray sharedArray = new RubyArray(getRuntime(), klass,
0635: objectSpace);
0636: shared = true;
0637: sharedArray.values = values;
0638: sharedArray.shared = true;
0639: sharedArray.begin = beg;
0640: sharedArray.realLength = len;
0641: return sharedArray;
0642: }
0643:
0644: /** rb_ary_modify_check
0645: *
0646: */
0647: private final void modifyCheck() {
0648: testFrozen("array");
0649:
0650: if (tmpLock) {
0651: throw getRuntime().newTypeError(
0652: "can't modify array during iteration");
0653: }
0654: if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
0655: throw getRuntime().newSecurityError(
0656: "Insecure: can't modify array");
0657: }
0658: }
0659:
0660: /** rb_ary_modify
0661: *
0662: */
0663: private final void modify() {
0664: modifyCheck();
0665: if (shared) {
0666: IRubyObject[] vals = reserve(realLength);
0667: shared = false;
0668: System.arraycopy(values, begin, vals, 0, realLength);
0669: begin = 0;
0670: values = vals;
0671: }
0672: }
0673:
0674: /* ================
0675: * Instance Methods
0676: * ================
0677: */
0678:
0679: /** rb_ary_initialize
0680: *
0681: */
0682: public IRubyObject initialize(IRubyObject[] args, Block block) {
0683: int argc = Arity.checkArgumentCount(getRuntime(), args, 0, 2);
0684: Ruby runtime = getRuntime();
0685:
0686: if (argc == 0) {
0687: realLength = 0;
0688: if (block.isGiven())
0689: runtime.getWarnings().warn("given block not used");
0690:
0691: return this ;
0692: }
0693:
0694: if (argc == 1 && !(args[0] instanceof RubyFixnum)) {
0695: IRubyObject val = args[0].checkArrayType();
0696: if (!val.isNil()) {
0697: replace(val);
0698: return this ;
0699: }
0700: }
0701:
0702: long len = RubyNumeric.num2long(args[0]);
0703:
0704: if (len < 0)
0705: throw runtime.newArgumentError("negative array size");
0706:
0707: if (len >= Integer.MAX_VALUE)
0708: throw runtime.newArgumentError("array size too big");
0709:
0710: int ilen = (int) len;
0711:
0712: modify();
0713:
0714: if (ilen > values.length)
0715: values = reserve(ilen);
0716:
0717: if (block.isGiven()) {
0718: if (argc == 2) {
0719: runtime.getWarnings().warn(
0720: "block supersedes default value argument");
0721: }
0722:
0723: ThreadContext context = runtime.getCurrentContext();
0724: for (int i = 0; i < ilen; i++) {
0725: store(i, block.yield(context,
0726: new RubyFixnum(runtime, i)));
0727: realLength = i + 1;
0728: }
0729: } else {
0730: Arrays.fill(values, 0, ilen, (argc == 2) ? args[1]
0731: : runtime.getNil());
0732: realLength = ilen;
0733: }
0734: return this ;
0735: }
0736:
0737: /** rb_ary_replace
0738: *
0739: */
0740: public IRubyObject replace(IRubyObject orig) {
0741: modifyCheck();
0742:
0743: RubyArray origArr = orig.convertToArray();
0744:
0745: if (this == orig)
0746: return this ;
0747:
0748: origArr.shared = true;
0749: values = origArr.values;
0750: realLength = origArr.realLength;
0751: begin = origArr.begin;
0752: shared = true;
0753:
0754: return this ;
0755: }
0756:
0757: /** rb_ary_to_s
0758: *
0759: */
0760: public IRubyObject to_s() {
0761: if (realLength == 0)
0762: return getRuntime().newString("");
0763:
0764: return join(getRuntime().getGlobalVariables().get("$,"));
0765: }
0766:
0767: public boolean includes(IRubyObject item) {
0768: final ThreadContext context = getRuntime().getCurrentContext();
0769: int begin = this .begin;
0770:
0771: for (int i = begin; i < begin + realLength; i++) {
0772: if (values[i].equalInternal(context, item).isTrue())
0773: return true;
0774: }
0775:
0776: return false;
0777: }
0778:
0779: /** rb_ary_hash
0780: *
0781: */
0782: public RubyFixnum hash() {
0783: int h = realLength;
0784:
0785: Ruby runtime = getRuntime();
0786: ThreadContext context = runtime.getCurrentContext();
0787: int begin = this .begin;
0788: for (int i = begin; i < begin + realLength; i++) {
0789: h = (h << 1) | (h < 0 ? 1 : 0);
0790: h ^= RubyNumeric.num2long(values[i].callMethod(context,
0791: MethodIndex.HASH, "hash"));
0792: }
0793:
0794: return runtime.newFixnum(h);
0795: }
0796:
0797: /** rb_ary_store
0798: *
0799: */
0800: public final IRubyObject store(long index, IRubyObject value) {
0801: if (index < 0) {
0802: index += realLength;
0803: if (index < 0) {
0804: throw getRuntime().newIndexError(
0805: "index " + (index - realLength)
0806: + " out of array");
0807: }
0808: }
0809:
0810: modify();
0811:
0812: if (index >= realLength) {
0813: if (index >= values.length) {
0814: long newLength = values.length >> 1;
0815:
0816: if (newLength < ARRAY_DEFAULT_SIZE)
0817: newLength = ARRAY_DEFAULT_SIZE;
0818:
0819: newLength += index;
0820: if (newLength >= Integer.MAX_VALUE) {
0821: throw getRuntime()
0822: .newArgumentError("index too big");
0823: }
0824: realloc((int) newLength);
0825: }
0826: if (index != realLength)
0827: Arrays.fill(values, realLength, (int) index + 1,
0828: getRuntime().getNil());
0829:
0830: realLength = (int) index + 1;
0831: }
0832:
0833: values[(int) index] = value;
0834: return value;
0835: }
0836:
0837: /** rb_ary_elt - faster
0838: *
0839: */
0840: private final IRubyObject elt(long offset) {
0841: if (realLength == 0 || offset < 0 || offset >= realLength)
0842: return getRuntime().getNil();
0843:
0844: return values[begin + (int) offset];
0845: }
0846:
0847: /** rb_ary_elt - faster
0848: *
0849: */
0850: private final IRubyObject elt(int offset) {
0851: if (realLength == 0 || offset < 0 || offset >= realLength)
0852: return getRuntime().getNil();
0853:
0854: return values[begin + offset];
0855: }
0856:
0857: /** rb_ary_elt - faster
0858: *
0859: */
0860: private final IRubyObject elt_f(long offset) {
0861: if (realLength == 0 || offset >= realLength)
0862: return getRuntime().getNil();
0863:
0864: return values[begin + (int) offset];
0865: }
0866:
0867: /** rb_ary_elt - faster
0868: *
0869: */
0870: private final IRubyObject elt_f(int offset) {
0871: if (realLength == 0 || offset >= realLength)
0872: return getRuntime().getNil();
0873:
0874: return values[begin + offset];
0875: }
0876:
0877: /** rb_ary_entry
0878: *
0879: */
0880: public final IRubyObject entry(long offset) {
0881: return (offset < 0) ? elt(offset + realLength) : elt_f(offset);
0882: }
0883:
0884: /** rb_ary_entry
0885: *
0886: */
0887: public final IRubyObject entry(int offset) {
0888: return (offset < 0) ? elt(offset + realLength) : elt_f(offset);
0889: }
0890:
0891: public final IRubyObject eltInternal(int offset) {
0892: return values[begin + offset];
0893: }
0894:
0895: public final IRubyObject eltInternalSet(int offset, IRubyObject item) {
0896: return values[begin + offset] = item;
0897: }
0898:
0899: /** rb_ary_fetch
0900: *
0901: */
0902: public IRubyObject fetch(IRubyObject[] args, Block block) {
0903: if (Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2
0904: && block.isGiven()) {
0905: getRuntime().getWarnings().warn(
0906: "block supersedes default value argument");
0907: }
0908:
0909: long index = RubyNumeric.num2long(args[0]);
0910:
0911: if (index < 0)
0912: index += realLength;
0913:
0914: if (index < 0 || index >= realLength) {
0915: if (block.isGiven())
0916: return block.yield(getRuntime().getCurrentContext(),
0917: args[0]);
0918:
0919: if (args.length == 1) {
0920: throw getRuntime().newIndexError(
0921: "index " + index + " out of array");
0922: }
0923:
0924: return args[1];
0925: }
0926:
0927: return values[begin + (int) index];
0928: }
0929:
0930: /** rb_ary_to_ary
0931: *
0932: */
0933: private static RubyArray aryToAry(IRubyObject obj) {
0934: if (obj instanceof RubyArray)
0935: return (RubyArray) obj;
0936:
0937: if (obj.respondsTo("to_ary"))
0938: return obj.convertToArray();
0939:
0940: RubyArray arr = new RubyArray(obj.getRuntime(), false); // possibly should not in object space
0941: arr.alloc(1);
0942: arr.values[0] = obj;
0943: arr.realLength = 1;
0944: return arr;
0945: }
0946:
0947: /** rb_ary_splice
0948: *
0949: */
0950: private final void splice(long beg, long len, IRubyObject rpl) {
0951: int rlen;
0952:
0953: if (len < 0)
0954: throw getRuntime().newIndexError(
0955: "negative length (" + len + ")");
0956:
0957: if (beg < 0) {
0958: beg += realLength;
0959: if (beg < 0) {
0960: beg -= realLength;
0961: throw getRuntime().newIndexError(
0962: "index " + beg + " out of array");
0963: }
0964: }
0965:
0966: if (beg + len > realLength)
0967: len = realLength - beg;
0968:
0969: RubyArray rplArr;
0970: if (rpl == null || rpl.isNil()) {
0971: rplArr = null;
0972: rlen = 0;
0973: } else {
0974: rplArr = aryToAry(rpl);
0975: rlen = rplArr.realLength;
0976: }
0977:
0978: modify();
0979:
0980: if (beg >= realLength) {
0981: len = beg + rlen;
0982:
0983: if (len >= values.length) {
0984: int tryNewLength = values.length + (values.length >> 1);
0985:
0986: realloc(len > tryNewLength ? (int) len : tryNewLength);
0987: }
0988:
0989: Arrays.fill(values, realLength, (int) beg, getRuntime()
0990: .getNil());
0991: if (rlen > 0) {
0992: System.arraycopy(rplArr.values, rplArr.begin, values,
0993: (int) beg, rlen);
0994: }
0995: realLength = (int) len;
0996: } else {
0997: long alen;
0998:
0999: if (beg + len > realLength)
1000: len = realLength - beg;
1001:
1002: alen = realLength + rlen - len;
1003: if (alen >= values.length) {
1004: int tryNewLength = values.length + (values.length >> 1);
1005:
1006: realloc(alen > tryNewLength ? (int) alen : tryNewLength);
1007: }
1008:
1009: if (len != rlen) {
1010: System.arraycopy(values, (int) (beg + len), values,
1011: (int) beg + rlen, realLength
1012: - (int) (beg + len));
1013: realLength = (int) alen;
1014: }
1015:
1016: if (rlen > 0) {
1017: System.arraycopy(rplArr.values, rplArr.begin, values,
1018: (int) beg, rlen);
1019: }
1020: }
1021: }
1022:
1023: /** rb_ary_insert
1024: *
1025: */
1026: public IRubyObject insert(IRubyObject[] args) {
1027: if (args.length == 1)
1028: return this ;
1029:
1030: if (args.length < 1) {
1031: throw getRuntime().newArgumentError(
1032: "wrong number of arguments (at least 1)");
1033: }
1034:
1035: long pos = RubyNumeric.num2long(args[0]);
1036:
1037: if (pos == -1)
1038: pos = realLength;
1039: if (pos < 0)
1040: pos++;
1041:
1042: RubyArray inserted = new RubyArray(getRuntime(), false);
1043: inserted.values = args;
1044: inserted.begin = 1;
1045: inserted.realLength = args.length - 1;
1046:
1047: splice(pos, 0, inserted); // rb_ary_new4
1048:
1049: return this ;
1050: }
1051:
1052: /** rb_ary_dup
1053: *
1054: */
1055: private final RubyArray aryDup() {
1056: RubyArray dup = new RubyArray(getRuntime(), getMetaClass(),
1057: this );
1058: dup.setTaint(isTaint()); // from DUP_SETUP
1059: // rb_copy_generic_ivar from DUP_SETUP here ...unlikely..
1060: return dup;
1061: }
1062:
1063: /** rb_ary_transpose
1064: *
1065: */
1066: public RubyArray transpose() {
1067: RubyArray tmp, result = null;
1068:
1069: int alen = realLength;
1070: if (alen == 0)
1071: return aryDup();
1072:
1073: Ruby runtime = getRuntime();
1074: int elen = -1;
1075: int end = begin + alen;
1076: for (int i = begin; i < end; i++) {
1077: tmp = elt(i).convertToArray();
1078: if (elen < 0) {
1079: elen = tmp.realLength;
1080: result = new RubyArray(runtime, elen);
1081: for (int j = 0; j < elen; j++) {
1082: result.store(j, new RubyArray(runtime, alen));
1083: }
1084: } else if (elen != tmp.realLength) {
1085: throw runtime.newIndexError("element size differs ("
1086: + tmp.realLength + " should be " + elen + ")");
1087: }
1088: for (int j = 0; j < elen; j++) {
1089: ((RubyArray) result.elt(j))
1090: .store(i - begin, tmp.elt(j));
1091: }
1092: }
1093: return result;
1094: }
1095:
1096: /** rb_values_at (internal)
1097: *
1098: */
1099: private final IRubyObject values_at(long olen, IRubyObject[] args) {
1100: RubyArray result = new RubyArray(getRuntime(), args.length);
1101:
1102: for (int i = 0; i < args.length; i++) {
1103: if (args[i] instanceof RubyFixnum) {
1104: result.append(entry(((RubyFixnum) args[i])
1105: .getLongValue()));
1106: continue;
1107: }
1108:
1109: long beglen[];
1110: if (!(args[i] instanceof RubyRange)) {
1111: } else if ((beglen = ((RubyRange) args[i]).begLen(olen, 0)) == null) {
1112: continue;
1113: } else {
1114: int beg = (int) beglen[0];
1115: int len = (int) beglen[1];
1116: int end = begin + len;
1117: for (int j = begin; j < end; j++) {
1118: result.append(entry(j + beg));
1119: }
1120: continue;
1121: }
1122: result.append(entry(RubyNumeric.num2long(args[i])));
1123: }
1124:
1125: return result;
1126: }
1127:
1128: /** rb_values_at
1129: *
1130: */
1131: public IRubyObject values_at(IRubyObject[] args) {
1132: return values_at(realLength, args);
1133: }
1134:
1135: /** rb_ary_subseq
1136: *
1137: */
1138: public IRubyObject subseq(long beg, long len) {
1139: if (beg > realLength || beg < 0 || len < 0)
1140: return getRuntime().getNil();
1141:
1142: if (beg + len > realLength) {
1143: len = realLength - beg;
1144:
1145: if (len < 0)
1146: len = 0;
1147: }
1148:
1149: if (len == 0)
1150: return new RubyArray(getRuntime(), getMetaClass(), 0);
1151:
1152: return makeShared(begin + (int) beg, (int) len, getMetaClass(),
1153: true);
1154: }
1155:
1156: /** rb_ary_subseq
1157: *
1158: */
1159: public IRubyObject subseqLight(long beg, long len) {
1160: if (beg > realLength || beg < 0 || len < 0)
1161: return getRuntime().getNil();
1162:
1163: if (beg + len > realLength) {
1164: len = realLength - beg;
1165:
1166: if (len < 0)
1167: len = 0;
1168: }
1169:
1170: if (len == 0)
1171: return new RubyArray(getRuntime(), getMetaClass(), 0, false);
1172:
1173: return makeShared(begin + (int) beg, (int) len, getMetaClass(),
1174: false);
1175: }
1176:
1177: /** rb_ary_length
1178: *
1179: */
1180: public RubyFixnum length() {
1181: return getRuntime().newFixnum(realLength);
1182: }
1183:
1184: /** rb_ary_push - specialized rb_ary_store
1185: *
1186: */
1187: public RubyArray append(IRubyObject item) {
1188: modify();
1189:
1190: if (realLength == values.length) {
1191: if (realLength == Integer.MAX_VALUE)
1192: throw getRuntime().newArgumentError("index too big");
1193:
1194: long newLength = values.length + (values.length >> 1);
1195: if (newLength > Integer.MAX_VALUE) {
1196: newLength = Integer.MAX_VALUE;
1197: } else if (newLength < ARRAY_DEFAULT_SIZE) {
1198: newLength = ARRAY_DEFAULT_SIZE;
1199: }
1200:
1201: realloc((int) newLength);
1202: }
1203:
1204: values[realLength++] = item;
1205: return this ;
1206: }
1207:
1208: /** rb_ary_push_m
1209: *
1210: */
1211: public RubyArray push_m(IRubyObject[] items) {
1212: for (int i = 0; i < items.length; i++) {
1213: append(items[i]);
1214: }
1215:
1216: return this ;
1217: }
1218:
1219: /** rb_ary_pop
1220: *
1221: */
1222: public IRubyObject pop() {
1223: modifyCheck();
1224:
1225: if (realLength == 0)
1226: return getRuntime().getNil();
1227:
1228: if (!shared) {
1229: int index = begin + --realLength;
1230: IRubyObject obj = values[index];
1231: values[index] = null;
1232: return obj;
1233: }
1234:
1235: return values[begin + --realLength];
1236: }
1237:
1238: /** rb_ary_shift
1239: *
1240: */
1241: public IRubyObject shift() {
1242: modifyCheck();
1243:
1244: if (realLength == 0)
1245: return getRuntime().getNil();
1246:
1247: IRubyObject obj = values[begin];
1248:
1249: if (!shared)
1250: shared = true;
1251:
1252: begin++;
1253: realLength--;
1254:
1255: return obj;
1256: }
1257:
1258: /** rb_ary_unshift
1259: *
1260: */
1261: public RubyArray unshift(IRubyObject item) {
1262: modify();
1263:
1264: if (realLength == values.length) {
1265: int newLength = values.length >> 1;
1266: if (newLength < ARRAY_DEFAULT_SIZE)
1267: newLength = ARRAY_DEFAULT_SIZE;
1268:
1269: newLength += values.length;
1270: realloc(newLength);
1271: }
1272: System.arraycopy(values, 0, values, 1, realLength);
1273:
1274: realLength++;
1275: values[0] = item;
1276:
1277: return this ;
1278: }
1279:
1280: /** rb_ary_unshift_m
1281: *
1282: */
1283: public RubyArray unshift_m(IRubyObject[] items) {
1284: long len = realLength;
1285:
1286: if (items.length == 0)
1287: return this ;
1288:
1289: store(len + items.length - 1, getRuntime().getNil());
1290:
1291: // it's safe to use zeroes here since modified by store()
1292: System.arraycopy(values, 0, values, items.length, (int) len);
1293: System.arraycopy(items, 0, values, 0, items.length);
1294:
1295: return this ;
1296: }
1297:
1298: /** rb_ary_includes
1299: *
1300: */
1301: public RubyBoolean include_p(IRubyObject item) {
1302: return getRuntime().newBoolean(includes(item));
1303: }
1304:
1305: /** rb_ary_frozen_p
1306: *
1307: */
1308: public RubyBoolean frozen() {
1309: return getRuntime().newBoolean(isFrozen() || tmpLock);
1310: }
1311:
1312: /** rb_ary_aref
1313: */
1314: public IRubyObject aref(IRubyObject[] args) {
1315: long beg, len;
1316:
1317: if (args.length == 1) {
1318: if (args[0] instanceof RubyFixnum)
1319: return entry(((RubyFixnum) args[0]).getLongValue());
1320: if (args[0] instanceof RubySymbol)
1321: throw getRuntime()
1322: .newTypeError("Symbol as array index");
1323:
1324: long[] beglen;
1325: if (!(args[0] instanceof RubyRange)) {
1326: } else if ((beglen = ((RubyRange) args[0]).begLen(
1327: realLength, 0)) == null) {
1328: return getRuntime().getNil();
1329: } else {
1330: beg = beglen[0];
1331: len = beglen[1];
1332: return subseq(beg, len);
1333: }
1334:
1335: return entry(RubyNumeric.num2long(args[0]));
1336: }
1337:
1338: if (args.length == 2) {
1339: if (args[0] instanceof RubySymbol) {
1340: throw getRuntime()
1341: .newTypeError("Symbol as array index");
1342: }
1343: beg = RubyNumeric.num2long(args[0]);
1344: len = RubyNumeric.num2long(args[1]);
1345:
1346: if (beg < 0)
1347: beg += realLength;
1348:
1349: return subseq(beg, len);
1350: }
1351:
1352: Arity.checkArgumentCount(getRuntime(), args, 1, 2);
1353: return null;
1354: }
1355:
1356: /** rb_ary_aset
1357: *
1358: */
1359: public IRubyObject aset(IRubyObject[] args) {
1360: if (args.length == 2) {
1361: if (args[0] instanceof RubyFixnum) {
1362: store(((RubyFixnum) args[0]).getLongValue(), args[1]);
1363: return args[1];
1364: }
1365: if (args[0] instanceof RubyRange) {
1366: long[] beglen = ((RubyRange) args[0]).begLen(
1367: realLength, 1);
1368: splice(beglen[0], beglen[1], args[1]);
1369: return args[1];
1370: }
1371: if (args[0] instanceof RubySymbol)
1372: throw getRuntime()
1373: .newTypeError("Symbol as array index");
1374:
1375: store(RubyNumeric.num2long(args[0]), args[1]);
1376: return args[1];
1377: }
1378:
1379: if (args.length == 3) {
1380: if (args[0] instanceof RubySymbol)
1381: throw getRuntime()
1382: .newTypeError("Symbol as array index");
1383: if (args[1] instanceof RubySymbol)
1384: throw getRuntime().newTypeError(
1385: "Symbol as subarray length");
1386:
1387: splice(RubyNumeric.num2long(args[0]), RubyNumeric
1388: .num2long(args[1]), args[2]);
1389: return args[2];
1390: }
1391:
1392: throw getRuntime()
1393: .newArgumentError(
1394: "wrong number of arguments (" + args.length
1395: + " for 2)");
1396: }
1397:
1398: /** rb_ary_at
1399: *
1400: */
1401: public IRubyObject at(IRubyObject pos) {
1402: return entry(RubyNumeric.num2long(pos));
1403: }
1404:
1405: /** rb_ary_concat
1406: *
1407: */
1408: public RubyArray concat(IRubyObject obj) {
1409: RubyArray ary = obj.convertToArray();
1410:
1411: if (ary.realLength > 0)
1412: splice(realLength, 0, ary);
1413:
1414: return this ;
1415: }
1416:
1417: /** rb_ary_inspect
1418: *
1419: */
1420: public IRubyObject inspect() {
1421: if (realLength == 0)
1422: return getRuntime().newString("[]");
1423:
1424: if (!getRuntime().registerInspecting(this ))
1425: return getRuntime().newString("[...]");
1426:
1427: RubyString s;
1428: try {
1429: StringBuffer buffer = new StringBuffer("[");
1430: Ruby runtime = getRuntime();
1431: ThreadContext context = runtime.getCurrentContext();
1432: boolean tainted = isTaint();
1433: for (int i = 0; i < realLength; i++) {
1434: s = RubyString.objAsString(values[begin + i]
1435: .callMethod(context, "inspect"));
1436:
1437: if (s.isTaint())
1438: tainted = true;
1439:
1440: if (i > 0)
1441: buffer.append(", ");
1442:
1443: buffer.append(s.toString());
1444: }
1445: buffer.append("]");
1446: if (tainted)
1447: setTaint(true);
1448:
1449: return runtime.newString(buffer.toString());
1450: } finally {
1451: getRuntime().unregisterInspecting(this );
1452: }
1453: }
1454:
1455: /** rb_ary_first
1456: *
1457: */
1458: public IRubyObject first(IRubyObject[] args) {
1459: if (args.length == 0) {
1460: if (realLength == 0)
1461: return getRuntime().getNil();
1462:
1463: return values[begin];
1464: }
1465:
1466: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1467: long n = RubyNumeric.num2long(args[0]);
1468: if (n > realLength) {
1469: n = realLength;
1470: } else if (n < 0) {
1471: throw getRuntime().newArgumentError(
1472: "negative array size (or size too big)");
1473: }
1474:
1475: return makeShared(begin, (int) n, getRuntime().getArray(), true);
1476: }
1477:
1478: /** rb_ary_last
1479: *
1480: */
1481: public IRubyObject last(IRubyObject[] args) {
1482: if (args.length == 0) {
1483: if (realLength == 0)
1484: return getRuntime().getNil();
1485:
1486: return values[begin + realLength - 1];
1487: }
1488:
1489: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1490: long n = RubyNumeric.num2long(args[0]);
1491: if (n > realLength) {
1492: n = realLength;
1493: } else if (n < 0) {
1494: throw getRuntime().newArgumentError(
1495: "negative array size (or size too big)");
1496: }
1497:
1498: return makeShared(begin + realLength - (int) n, (int) n,
1499: getRuntime().getArray(), true);
1500: }
1501:
1502: /** rb_ary_each
1503: *
1504: */
1505: public IRubyObject each(Block block) {
1506: ThreadContext context = getRuntime().getCurrentContext();
1507: if (shared) {
1508: for (int i = begin; i < begin + realLength; i++) {
1509: block.yield(context, values[i]);
1510: }
1511: } else {
1512: for (int i = 0; i < realLength; i++) {
1513: block.yield(context, values[i]);
1514: }
1515: }
1516: return this ;
1517: }
1518:
1519: /** rb_ary_each_index
1520: *
1521: */
1522: public IRubyObject each_index(Block block) {
1523: Ruby runtime = getRuntime();
1524: ThreadContext context = runtime.getCurrentContext();
1525: for (int i = 0; i < realLength; i++) {
1526: block.yield(context, runtime.newFixnum(i));
1527: }
1528: return this ;
1529: }
1530:
1531: /** rb_ary_reverse_each
1532: *
1533: */
1534: public IRubyObject reverse_each(Block block) {
1535: ThreadContext context = getRuntime().getCurrentContext();
1536:
1537: int len = realLength;
1538:
1539: while (len-- > 0) {
1540: block.yield(context, values[begin + len]);
1541:
1542: if (realLength < len)
1543: len = realLength;
1544: }
1545:
1546: return this ;
1547: }
1548:
1549: private final IRubyObject inspectJoin(IRubyObject sep) {
1550: IRubyObject result = join(sep);
1551: getRuntime().unregisterInspecting(this );
1552: return result;
1553: }
1554:
1555: /** rb_ary_join
1556: *
1557: */
1558: public RubyString join(IRubyObject sep) {
1559: if (realLength == 0)
1560: return getRuntime().newString("");
1561:
1562: boolean taint = isTaint() || sep.isTaint();
1563:
1564: long len = 1;
1565: for (int i = begin; i < begin + realLength; i++) {
1566: IRubyObject tmp = values[i].checkStringType();
1567: len += tmp.isNil() ? 10 : ((RubyString) tmp).getByteList()
1568: .length();
1569: }
1570:
1571: RubyString strSep = null;
1572: if (!sep.isNil()) {
1573: sep = strSep = sep.convertToString();
1574: len += strSep.getByteList().length() * (realLength - 1);
1575: }
1576:
1577: ByteList buf = new ByteList((int) len);
1578: Ruby runtime = getRuntime();
1579: for (int i = begin; i < begin + realLength; i++) {
1580: IRubyObject tmp = values[i];
1581: if (tmp instanceof RubyString) {
1582: // do nothing
1583: } else if (tmp instanceof RubyArray) {
1584: if (!runtime.registerInspecting(tmp)) {
1585: tmp = runtime.newString("[...]");
1586: } else {
1587: tmp = ((RubyArray) tmp).inspectJoin(sep);
1588: }
1589: } else {
1590: tmp = RubyString.objAsString(tmp);
1591: }
1592:
1593: if (i > begin && !sep.isNil())
1594: buf.append(strSep.getByteList());
1595:
1596: buf.append(tmp.asString().getByteList());
1597: taint |= tmp.isTaint();
1598: }
1599:
1600: RubyString result = runtime.newString(buf);
1601:
1602: if (taint)
1603: result.setTaint(true);
1604:
1605: return result;
1606: }
1607:
1608: /** rb_ary_join_m
1609: *
1610: */
1611: public RubyString join_m(IRubyObject[] args) {
1612: int argc = Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1613: IRubyObject sep = (argc == 1) ? args[0] : getRuntime()
1614: .getGlobalVariables().get("$,");
1615:
1616: return join(sep);
1617: }
1618:
1619: /** rb_ary_to_a
1620: *
1621: */
1622: public RubyArray to_a() {
1623: if (getMetaClass() != getRuntime().getArray()) {
1624: RubyArray dup = new RubyArray(getRuntime(), true);
1625:
1626: shared = true;
1627: dup.values = values;
1628: dup.realLength = realLength;
1629: dup.begin = begin;
1630: dup.shared = true;
1631: return dup;
1632: }
1633: return this ;
1634: }
1635:
1636: public IRubyObject to_ary() {
1637: return this ;
1638: }
1639:
1640: public RubyArray convertToArray() {
1641: return this ;
1642: }
1643:
1644: public IRubyObject checkArrayType() {
1645: return this ;
1646: }
1647:
1648: /** rb_ary_equal
1649: *
1650: */
1651: public IRubyObject op_equal(IRubyObject obj) {
1652: if (this == obj)
1653: return getRuntime().getTrue();
1654:
1655: if (!(obj instanceof RubyArray)) {
1656: if (!obj.respondsTo("to_ary")) {
1657: return getRuntime().getFalse();
1658: } else {
1659: return obj.equalInternal(getRuntime()
1660: .getCurrentContext(), this );
1661: }
1662: }
1663:
1664: RubyArray ary = (RubyArray) obj;
1665: if (realLength != ary.realLength)
1666: return getRuntime().getFalse();
1667:
1668: Ruby runtime = getRuntime();
1669: final ThreadContext context = runtime.getCurrentContext();
1670: for (long i = 0; i < realLength; i++) {
1671: if (!elt(i).equalInternal(context, ary.elt(i)).isTrue())
1672: return runtime.getFalse();
1673: }
1674: return runtime.getTrue();
1675: }
1676:
1677: /** rb_ary_eql
1678: *
1679: */
1680: public RubyBoolean eql_p(IRubyObject obj) {
1681: if (this == obj)
1682: return getRuntime().getTrue();
1683: if (!(obj instanceof RubyArray))
1684: return getRuntime().getFalse();
1685:
1686: RubyArray ary = (RubyArray) obj;
1687:
1688: if (realLength != ary.realLength)
1689: return getRuntime().getFalse();
1690:
1691: Ruby runtime = getRuntime();
1692: final ThreadContext context = runtime.getCurrentContext();
1693: for (int i = 0; i < realLength; i++) {
1694: if (!elt(i).eqlInternal(context, ary.elt(i)))
1695: return runtime.getFalse();
1696: }
1697: return runtime.getTrue();
1698: }
1699:
1700: /** rb_ary_compact_bang
1701: *
1702: */
1703: public IRubyObject compact_bang() {
1704: modify();
1705:
1706: int p = 0;
1707: int t = 0;
1708: int end = p + realLength;
1709:
1710: while (t < end) {
1711: if (values[t].isNil()) {
1712: t++;
1713: } else {
1714: values[p++] = values[t++];
1715: }
1716: }
1717:
1718: if (realLength == p)
1719: return getRuntime().getNil();
1720:
1721: realloc(p);
1722: realLength = p;
1723: return this ;
1724: }
1725:
1726: /** rb_ary_compact
1727: *
1728: */
1729: public IRubyObject compact() {
1730: RubyArray ary = aryDup();
1731: ary.compact_bang();
1732: return ary;
1733: }
1734:
1735: /** rb_ary_empty_p
1736: *
1737: */
1738: public IRubyObject empty_p() {
1739: return realLength == 0 ? getRuntime().getTrue() : getRuntime()
1740: .getFalse();
1741: }
1742:
1743: /** rb_ary_clear
1744: *
1745: */
1746: public IRubyObject rb_clear() {
1747: modifyCheck();
1748:
1749: if (shared) {
1750: alloc(ARRAY_DEFAULT_SIZE);
1751: shared = false;
1752: } else if (values.length > ARRAY_DEFAULT_SIZE << 1) {
1753: alloc(ARRAY_DEFAULT_SIZE << 1);
1754: }
1755:
1756: begin = 0;
1757: realLength = 0;
1758: return this ;
1759: }
1760:
1761: /** rb_ary_fill
1762: *
1763: */
1764: public IRubyObject fill(IRubyObject[] args, Block block) {
1765: IRubyObject item = null;
1766: IRubyObject begObj = null;
1767: IRubyObject lenObj = null;
1768: int argc = args.length;
1769:
1770: if (block.isGiven()) {
1771: Arity.checkArgumentCount(getRuntime(), args, 0, 2);
1772: item = null;
1773: begObj = argc > 0 ? args[0] : null;
1774: lenObj = argc > 1 ? args[1] : null;
1775: argc++;
1776: } else {
1777: Arity.checkArgumentCount(getRuntime(), args, 1, 3);
1778: item = args[0];
1779: begObj = argc > 1 ? args[1] : null;
1780: lenObj = argc > 2 ? args[2] : null;
1781: }
1782:
1783: long beg = 0, end = 0, len = 0;
1784: switch (argc) {
1785: case 1:
1786: beg = 0;
1787: len = realLength;
1788: break;
1789: case 2:
1790: if (begObj instanceof RubyRange) {
1791: long[] beglen = ((RubyRange) begObj).begLen(realLength,
1792: 1);
1793: beg = (int) beglen[0];
1794: len = (int) beglen[1];
1795: break;
1796: }
1797: /* fall through */
1798: case 3:
1799: beg = begObj.isNil() ? 0 : RubyNumeric.num2long(begObj);
1800: if (beg < 0) {
1801: beg = realLength + beg;
1802: if (beg < 0)
1803: beg = 0;
1804: }
1805: len = (lenObj == null || lenObj.isNil()) ? realLength - beg
1806: : RubyNumeric.num2long(lenObj);
1807: break;
1808: }
1809:
1810: modify();
1811:
1812: end = beg + len;
1813: if (end > realLength) {
1814: if (end >= values.length)
1815: realloc((int) end);
1816:
1817: Arrays.fill(values, realLength, (int) end, getRuntime()
1818: .getNil());
1819: realLength = (int) end;
1820: }
1821:
1822: if (block.isGiven()) {
1823: Ruby runtime = getRuntime();
1824: ThreadContext context = runtime.getCurrentContext();
1825: for (int i = (int) beg; i < (int) end; i++) {
1826: IRubyObject v = block.yield(context, runtime
1827: .newFixnum(i));
1828: if (i >= realLength)
1829: break;
1830:
1831: values[i] = v;
1832: }
1833: } else {
1834: if (len > 0)
1835: Arrays.fill(values, (int) beg, (int) (beg + len), item);
1836: }
1837:
1838: return this ;
1839: }
1840:
1841: /** rb_ary_index
1842: *
1843: */
1844: public IRubyObject index(IRubyObject obj) {
1845: Ruby runtime = getRuntime();
1846: final ThreadContext context = runtime.getCurrentContext();
1847: for (int i = begin; i < begin + realLength; i++) {
1848: if (values[i].equalInternal(context, obj).isTrue())
1849: return runtime.newFixnum(i - begin);
1850: }
1851:
1852: return runtime.getNil();
1853: }
1854:
1855: /** rb_ary_rindex
1856: *
1857: */
1858: public IRubyObject rindex(IRubyObject obj) {
1859: Ruby runtime = getRuntime();
1860: final ThreadContext context = runtime.getCurrentContext();
1861:
1862: int i = realLength;
1863:
1864: while (i-- > 0) {
1865: if (i > realLength) {
1866: i = realLength;
1867: continue;
1868: }
1869: if (values[begin + i].equalInternal(context, obj).isTrue()) {
1870: return getRuntime().newFixnum(i);
1871: }
1872: }
1873:
1874: return runtime.getNil();
1875: }
1876:
1877: /** rb_ary_indexes
1878: *
1879: */
1880: public IRubyObject indexes(IRubyObject[] args) {
1881: getRuntime().getWarnings().warn(
1882: "Array#indexes is deprecated; use Array#values_at");
1883:
1884: RubyArray ary = new RubyArray(getRuntime(), args.length);
1885:
1886: IRubyObject[] arefArgs = new IRubyObject[1];
1887: for (int i = 0; i < args.length; i++) {
1888: arefArgs[0] = args[i];
1889: ary.append(aref(arefArgs));
1890: }
1891:
1892: return ary;
1893: }
1894:
1895: /** rb_ary_reverse_bang
1896: *
1897: */
1898: public IRubyObject reverse_bang() {
1899: modify();
1900:
1901: IRubyObject tmp;
1902: if (realLength > 1) {
1903: int p1 = 0;
1904: int p2 = p1 + realLength - 1;
1905:
1906: while (p1 < p2) {
1907: tmp = values[p1];
1908: values[p1++] = values[p2];
1909: values[p2--] = tmp;
1910: }
1911: }
1912: return this ;
1913: }
1914:
1915: /** rb_ary_reverse_m
1916: *
1917: */
1918: public IRubyObject reverse() {
1919: return aryDup().reverse_bang();
1920: }
1921:
1922: /** rb_ary_collect
1923: *
1924: */
1925: public RubyArray collect(Block block) {
1926: Ruby runtime = getRuntime();
1927:
1928: if (!block.isGiven())
1929: return new RubyArray(getRuntime(), runtime.getArray(), this );
1930:
1931: ThreadContext context = runtime.getCurrentContext();
1932: RubyArray collect = new RubyArray(runtime, realLength);
1933:
1934: for (int i = begin; i < begin + realLength; i++) {
1935: collect.append(block.yield(context, values[i]));
1936: }
1937:
1938: return collect;
1939: }
1940:
1941: /** rb_ary_collect_bang
1942: *
1943: */
1944: public RubyArray collect_bang(Block block) {
1945: modify();
1946: ThreadContext context = getRuntime().getCurrentContext();
1947: for (int i = 0, len = realLength; i < len; i++) {
1948: store(i, block.yield(context, values[begin + i]));
1949: }
1950: return this ;
1951: }
1952:
1953: /** rb_ary_select
1954: *
1955: */
1956: public RubyArray select(Block block) {
1957: Ruby runtime = getRuntime();
1958: RubyArray result = new RubyArray(runtime, realLength);
1959:
1960: ThreadContext context = runtime.getCurrentContext();
1961: if (shared) {
1962: for (int i = begin; i < begin + realLength; i++) {
1963: if (block.yield(context, values[i]).isTrue())
1964: result.append(elt(i - begin));
1965: }
1966: } else {
1967: for (int i = 0; i < realLength; i++) {
1968: if (block.yield(context, values[i]).isTrue())
1969: result.append(elt(i));
1970: }
1971: }
1972: return result;
1973: }
1974:
1975: /** rb_ary_delete
1976: *
1977: */
1978: public IRubyObject delete(IRubyObject item, Block block) {
1979: int i2 = 0;
1980:
1981: Ruby runtime = getRuntime();
1982: final ThreadContext context = runtime.getCurrentContext();
1983: for (int i1 = 0; i1 < realLength; i1++) {
1984: IRubyObject e = values[begin + i1];
1985: if (e.equalInternal(context, item).isTrue())
1986: continue;
1987: if (i1 != i2)
1988: store(i2, e);
1989: i2++;
1990: }
1991:
1992: if (realLength == i2) {
1993: if (block.isGiven())
1994: return block.yield(context, item);
1995:
1996: return runtime.getNil();
1997: }
1998:
1999: modify();
2000:
2001: if (realLength > i2) {
2002: realLength = i2;
2003: if (i2 << 1 < values.length
2004: && values.length > ARRAY_DEFAULT_SIZE)
2005: realloc(i2 << 1);
2006: }
2007: return item;
2008: }
2009:
2010: /** rb_ary_delete_at
2011: *
2012: */
2013: private final IRubyObject delete_at(int pos) {
2014: int len = realLength;
2015:
2016: if (pos >= len)
2017: return getRuntime().getNil();
2018:
2019: if (pos < 0)
2020: pos += len;
2021:
2022: if (pos < 0)
2023: return getRuntime().getNil();
2024:
2025: modify();
2026:
2027: IRubyObject obj = values[pos];
2028: System.arraycopy(values, pos + 1, values, pos, len - (pos + 1));
2029:
2030: realLength--;
2031:
2032: return obj;
2033: }
2034:
2035: /** rb_ary_delete_at_m
2036: *
2037: */
2038: public IRubyObject delete_at(IRubyObject obj) {
2039: return delete_at((int) RubyNumeric.num2long(obj));
2040: }
2041:
2042: /** rb_ary_reject_bang
2043: *
2044: */
2045: public IRubyObject reject(Block block) {
2046: RubyArray ary = aryDup();
2047: ary.reject_bang(block);
2048: return ary;
2049: }
2050:
2051: /** rb_ary_reject_bang
2052: *
2053: */
2054: public IRubyObject reject_bang(Block block) {
2055: int i2 = 0;
2056: modify();
2057:
2058: ThreadContext context = getRuntime().getCurrentContext();
2059: for (int i1 = 0; i1 < realLength; i1++) {
2060: IRubyObject v = values[i1];
2061: if (block.yield(context, v).isTrue())
2062: continue;
2063:
2064: if (i1 != i2)
2065: store(i2, v);
2066: i2++;
2067: }
2068: if (realLength == i2)
2069: return getRuntime().getNil();
2070:
2071: if (i2 < realLength)
2072: realLength = i2;
2073:
2074: return this ;
2075: }
2076:
2077: /** rb_ary_delete_if
2078: *
2079: */
2080: public IRubyObject delete_if(Block block) {
2081: reject_bang(block);
2082: return this ;
2083: }
2084:
2085: /** rb_ary_zip
2086: *
2087: */
2088: public IRubyObject zip(IRubyObject[] args, Block block) {
2089: for (int i = 0; i < args.length; i++) {
2090: args[i] = args[i].convertToArray();
2091: }
2092:
2093: Ruby runtime = getRuntime();
2094: ThreadContext context = runtime.getCurrentContext();
2095: if (block.isGiven()) {
2096: for (int i = 0; i < realLength; i++) {
2097: RubyArray tmp = new RubyArray(runtime, args.length + 1);
2098: tmp.append(elt(i));
2099: for (int j = 0; j < args.length; j++) {
2100: tmp.append(((RubyArray) args[j]).elt(i));
2101: }
2102: block.yield(context, tmp);
2103: }
2104: return runtime.getNil();
2105: }
2106:
2107: int len = realLength;
2108: RubyArray result = new RubyArray(runtime, len);
2109: for (int i = 0; i < len; i++) {
2110: RubyArray tmp = new RubyArray(runtime, args.length + 1);
2111: tmp.append(elt(i));
2112: for (int j = 0; j < args.length; j++) {
2113: tmp.append(((RubyArray) args[j]).elt(i));
2114: }
2115: result.append(tmp);
2116: }
2117: return result;
2118: }
2119:
2120: /** rb_ary_cmp
2121: *
2122: */
2123: public IRubyObject op_cmp(IRubyObject obj) {
2124: RubyArray ary2 = obj.convertToArray();
2125:
2126: int len = realLength;
2127:
2128: if (len > ary2.realLength)
2129: len = ary2.realLength;
2130:
2131: Ruby runtime = getRuntime();
2132: ThreadContext context = runtime.getCurrentContext();
2133: for (int i = 0; i < len; i++) {
2134: IRubyObject v = elt(i).callMethod(context,
2135: MethodIndex.OP_SPACESHIP, "<=>", ary2.elt(i));
2136: if (!(v instanceof RubyFixnum)
2137: || ((RubyFixnum) v).getLongValue() != 0)
2138: return v;
2139: }
2140: len = realLength - ary2.realLength;
2141:
2142: if (len == 0)
2143: return RubyFixnum.zero(runtime);
2144: if (len > 0)
2145: return RubyFixnum.one(runtime);
2146:
2147: return RubyFixnum.minus_one(runtime);
2148: }
2149:
2150: /** rb_ary_slice_bang
2151: *
2152: */
2153: public IRubyObject slice_bang(IRubyObject[] args) {
2154: if (Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2) {
2155: long pos = RubyNumeric.num2long(args[0]);
2156: long len = RubyNumeric.num2long(args[1]);
2157:
2158: if (pos < 0)
2159: pos = realLength + pos;
2160:
2161: args[1] = subseq(pos, len);
2162: splice(pos, len, null);
2163:
2164: return args[1];
2165: }
2166:
2167: IRubyObject arg = args[0];
2168: if (arg instanceof RubyRange) {
2169: long[] beglen = ((RubyRange) arg).begLen(realLength, 1);
2170: long pos = beglen[0];
2171: long len = beglen[1];
2172:
2173: if (pos < 0) {
2174: pos = realLength + pos;
2175: }
2176: arg = subseq(pos, len);
2177: splice(pos, len, null);
2178: return arg;
2179: }
2180:
2181: return delete_at((int) RubyNumeric.num2long(args[0]));
2182: }
2183:
2184: /** rb_ary_assoc
2185: *
2186: */
2187: public IRubyObject assoc(IRubyObject key) {
2188: Ruby runtime = getRuntime();
2189: final ThreadContext context = runtime.getCurrentContext();
2190:
2191: for (int i = begin; i < begin + realLength; i++) {
2192: IRubyObject v = values[i];
2193: if (v instanceof RubyArray
2194: && ((RubyArray) v).realLength > 0
2195: && ((RubyArray) v).values[0].equalInternal(context,
2196: key).isTrue()) {
2197: return v;
2198: }
2199: }
2200: return runtime.getNil();
2201: }
2202:
2203: /** rb_ary_rassoc
2204: *
2205: */
2206: public IRubyObject rassoc(IRubyObject value) {
2207: Ruby runtime = getRuntime();
2208: final ThreadContext context = runtime.getCurrentContext();
2209:
2210: for (int i = begin; i < begin + realLength; i++) {
2211: IRubyObject v = values[i];
2212: if (v instanceof RubyArray
2213: && ((RubyArray) v).realLength > 1
2214: && ((RubyArray) v).values[1].equalInternal(context,
2215: value).isTrue()) {
2216: return v;
2217: }
2218: }
2219:
2220: return runtime.getNil();
2221: }
2222:
2223: /** flatten
2224: *
2225: */
2226: private final int flatten(int index, RubyArray ary2, RubyArray memo) {
2227: int i = index;
2228: int n;
2229: int lim = index + ary2.realLength;
2230:
2231: IRubyObject id = ary2.id();
2232:
2233: if (memo.includes(id))
2234: throw getRuntime().newArgumentError(
2235: "tried to flatten recursive array");
2236:
2237: memo.append(id);
2238: splice(index, 1, ary2);
2239: while (i < lim) {
2240: IRubyObject tmp = elt(i).checkArrayType();
2241: if (!tmp.isNil()) {
2242: n = flatten(i, (RubyArray) tmp, memo);
2243: i += n;
2244: lim += n;
2245: }
2246: i++;
2247: }
2248: memo.pop();
2249: return lim - index - 1; /* returns number of increased items */
2250: }
2251:
2252: /** rb_ary_flatten_bang
2253: *
2254: */
2255: public IRubyObject flatten_bang() {
2256: int i = 0;
2257: RubyArray memo = null;
2258:
2259: while (i < realLength) {
2260: IRubyObject ary2 = values[begin + i];
2261: IRubyObject tmp = ary2.checkArrayType();
2262: if (!tmp.isNil()) {
2263: if (memo == null) {
2264: memo = new RubyArray(getRuntime(), false);
2265: memo.values = reserve(ARRAY_DEFAULT_SIZE);
2266: }
2267:
2268: i += flatten(i, (RubyArray) tmp, memo);
2269: }
2270: i++;
2271: }
2272: if (memo == null)
2273: return getRuntime().getNil();
2274:
2275: return this ;
2276: }
2277:
2278: /** rb_ary_flatten
2279: *
2280: */
2281: public IRubyObject flatten() {
2282: RubyArray ary = aryDup();
2283: ary.flatten_bang();
2284: return ary;
2285: }
2286:
2287: /** rb_ary_nitems
2288: *
2289: */
2290: public IRubyObject nitems() {
2291: int n = 0;
2292:
2293: for (int i = begin; i < begin + realLength; i++) {
2294: if (!values[i].isNil())
2295: n++;
2296: }
2297:
2298: return getRuntime().newFixnum(n);
2299: }
2300:
2301: /** rb_ary_plus
2302: *
2303: */
2304: public IRubyObject op_plus(IRubyObject obj) {
2305: RubyArray y = obj.convertToArray();
2306: int len = realLength + y.realLength;
2307: RubyArray z = new RubyArray(getRuntime(), len);
2308: System.arraycopy(values, begin, z.values, 0, realLength);
2309: System.arraycopy(y.values, y.begin, z.values, realLength,
2310: y.realLength);
2311: z.realLength = len;
2312: return z;
2313: }
2314:
2315: /** rb_ary_times
2316: *
2317: */
2318: public IRubyObject op_times(IRubyObject times) {
2319: IRubyObject tmp = times.checkStringType();
2320:
2321: if (!tmp.isNil())
2322: return join(tmp);
2323:
2324: long len = RubyNumeric.num2long(times);
2325: if (len == 0)
2326: return new RubyArray(getRuntime(), getMetaClass(), 0);
2327: if (len < 0)
2328: throw getRuntime().newArgumentError("negative argument");
2329:
2330: if (Long.MAX_VALUE / len < realLength) {
2331: throw getRuntime().newArgumentError("argument too big");
2332: }
2333:
2334: len *= realLength;
2335:
2336: RubyArray ary2 = new RubyArray(getRuntime(), getMetaClass(),
2337: len);
2338: ary2.realLength = (int) len;
2339:
2340: for (int i = 0; i < len; i += realLength) {
2341: System.arraycopy(values, begin, ary2.values, i, realLength);
2342: }
2343:
2344: ary2.infectBy(this );
2345:
2346: return ary2;
2347: }
2348:
2349: /** ary_make_hash
2350: *
2351: */
2352: private final Set makeSet(RubyArray ary2) {
2353: final Set set = new HashSet();
2354: int begin = this .begin;
2355: for (int i = begin; i < begin + realLength; i++) {
2356: set.add(values[i]);
2357: }
2358:
2359: if (ary2 != null) {
2360: begin = ary2.begin;
2361: for (int i = begin; i < begin + ary2.realLength; i++) {
2362: set.add(ary2.values[i]);
2363: }
2364: }
2365: return set;
2366: }
2367:
2368: /** rb_ary_uniq_bang
2369: *
2370: */
2371: public IRubyObject uniq_bang() {
2372: Set set = makeSet(null);
2373:
2374: if (realLength == set.size())
2375: return getRuntime().getNil();
2376:
2377: int j = 0;
2378: for (int i = 0; i < realLength; i++) {
2379: IRubyObject v = elt(i);
2380: if (set.remove(v))
2381: store(j++, v);
2382: }
2383: realLength = j;
2384: return this ;
2385: }
2386:
2387: /** rb_ary_uniq
2388: *
2389: */
2390: public IRubyObject uniq() {
2391: RubyArray ary = aryDup();
2392: ary.uniq_bang();
2393: return ary;
2394: }
2395:
2396: /** rb_ary_diff
2397: *
2398: */
2399: public IRubyObject op_diff(IRubyObject other) {
2400: Set set = other.convertToArray().makeSet(null);
2401: RubyArray ary3 = new RubyArray(getRuntime());
2402:
2403: int begin = this .begin;
2404: for (int i = begin; i < begin + realLength; i++) {
2405: if (set.contains(values[i]))
2406: continue;
2407:
2408: ary3.append(elt(i - begin));
2409: }
2410:
2411: return ary3;
2412: }
2413:
2414: /** rb_ary_and
2415: *
2416: */
2417: public IRubyObject op_and(IRubyObject other) {
2418: RubyArray ary2 = other.convertToArray();
2419: Set set = ary2.makeSet(null);
2420: RubyArray ary3 = new RubyArray(getRuntime(),
2421: realLength < ary2.realLength ? realLength
2422: : ary2.realLength);
2423:
2424: for (int i = 0; i < realLength; i++) {
2425: IRubyObject v = elt(i);
2426: if (set.remove(v))
2427: ary3.append(v);
2428: }
2429:
2430: return ary3;
2431: }
2432:
2433: /** rb_ary_or
2434: *
2435: */
2436: public IRubyObject op_or(IRubyObject other) {
2437: RubyArray ary2 = other.convertToArray();
2438: Set set = makeSet(ary2);
2439:
2440: RubyArray ary3 = new RubyArray(getRuntime(), realLength
2441: + ary2.realLength);
2442:
2443: for (int i = 0; i < realLength; i++) {
2444: IRubyObject v = elt(i);
2445: if (set.remove(v))
2446: ary3.append(v);
2447: }
2448: for (int i = 0; i < ary2.realLength; i++) {
2449: IRubyObject v = ary2.elt(i);
2450: if (set.remove(v))
2451: ary3.append(v);
2452: }
2453: return ary3;
2454: }
2455:
2456: /** rb_ary_sort
2457: *
2458: */
2459: public RubyArray sort(Block block) {
2460: RubyArray ary = aryDup();
2461: ary.sort_bang(block);
2462: return ary;
2463: }
2464:
2465: /** rb_ary_sort_bang
2466: *
2467: */
2468: public RubyArray sort_bang(Block block) {
2469: modify();
2470: if (realLength > 1) {
2471: tmpLock = true;
2472: try {
2473: if (block.isGiven()) {
2474: Arrays.sort(values, 0, realLength,
2475: new BlockComparator(block));
2476: } else {
2477: Arrays.sort(values, 0, realLength,
2478: new DefaultComparator());
2479: }
2480: } finally {
2481: tmpLock = false;
2482: }
2483: }
2484: return this ;
2485: }
2486:
2487: final class BlockComparator implements Comparator {
2488: private Block block;
2489:
2490: public BlockComparator(Block block) {
2491: this .block = block;
2492: }
2493:
2494: public int compare(Object o1, Object o2) {
2495: ThreadContext context = getRuntime().getCurrentContext();
2496: IRubyObject obj1 = (IRubyObject) o1;
2497: IRubyObject obj2 = (IRubyObject) o2;
2498: IRubyObject ret = block.yield(context, getRuntime()
2499: .newArray(obj1, obj2), null, null, true);
2500: int n = RubyComparable.cmpint(ret, obj1, obj2);
2501: //TODO: ary_sort_check should be done here
2502: return n;
2503: }
2504: }
2505:
2506: final class DefaultComparator implements Comparator {
2507: public int compare(Object o1, Object o2) {
2508: if (o1 instanceof RubyFixnum && o2 instanceof RubyFixnum) {
2509: long a = ((RubyFixnum) o1).getLongValue();
2510: long b = ((RubyFixnum) o2).getLongValue();
2511: if (a > b)
2512: return 1;
2513: if (a < b)
2514: return -1;
2515: return 0;
2516: }
2517: if (o1 instanceof RubyString && o2 instanceof RubyString) {
2518: return ((RubyString) o1).cmp((RubyString) o2);
2519: }
2520:
2521: IRubyObject obj1 = (IRubyObject) o1;
2522: IRubyObject obj2 = (IRubyObject) o2;
2523:
2524: IRubyObject ret = obj1.callMethod(obj1.getRuntime()
2525: .getCurrentContext(), MethodIndex.OP_SPACESHIP,
2526: "<=>", obj2);
2527: int n = RubyComparable.cmpint(ret, obj1, obj2);
2528: //TODO: ary_sort_check should be done here
2529: return n;
2530: }
2531: }
2532:
2533: public static void marshalTo(RubyArray array, MarshalStream output)
2534: throws IOException {
2535: output.writeInt(array.getList().size());
2536: for (Iterator iter = array.getList().iterator(); iter.hasNext();) {
2537: output.dumpObject((IRubyObject) iter.next());
2538: }
2539: }
2540:
2541: public static RubyArray unmarshalFrom(UnmarshalStream input)
2542: throws IOException {
2543: RubyArray result = input.getRuntime().newArray();
2544: input.registerLinkTarget(result);
2545: int size = input.unmarshalInt();
2546: for (int i = 0; i < size; i++) {
2547: result.append(input.unmarshalObject());
2548: }
2549: return result;
2550: }
2551:
2552: /**
2553: * @see org.jruby.util.Pack#pack
2554: */
2555: public RubyString pack(IRubyObject obj) {
2556: RubyString iFmt = RubyString.objAsString(obj);
2557: return Pack.pack(getRuntime(), this , iFmt.getByteList());
2558: }
2559:
2560: public Class getJavaClass() {
2561: return List.class;
2562: }
2563:
2564: // Satisfy java.util.List interface (for Java integration)
2565:
2566: public int size() {
2567: return realLength;
2568: }
2569:
2570: public boolean isEmpty() {
2571: return realLength == 0;
2572: }
2573:
2574: public boolean contains(Object element) {
2575: return indexOf(element) != -1;
2576: }
2577:
2578: public Object[] toArray() {
2579: Object[] array = new Object[realLength];
2580: for (int i = begin; i < realLength; i++) {
2581: array[i - begin] = JavaUtil.convertRubyToJava(values[i]);
2582: }
2583: return array;
2584: }
2585:
2586: public Object[] toArray(final Object[] arg) {
2587: Object[] array = arg;
2588: if (array.length < realLength) {
2589: Class type = array.getClass().getComponentType();
2590: array = (Object[]) Array.newInstance(type, realLength);
2591: }
2592: int length = realLength - begin;
2593:
2594: for (int i = 0; i < length; i++) {
2595: array[i] = JavaUtil.convertRubyToJava(values[i + begin]);
2596: }
2597: return array;
2598: }
2599:
2600: public boolean add(Object element) {
2601: append(JavaUtil.convertJavaToRuby(getRuntime(), element));
2602: return true;
2603: }
2604:
2605: public boolean remove(Object element) {
2606: IRubyObject deleted = delete(JavaUtil.convertJavaToRuby(
2607: getRuntime(), element), Block.NULL_BLOCK);
2608: return deleted.isNil() ? false : true; // TODO: is this correct ?
2609: }
2610:
2611: public boolean containsAll(Collection c) {
2612: for (Iterator iter = c.iterator(); iter.hasNext();) {
2613: if (indexOf(iter.next()) == -1)
2614: return false;
2615: }
2616:
2617: return true;
2618: }
2619:
2620: public boolean addAll(Collection c) {
2621: for (Iterator iter = c.iterator(); iter.hasNext();) {
2622: add(iter.next());
2623: }
2624: return !c.isEmpty();
2625: }
2626:
2627: public boolean addAll(int index, Collection c) {
2628: Iterator iter = c.iterator();
2629: for (int i = index; iter.hasNext(); i++) {
2630: add(i, iter.next());
2631: }
2632: return !c.isEmpty();
2633: }
2634:
2635: public boolean removeAll(Collection c) {
2636: boolean listChanged = false;
2637: for (Iterator iter = c.iterator(); iter.hasNext();) {
2638: if (remove(iter.next())) {
2639: listChanged = true;
2640: }
2641: }
2642: return listChanged;
2643: }
2644:
2645: public boolean retainAll(Collection c) {
2646: boolean listChanged = false;
2647:
2648: for (Iterator iter = iterator(); iter.hasNext();) {
2649: Object element = iter.next();
2650: if (!c.contains(element)) {
2651: remove(element);
2652: listChanged = true;
2653: }
2654: }
2655: return listChanged;
2656: }
2657:
2658: public Object get(int index) {
2659: return JavaUtil.convertRubyToJava((IRubyObject) elt(index),
2660: Object.class);
2661: }
2662:
2663: public Object set(int index, Object element) {
2664: return store(index, JavaUtil.convertJavaToRuby(getRuntime(),
2665: element));
2666: }
2667:
2668: // TODO: make more efficient by not creating IRubyArray[]
2669: public void add(int index, Object element) {
2670: insert(new IRubyObject[] {
2671: RubyFixnum.newFixnum(getRuntime(), index),
2672: JavaUtil.convertJavaToRuby(getRuntime(), element) });
2673: }
2674:
2675: public Object remove(int index) {
2676: return JavaUtil.convertRubyToJava(delete_at(index),
2677: Object.class);
2678: }
2679:
2680: public int indexOf(Object element) {
2681: int begin = this .begin;
2682:
2683: if (element == null) {
2684: for (int i = begin; i < begin + realLength; i++) {
2685: if (values[i] == null)
2686: return i;
2687: }
2688: } else {
2689: IRubyObject convertedElement = JavaUtil.convertJavaToRuby(
2690: getRuntime(), element);
2691:
2692: for (int i = begin; i < begin + realLength; i++) {
2693: if (convertedElement.equals(values[i]))
2694: return i;
2695: }
2696: }
2697: return -1;
2698: }
2699:
2700: public int lastIndexOf(Object element) {
2701: int begin = this .begin;
2702:
2703: if (element == null) {
2704: for (int i = begin + realLength - 1; i >= begin; i--) {
2705: if (values[i] == null)
2706: return i;
2707: }
2708: } else {
2709: IRubyObject convertedElement = JavaUtil.convertJavaToRuby(
2710: getRuntime(), element);
2711:
2712: for (int i = begin + realLength - 1; i >= begin; i--) {
2713: if (convertedElement.equals(values[i]))
2714: return i;
2715: }
2716: }
2717:
2718: return -1;
2719: }
2720:
2721: public class RubyArrayConversionIterator implements Iterator {
2722: protected int index = 0;
2723: protected int last = -1;
2724:
2725: public boolean hasNext() {
2726: return index < realLength;
2727: }
2728:
2729: public Object next() {
2730: IRubyObject element = elt(index);
2731: last = index++;
2732: return JavaUtil.convertRubyToJava(element, Object.class);
2733: }
2734:
2735: public void remove() {
2736: if (last == -1)
2737: throw new IllegalStateException();
2738:
2739: delete_at(last);
2740: if (last < index)
2741: index--;
2742:
2743: last = -1;
2744:
2745: }
2746: }
2747:
2748: public Iterator iterator() {
2749: return new RubyArrayConversionIterator();
2750: }
2751:
2752: final class RubyArrayConversionListIterator extends
2753: RubyArrayConversionIterator implements ListIterator {
2754: public RubyArrayConversionListIterator() {
2755: }
2756:
2757: public RubyArrayConversionListIterator(int index) {
2758: this .index = index;
2759: }
2760:
2761: public boolean hasPrevious() {
2762: return index >= 0;
2763: }
2764:
2765: public Object previous() {
2766: return JavaUtil.convertRubyToJava(
2767: (IRubyObject) elt(last = --index), Object.class);
2768: }
2769:
2770: public int nextIndex() {
2771: return index;
2772: }
2773:
2774: public int previousIndex() {
2775: return index - 1;
2776: }
2777:
2778: public void set(Object obj) {
2779: if (last == -1)
2780: throw new IllegalStateException();
2781:
2782: store(last, JavaUtil.convertJavaToRuby(getRuntime(), obj));
2783: }
2784:
2785: public void add(Object obj) {
2786: insert(new IRubyObject[] {
2787: RubyFixnum.newFixnum(getRuntime(), index++),
2788: JavaUtil.convertJavaToRuby(getRuntime(), obj) });
2789: last = -1;
2790: }
2791: }
2792:
2793: public ListIterator listIterator() {
2794: return new RubyArrayConversionListIterator();
2795: }
2796:
2797: public ListIterator listIterator(int index) {
2798: return new RubyArrayConversionListIterator(index);
2799: }
2800:
2801: // TODO: list.subList(from, to).clear() is supposed to clear the sublist from the list.
2802: // How can we support this operation?
2803: public List subList(int fromIndex, int toIndex) {
2804: if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
2805: throw new IndexOutOfBoundsException();
2806: }
2807:
2808: IRubyObject subList = subseq(fromIndex, toIndex - fromIndex + 1);
2809:
2810: return subList.isNil() ? null : (List) subList;
2811: }
2812:
2813: public void clear() {
2814: rb_clear();
2815: }
2816: }
|