/* * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.data.record; import java.util.Arrays; import java.util.Iterator; /** * * @author pron */ class SimpleRecordArray<R> implements RecordArray<R>, Iterable<Record<R>>, Cloneable { public final RecordType<R> type; public final int length; private final int osize; private final int bsize; private final int[] offsets; private final Object[] oa; private final byte[] ba; private final int offset; public SimpleRecordArray(RecordType<R> recordType, int length) { this.type = recordType; this.length = length; this.offsets = recordType.getOffsets(); this.osize = recordType.getObjectIndex() > 0 ? recordType.getObjectOffset() : 0; this.bsize = recordType.getPrimitiveIndex() > 0 ? recordType.getPrimitiveOffset() : 0; this.oa = osize > 0 ? new Object[osize * length] : null; this.ba = bsize > 0 ? new byte[bsize * length] : null; this.offset = 0; } private SimpleRecordArray(SimpleRecordArray<R> other, int offset, int length, boolean copy) { this.type = other.type; this.length = length; this.offsets = other.offsets; this.osize = other.osize; this.bsize = other.bsize; if (copy) { this.oa = other.oa != null ? Arrays.copyOfRange(other.oa, offset * osize, (offset + length) * osize) : null; this.ba = other.ba != null ? Arrays.copyOfRange(other.ba, offset * bsize, (offset + length) * bsize) : null; this.offset = 0; } else { this.oa = other.oa; this.ba = other.ba; this.offset = offset; } } @Override public RecordType<R> type() { return type; } @Override protected SimpleRecordArray<R> clone() { return new SimpleRecordArray<R>(this, offset, length, true); } @Override public Accessor newAccessor() { return new AccessorRecord(type, offsets, oa, ba, osize, bsize, offset); } @Override public Accessor reset(Accessor accessor) { ((AccessorRecord) accessor).index = -1; return accessor; } @Override public Record<R> at(Accessor accessor, int index) { if (index < 0 || index >= length) throw new ArrayIndexOutOfBoundsException(index); final AccessorRecord<R> ar = (AccessorRecord<R>) accessor; ar.index = index; return ar; } @Override public Record<R> at(int index) { return at(newAccessor(), index); } @Override public RecordArray<R> slice(int from, int to) { if(from > to) throw new IllegalArgumentException("fromIndex(" + from + ") > toIndex(" + to + ")"); return new SimpleRecordArray<R>(this, offset + from, to - from, false); } public RecordArray<R> clear() { Arrays.fill(oa, offset * osize, (offset + length) * osize, null); Arrays.fill(ba, offset * bsize, (offset + length) * bsize, (byte)0); return this; } @Override public Iterator<Record<R>> iterator() { return new Iterator<Record<R>>() { private final AccessorRecord<R> acc = (AccessorRecord<R>) newAccessor(); @Override public boolean hasNext() { return (acc.index + 1) < length; } @Override public Record<R> next() { acc.index++; return acc; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } // public Record<R> at(Record<R> accessor) private static class AccessorRecord<R> extends SimpleRecord<R> implements Accessor { private final int osize; private final int bsize; private final int offset; int index; public AccessorRecord(RecordType<R> recordType, int[] offsets, Object[] oa, byte[] ba, int osize, int bsize, int offset) { super(recordType, offsets, oa, ba); this.osize = osize; this.bsize = bsize; this.index = -1; this.offset = offset; } @Override int fieldOffset(Field<? super R, ?> field) { try { final int stride = (field.type() == Field.OBJECT || field.type() == Field.OBJECT_ARRAY) ? osize : bsize; return (index + offset) * stride + offsets[field.id]; } catch (IndexOutOfBoundsException e) { if (index < 0) throw new IllegalStateException("Accessor not pointing at an element"); else throw new FieldNotFoundException(field, this); } } } }