package org.jruby.specialized;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.runtime.Constants;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.builtin.IRubyObject;

This is the base class for all specialized RubyArray. Specialized RubyArray use fields rather than an IRubyObject[] to hold their values. When they need to grow or shrink, they unpack those values to a proper IRubyObject[] and fall back on RubyArray logic. Subclasses should override all methods that would access the array directly to use the fields, with guards for the packed flag and access outside packed range. This includes the following methods (at the time of this writing...this list will evolve): RubyArrayRubyArray.eltInternal(int) RubyArrayRubyArray.eltInternalSet(int index, IRubyObject value) RubyArraySpecializedfinishUnpack(IRubyObject nil) RubyArrayRubyArray.aryDup() RubyArrayRubyArray.rb_clear() RubyArrayRubyArray.collect(ThreadContext, Block) RubyArrayRubyArray.copyInto(IRubyObject[], int) RubyArrayRubyArray.copyInto(IRubyObject[], int, int) RubyArrayRubyArray.dupImpl() RubyArrayRubyArray.includes(ThreadContext, IRubyObject) RubyArrayRubyArray.indexOf(Object) RubyArrayRubyArray.inspectAry(ThreadContext) RubyArrayRubyArray.internalRotate(ThreadContext, int) RubyArrayRubyArray.internalRotateBang(ThreadContext, int) RubyArrayRubyArray.op_plus(IRubyObject) RubyArrayRubyArray.reverse_bang() RubyArrayRubyArray.safeReverse() RubyArrayRubyArray.sortInternal(ThreadContext, Block) RubyArrayRubyArray.sortInternal(ThreadContext, boolean) RubyArrayRubyArray.storeInternal(int, IRubyObject) RubyArrayRubyArray.subseq(RubyClass, long, long, boolean) RubyArrayRubyArray.toJavaArray() RubyArrayRubyArray.uniq(ThreadContext)
/** * This is the base class for all specialized RubyArray. * * Specialized RubyArray use fields rather than an IRubyObject[] to hold their values. When they need * to grow or shrink, they unpack those values to a proper IRubyObject[] and fall back on RubyArray * logic. * * Subclasses should override all methods that would access the array directly to use the fields, * with guards for the packed flag and access outside packed range. This includes the following * methods (at the time of this writing...this list will evolve): * * RubyArray{@link #eltInternal(int)} * RubyArray{@link #eltInternalSet(int index, IRubyObject value)} * RubyArraySpecialized{@link #finishUnpack(IRubyObject nil)} * RubyArray{@link #aryDup()} * RubyArray{@link #rb_clear()} * RubyArray{@link #collect(org.jruby.runtime.ThreadContext, org.jruby.runtime.Block)} * RubyArray{@link #copyInto(IRubyObject[], int)} * RubyArray{@link #copyInto(IRubyObject[], int, int)} * RubyArray{@link #dupImpl()} * RubyArray{@link #includes(org.jruby.runtime.ThreadContext, IRubyObject)} * RubyArray{@link #indexOf(Object)} * RubyArray{@link #inspectAry(org.jruby.runtime.ThreadContext)} * RubyArray{@link #internalRotate(org.jruby.runtime.ThreadContext, int)} * RubyArray{@link #internalRotateBang(org.jruby.runtime.ThreadContext, int)} * RubyArray{@link #op_plus(IRubyObject)} * RubyArray{@link #reverse_bang()} * RubyArray{@link #safeReverse()} * RubyArray{@link #sortInternal(org.jruby.runtime.ThreadContext, org.jruby.runtime.Block)} * RubyArray{@link #sortInternal(org.jruby.runtime.ThreadContext, boolean)} * RubyArray{@link #storeInternal(int, IRubyObject)} * RubyArray{@link #subseq(RubyClass, long, long, boolean)} * RubyArray{@link #toJavaArray()} * RubyArray{@link #uniq(org.jruby.runtime.ThreadContext)} */
public abstract class RubyArraySpecialized extends RubyArray { public static final int MAX_PACKED_SIZE = 2; public RubyArraySpecialized(Ruby runtime, boolean light) { super(runtime, runtime.getArray(), light); } public RubyArraySpecialized(RubyClass otherClass, boolean light) { super(otherClass.getClassRuntime(), otherClass, light); } protected final void unpack() { if (!packed()) return; // CON: I believe most of the time we'll unpack because we need to grow, so give a bit of extra room. // For example, <<, unshift, and push will all just add one to front or back. Ruby runtime = getRuntime(); IRubyObject[] values = new IRubyObject[realLength + 2]; Helpers.fillNil(values, runtime); copyInto(values, 1); this.values = values; this.begin = 1; finishUnpack(runtime.getNil()); } protected abstract void finishUnpack(IRubyObject nil); protected boolean packed() { return values == null; } }