KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyArray


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
16  * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
18  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
19  * Copyright (C) 2002-2005 Thomas E Enebo <enebo@acm.org>
20  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
21  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
22  * Copyright (C) 2006 Ola Bini <Ola.Bini@ki.se>
23  * Copyright (C) 2006 Daniel Steer <damian.steer@hp.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the CPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the CPL, the GPL or the LGPL.
36  ***** END LICENSE BLOCK *****/

37 package org.jruby;
38
39 import java.lang.reflect.Array JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.util.Arrays JavaDoc;
42 import java.util.Collection JavaDoc;
43 import java.util.Comparator JavaDoc;
44 import java.util.HashSet JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.ListIterator JavaDoc;
48 import java.util.Set JavaDoc;
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 /**
63  * The implementation of the built-in class Array in Ruby.
64  */

65 public class RubyArray extends RubyObject implements List JavaDoc {
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 JavaDoc 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     /** rb_ary_s_create
219      *
220      */

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     /** rb_ary_new2
234      *
235      */

236     public static final RubyArray newArray(final Ruby runtime, final long len) {
237         return new RubyArray(runtime, len);
238     }
239
240     /** rb_ary_new
241      *
242      */

243     public static final RubyArray newArray(final Ruby runtime) {
244         return new RubyArray(runtime, ARRAY_DEFAULT_SIZE);
245     }
246
247     /** rb_ary_new
248      *
249      */

250     public static final RubyArray newArrayLight(final Ruby runtime) {
251         /* Ruby arrays default to holding 16 elements, so we create an
252          * ArrayList of the same size if we're not told otherwise
253          */

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     /** rb_assoc_new
264      *
265      */

266     public static RubyArray newArray(Ruby runtime, IRubyObject car, IRubyObject cdr) {
267         return new RubyArray(runtime, new IRubyObject[] { car, cdr });
268     }
269
270     /** rb_ary_new4, rb_ary_new3
271      *
272      */

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 JavaDoc 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     /*
301      * plain internal array assignment
302      */

303     public RubyArray(Ruby runtime, IRubyObject[]vals){
304         super(runtime, runtime.getArray());
305         values = vals;
306         realLength = vals.length;
307     }
308     
309     /* rb_ary_new2
310      * just allocates the internal array
311      */

312     private RubyArray(Ruby runtime, long length) {
313         super(runtime, runtime.getArray());
314         checkLength(length);
315         alloc((int) length);
316     }
317
318     /* rb_ary_new3, rb_ary_new4
319      * allocates the internal array of size length and copies the 'length' elements
320      */

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     /*
332      * just allocates the internal array, with optional objectspace
333      */

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     /*
341      * construction of array from an existing array, so we can skip length checking
342      */

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     /* NEWOBJ and OBJSETUP equivalent
351      * fastest one, for shared arrays, optional objectspace
352      */

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     /** Getter for property list.
396      * @return Value of property list.
397      */

398     public List JavaDoc 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     /** rb_ary_make_shared
421      *
422      */

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     /** rb_ary_modify_check
434      *
435      */

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     /** rb_ary_modify
448      *
449      */

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     /* ================
462      * Instance Methods
463      * ================
464      */

465
466     /** rb_ary_initialize
467      *
468      */

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     /** rb_ary_replace
518      *
519      */

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     /** rb_ary_to_s
537      *
538      */

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     /** rb_ary_hash
557      *
558      */

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     /** rb_ary_store
574      *
575      */

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     /** rb_ary_elt - faster
608      *
609      */

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     /** rb_ary_elt - faster
617      *
618      */

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     /** rb_ary_elt - faster
626      *
627      */

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     /** rb_ary_elt - faster
635      *
636      */

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     /** rb_ary_entry
644      *
645      */

646     public final IRubyObject entry(long offset) {
647         return (offset < 0 ) ? elt(offset + realLength) : elt_f(offset);
648     }
649
650
651     /** rb_ary_entry
652      *
653      */

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     /** rb_ary_fetch
663      *
664      */

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     /** rb_ary_to_ary
688      *
689      */

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); // possibly should not in object space
696
arr.alloc(1);
697         arr.values[0] = obj;
698         arr.realLength = 1;
699         return arr;
700     }
701
702     /** rb_ary_splice
703      *
704      */

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     /** rb_ary_insert
769      *
770      */

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); // rb_ary_new4
789

790         return this;
791     }
792
793     public final IRubyObject dup() {
794         return aryDup();
795     }
796
797     /** rb_ary_dup
798      *
799      */

800     private final RubyArray aryDup() {
801         RubyArray dup = new RubyArray(getRuntime(), this);
802         dup.setTaint(isTaint()); // from DUP_SETUP
803
// rb_copy_generic_ivar from DUP_SETUP here ...unlikely..
804
return dup;
805     }
806
807     /** rb_ary_transpose
808      *
809      */

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     /** rb_values_at (internal)
839      *
840      */

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     /** rb_values_at
870      *
871      */

872     public IRubyObject values_at(IRubyObject[] args) {
873         return values_at(realLength, args);
874     }
875
876     /** rb_ary_subseq
877      *
878      */

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         // MRI does klass = rb_obj_class(ary); here, what for ?
889
if (len == 0) return new RubyArray(getRuntime(), 0);
890
891         return makeShared(begin + (int) beg, (int) len);
892     }
893
894     /** rb_ary_length
895      *
896      */

897     public RubyFixnum length() {
898         return getRuntime().newFixnum(realLength);
899     }
900
901     /** rb_ary_push - specialized rb_ary_store
902      *
903      */

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     /** rb_ary_push_m
925      *
926      */

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     /** rb_ary_pop
936      *
937      */

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     /** rb_ary_shift
954      *
955      */

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     /** rb_ary_unshift
972      *
973      */

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     /** rb_ary_unshift_m
993      *
994      */

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        // it's safe to use zeroes here since modified by store()
1003
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    /** rb_ary_includes
1010     *
1011     */

1012    public RubyBoolean include_p(IRubyObject item) {
1013        return getRuntime().newBoolean(includes(item));
1014    }
1015
1016    /** rb_ary_frozen_p
1017     *
1018     */

1019    public RubyBoolean frozen() {
1020        return getRuntime().newBoolean(isFrozen() || tmpLock);
1021    }
1022
1023    /** rb_ary_aref
1024     */

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    /** rb_ary_aset
1060     *
1061     */

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    /** rb_ary_at
1091     *
1092     */

1093    public IRubyObject at(IRubyObject pos) {
1094        return entry(RubyNumeric.num2long(pos));
1095    }
1096
1097    /** rb_ary_concat
1098     *
1099     */

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    /** rb_ary_inspect
1109     *
1110     */

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 JavaDoc buffer = new StringBuffer JavaDoc("[");
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    /** rb_ary_first
1141     *
1142     */

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    /** rb_ary_last
1162     *
1163     */

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    /** rb_ary_each
1183     *
1184     */

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    /** rb_ary_each_index
1200     *
1201     */

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    /** rb_ary_reverse_each
1212     *
1213     */

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    /** rb_ary_join
1235     *
1236     */

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 JavaDoc buf = new StringBuffer JavaDoc((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                // do nothing
1256
} 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    /** rb_ary_join_m
1280     *
1281     */

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    /** rb_ary_to_a
1290     *
1291     */

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    /** rb_ary_equal
1309     *
1310     */

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    /** rb_ary_eql
1334     *
1335     */

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    /** rb_ary_compact_bang
1353     *
1354     */

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    /** rb_ary_compact
1378     *
1379     */

1380    public IRubyObject compact() {
1381        RubyArray ary = aryDup();
1382        ary.compact_bang();
1383        return ary;
1384    }
1385
1386    /** rb_ary_empty_p
1387     *
1388     */

1389    public IRubyObject empty_p() {
1390        return realLength == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
1391    }
1392
1393    /** rb_ary_clear
1394     *
1395     */

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    /** rb_ary_fill
1412     *
1413     */

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            /* fall through */
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    /** rb_ary_index
1484     *
1485     */

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    /** rb_ary_rindex
1497     *
1498     */

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    /** rb_ary_indexes
1519     *
1520     */

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    /** rb_ary_reverse_bang
1536     *
1537     */

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    /** rb_ary_reverse_m
1556     *
1557     */

1558    public IRubyObject reverse() {
1559        return aryDup().reverse_bang();
1560    }
1561
1562    /** rb_ary_collect
1563     *
1564     */

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    /** rb_ary_collect_bang
1580     *
1581     */

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    /** rb_ary_select
1592     *
1593     */

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    /** rb_ary_delete
1612     *
1613     */

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    /** rb_ary_delete_at
1642     *
1643     */

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    /** rb_ary_delete_at_m
1664     *
1665     */

1666    public IRubyObject delete_at(IRubyObject obj) {
1667        return delete_at((int) RubyNumeric.num2long(obj));
1668    }
1669
1670    /** rb_ary_reject_bang
1671     *
1672     */

1673    public IRubyObject reject(Block block) {
1674        RubyArray ary = aryDup();
1675        ary.reject_bang(block);
1676        return ary;
1677    }
1678
1679    /** rb_ary_reject_bang
1680     *
1681     */

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    /** rb_ary_delete_if
1702     *
1703     */

1704    public IRubyObject delete_if(Block block) {
1705        reject_bang(block);
1706        return this;
1707    }
1708
1709    /** rb_ary_zip
1710     *
1711     */

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    /** rb_ary_cmp
1745     *
1746     */

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    /** rb_ary_slice_bang
1769     *
1770     */

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    /** rb_ary_assoc
1802     *
1803     */

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    /** rb_ary_rassoc
1819     *
1820     */

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    /** flatten
1837     *
1838     */

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; /* returns number of increased items */
1861    }
1862
1863    /** rb_ary_flatten_bang
1864     *
1865     */

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    /** rb_ary_flatten
1889     *
1890     */

1891    public IRubyObject flatten() {
1892        RubyArray ary = aryDup();
1893        ary.flatten_bang();
1894        return ary;
1895    }
1896
1897    /** rb_ary_nitems
1898     *
1899     */

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    /** rb_ary_plus
1911     *
1912     */

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    /** rb_ary_times
1924     *
1925     */

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    /** ary_make_hash
1954     *
1955     */

1956    private final Set JavaDoc makeSet(RubyArray ary2) {
1957        final Set JavaDoc set = new HashSet JavaDoc();
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    /** rb_ary_uniq_bang
1973     *
1974     */

1975    public IRubyObject uniq_bang() {
1976        Set JavaDoc 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    /** rb_ary_uniq
1990     *
1991     */

1992    public IRubyObject uniq() {
1993        RubyArray ary = aryDup();
1994        ary.uniq_bang();
1995        return ary;
1996    }
1997
1998    /** rb_ary_diff
1999     *
2000     */

2001    public IRubyObject op_diff(IRubyObject other) {
2002        Set JavaDoc 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    /** rb_ary_and
2016     *
2017     */

2018    public IRubyObject op_and(IRubyObject other) {
2019        RubyArray ary2 = other.convertToArray();
2020        Set JavaDoc 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    /** rb_ary_or
2033     *
2034     */

2035    public IRubyObject op_or(IRubyObject other) {
2036        RubyArray ary2 = other.convertToArray();
2037        Set JavaDoc 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    /** rb_ary_sort
2053     *
2054     */

2055    public RubyArray sort(Block block) {
2056        RubyArray ary = aryDup();
2057        ary.sort_bang(block);
2058        return ary;
2059    }
2060
2061    /** rb_ary_sort_bang
2062     *
2063     */

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 JavaDoc {
2082        private Block block;
2083
2084        public BlockComparator(Block block) {
2085            this.block = block;
2086        }
2087
2088        public int compare(Object JavaDoc o1, Object JavaDoc 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            //TODO: ary_sort_check should be done here
2095
return n;
2096        }
2097    }
2098
2099    final class DefaultComparator implements Comparator JavaDoc {
2100        public int compare(Object JavaDoc o1, Object JavaDoc 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            //TODO: ary_sort_check should be done here
2118
return n;
2119        }
2120    }
2121
2122    public static void marshalTo(RubyArray array, MarshalStream output) throws IOException JavaDoc {
2123        output.writeInt(array.getList().size());
2124        for (Iterator JavaDoc iter = array.getList().iterator(); iter.hasNext();) {
2125            output.dumpObject((IRubyObject) iter.next());
2126        }
2127    }
2128
2129    public static RubyArray unmarshalFrom(UnmarshalStream input) throws IOException JavaDoc {
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    /**
2140     * @see org.jruby.util.Pack#pack
2141     */

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 JavaDoc getJavaClass() {
2148        return List JavaDoc.class;
2149    }
2150
2151    // Satisfy java.util.List interface (for Java integration)
2152

2153    public int size() {
2154        return realLength;
2155    }
2156
2157    public boolean isEmpty() {
2158        return realLength == 0;
2159    }
2160
2161    public boolean contains(Object JavaDoc element) {
2162        return indexOf(element) != -1;
2163    }
2164
2165    public Object JavaDoc[] toArray() {
2166        Object JavaDoc[] array = new Object JavaDoc[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 JavaDoc[] toArray(final Object JavaDoc[] arg) {
2174        Object JavaDoc[] array = arg;
2175        if (array.length < realLength) {
2176            Class JavaDoc type = array.getClass().getComponentType();
2177            array = (Object JavaDoc[]) 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 JavaDoc element) {
2188        append(JavaUtil.convertJavaToRuby(getRuntime(), element));
2189        return true;
2190    }
2191
2192    public boolean remove(Object JavaDoc element) {
2193        IRubyObject deleted = delete(JavaUtil.convertJavaToRuby(getRuntime(), element), Block.NULL_BLOCK);
2194        return deleted.isNil() ? false : true; // TODO: is this correct ?
2195
}
2196
2197    public boolean containsAll(Collection JavaDoc c) {
2198        for (Iterator JavaDoc 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 JavaDoc c) {
2206        for (Iterator JavaDoc iter = c.iterator(); iter.hasNext();) {
2207            add(iter.next());
2208        }
2209        return !c.isEmpty();
2210    }
2211
2212    public boolean addAll(int index, Collection JavaDoc c) {
2213        Iterator JavaDoc 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 JavaDoc c) {
2221        boolean listChanged = false;
2222        for (Iterator JavaDoc 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 JavaDoc c) {
2231        boolean listChanged = false;
2232
2233        for (Iterator JavaDoc iter = iterator(); iter.hasNext();) {
2234            Object JavaDoc element = iter.next();
2235            if (!c.contains(element)) {
2236                remove(element);
2237                listChanged = true;
2238            }
2239        }
2240        return listChanged;
2241    }
2242
2243    public Object JavaDoc get(int index) {
2244        return JavaUtil.convertRubyToJava((IRubyObject) elt(index), Object JavaDoc.class);
2245    }
2246
2247    public Object JavaDoc set(int index, Object JavaDoc element) {
2248        return store(index, JavaUtil.convertJavaToRuby(getRuntime(), element));
2249    }
2250
2251    // TODO: make more efficient by not creating IRubyArray[]
2252
public void add(int index, Object JavaDoc element) {
2253        insert(new IRubyObject[] { RubyFixnum.newFixnum(getRuntime(), index), JavaUtil.convertJavaToRuby(getRuntime(), element) });
2254    }
2255
2256    public Object JavaDoc remove(int index) {
2257        return JavaUtil.convertRubyToJava(delete_at(index), Object JavaDoc.class);
2258    }
2259
2260    public int indexOf(Object JavaDoc 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 JavaDoc 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 JavaDoc {
2296        protected int index = 0;
2297        protected int last = -1;
2298
2299        public boolean hasNext() {
2300            return index < realLength;
2301        }
2302
2303        public Object JavaDoc next() {
2304            IRubyObject element = elt(index);
2305            last = index++;
2306            return JavaUtil.convertRubyToJava(element, Object JavaDoc.class);
2307        }
2308
2309        public void remove() {
2310            if (last == -1) throw new IllegalStateException JavaDoc();
2311
2312            delete_at(last);
2313            if (last < index) index--;
2314
2315            last = -1;
2316    
2317        }
2318    }
2319
2320    public Iterator JavaDoc iterator() {
2321        return new RubyArrayConversionIterator();
2322    }
2323
2324    final class RubyArrayConversionListIterator extends RubyArrayConversionIterator implements ListIterator JavaDoc {
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 JavaDoc previous() {
2337            return JavaUtil.convertRubyToJava((IRubyObject) elt(last = --index), Object JavaDoc.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 JavaDoc obj) {
2349            if (last == -1) throw new IllegalStateException JavaDoc();
2350
2351            store(last, JavaUtil.convertJavaToRuby(getRuntime(), obj));
2352        }
2353
2354        public void add(Object JavaDoc obj) {
2355            insert(new IRubyObject[] { RubyFixnum.newFixnum(getRuntime(), index++), JavaUtil.convertJavaToRuby(getRuntime(), obj) });
2356            last = -1;
2357        }
2358    }
2359
2360    public ListIterator JavaDoc listIterator() {
2361        return new RubyArrayConversionListIterator();
2362    }
2363
2364    public ListIterator JavaDoc listIterator(int index) {
2365        return new RubyArrayConversionListIterator(index);
2366    }
2367
2368    // TODO: list.subList(from, to).clear() is supposed to clear the sublist from the list.
2369
// How can we support this operation?
2370
public List JavaDoc subList(int fromIndex, int toIndex) {
2371        if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
2372            throw new IndexOutOfBoundsException JavaDoc();
2373        }
2374        
2375        IRubyObject subList = subseq(fromIndex, toIndex - fromIndex + 1);
2376
2377        return subList.isNil() ? null : (List JavaDoc) subList;
2378    }
2379
2380    public void clear() {
2381        rb_clear();
2382    }
2383}
2384
Popular Tags