/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Square Brackets - Java Array Framework.
* Copyright (C) 2013 Beatgrid Media B.V.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Beatgrid Media B.V.
* Sisalbaan 5-A
* 2352 AZ Leiderdorp
* The Netherlands
*
* info@squarebrackets.org
* http://squarebrackets.org
*/
package org.squarebrackets;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
import static java.util.Arrays.copyOfRange;
import static java.util.Objects.requireNonNull;
/**
* <p>Immutable wrapper for {@code LongBuffer}s.</p>
*
* <p>This long array is constructed by the static interface methods of {@code LongArray}. The {@code copyOf}
* method returns a new array representing a deep copy of the buffer argument. The
* {@code unsafeValueOf} methods wrap a new {@code LongArray} around a buffer. It is imperative that this
* buffer is not modified outside the scope of this class, as this would break the immutable contract.
* The {@code unsafeValueOf} method is used to prevent unnecessary array copies. It is the caller's responsibility not
* to violate the contract.</p>
*
* <p>Arrays express characteristics to indicate that, for instance, elements are listed in sorted order, or no
* duplicate elements exist. These characteristics allow array implementations to optimize their algorithms based
* on the contents of the array. For example, operations that lookup elements can use a binary search algorithm if
* the array is marked as being sorted. These optimizations may reduce the time complexity of such operations by
* several orders of magnitude.</p>
*
* <p>This class attempts to establish these characteristics to accommodate these optimizations at best effort. This
* means that this implementation determines which set of characteristics apply to its elements without traversing
* these elements, in other words, without incurring a performance penalty. Primitive arrays, such as this class,
* always report {@code NONNULL}. The set of characteristics of immutable arrays are constant.</p>
*
* @author Leon van Zantvoort
*/
@Immutable
class LongBufferArrayImpl implements NativeArray<Long>, LongArray, Serializable {
/** Backing buffer. */
protected final LongBuffer elements;
/** Array characteristics. */
protected int characteristics;
/**
* Package visible constructor, to be used by static factory methods only.
*
* @param buffer backing buffer.
* @param characteristics array characteristics.
* @param duplicate {@code true} to duplicate the {@code buffer}, {@code false} to use {@code buffer} reference
* as backing buffer.
*/
LongBufferArrayImpl(@Nonnull LongBuffer buffer, int characteristics, boolean duplicate) {
requireNonNull(buffer);
if (duplicate) {
this.elements = buffer.duplicate();
} else {
this.elements = buffer;
}
this.characteristics = filterCharacteristics(characteristics) | (buffer.remaining() > 1 ? 0 : SORTED | DISTINCT);
}
/**
* Checks if the given index is in range. If not, throws an appropriate runtime exception.
*
* @throws IndexOutOfBoundsException if {@code index} position is invalid.
*/
final void rangeCheck(int index) {
Arrays.rangeCheck(elements.remaining(), index);
}
/**
* Checks if the given boundary is within this array's boundaries.
*
* @throws IndexOutOfBoundsException if {@code index} position is invalid.
*/
final void subArrayCheck(int offset, int length) {
Arrays.subArrayCheck((elements.hasArray() ? elements.arrayOffset() : 0) + elements.position(), elements.remaining(), offset, length);
}
/**
* A version of rangeCheck used by iterator.
*
* @throws IndexOutOfBoundsException if {@code index} position is invalid.
*/
final void rangeCheckForIterator(int index) {
Arrays.rangeCheckForIterator(elements.remaining(), index);
}
/**
* Returns the component type of the backing array.
*
* @return component type of the backing array.
*/
@Override
public final Class<Long> getComponentType() {
return Long.TYPE;
}
/**
* Gets the comparator that is used for sorting this array, {@code null} if array is primitive array, or if array
* sorted according to natural ordering of elements, or {@code null} if array is not sorted.
*
* @return a {@code Comparator}, or {@code null} if the elements are sorted in the natural order, or {@code null} if
* array is not sorted.
*/
@Override
public final @CheckForNull Comparator<? super Long> getComparator() {
return null;
}
/**
* Tells whether or not this array is backed by an array.
*
* <p>If this method returns {@code true} then array instance may safely be obtained through {@code array()}.</p>
*
* @return {@code true} if, and only if, this array is backed by an array.
*/
@Override
public final boolean hasArray() {
return elements.hasArray();
}
/**
* <p>Returns a native array containing all elements of this array.</p>
*
* <p>The resulting object must be cast to the primitive or object type of the implementing array's component type.</p>
*
* @return native array.
* @throws UnsupportedOperationException if array does not expose backing array.
*/
@Override
public final long[] nativeArray() {
if (elements.hasArray()) {
return elements.array();
}
throw new UnsupportedOperationException("Backing array not exposed by buffer.");
}
/**
* Tells whether or not this array is backed by a buffer.
*
* <p>If this method returns {@code true} then buffer instance may safely be obtained through {@code buffer()}.</p>
*
* @return {@code true} if, and only if, this array is backed by a buffer.
*/
@Override
public final boolean hasBuffer() {
return true;
}
/**
* Allow array implementation to filter characteristics based on array specific logic.
*
* <p>Default implementation passes specified value straight through.</p>
*
* @param characteristics characteristics to be filtered.
* @return the filtered characteristics.
*/
protected int filterCharacteristics(int characteristics) {
return characteristics | NONNULL & ~(MUTABLE | RESIZABLE | REPLACEABLE);
}
/**
* Returns the characteristics set for this array. The result is represented as ORed values from
* {@link #NONNULL}, {@link #MUTABLE}, {@link #REPLACEABLE}, {@link #SORTED}, {@link #DISTINCT}.
* Modification of the array contents may result in updated characteristics.
*
* @return the characteristics set for this array.
*/
@Override
public final int characteristics() {
return characteristics;
}
/**
* <p>Returns the offset relative to the backing array.</p>
*
* @return offset relative to the backing array.
*/
@Override
public final int offset() {
return elements.hasArray() ? elements.arrayOffset() + elements.position() : elements.position();
}
/**
* <p>Returns the number of elements of this array. All index related methods must respect the boundary represented
* by this value.</p>
*
* <p>Note that for mutable arrays, the backing array - as returned by {@code MutableArray.array()} -
* may be larger.</p>
*
* @return length of array.
*/
@Override
public final int length() {
return elements.remaining();
}
/**
* Returns {@code true} if this array contains no elements.
*
* @return {@code true} if this array contains no elements.
*/
@Override
public final boolean isEmpty() {
return elements.remaining() == 0;
}
/**
* Returns the object found at {@code index}.
*
* @param index index relative to the offset of the array.
* @return object found at the specified index.
* @throws IndexOutOfBoundsException if {@code index} position is invalid.
*/
@Override
public Long get(int index) {
if (Tripwire.ENABLED) {
Tripwire.trip(getClass());
}
return getLong(index);
}
/**
* Returns the long value found at {@code index}.
*
* @param index index relative to the offset of the array.
* @return long value found at the specified index.
* @throws IndexOutOfBoundsException if {@code index} position is invalid.
*/
@Override
public long getLong(int index) {
rangeCheck(index);
return elements.get(elements.position() + index);
}
/**
* Returns {@code true} if this array contains the specified object. This method supports boxed primitives. This
* means that if this array represents a primitive array, this method returns {@code true} if this array contains
* the unboxed version of specified object.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed until the specified object is found.</p>
*
* @param object object whose presence in this array is to be tested.
* @return {@code true} if this array contains the specified object.
*/
@SuppressWarnings("InconsistentJavaDoc")
@Override
public boolean contains(Object object) {
if (object instanceof Long) {
if (Tripwire.ENABLED) {
Tripwire.trip(getClass());
}
return containsLong((Long) object);
}
return false;
}
/**
* Returns {@code true} if this array contains the specified value.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed until the specified value is found.</p>
*
* @param value value whose presence in this array is to be tested.
* @return {@code true} if this array contains the specified value.
*/
@Override
public boolean containsLong(long value) {
if (hasCharacteristics(SORTED)) {
return Arrays.binarySearch(this, value) >= 0;
}
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
final int toIndex = fromIndex + elements.remaining();
for (int index = fromIndex; index < toIndex; index++) {
if (a[index] == value) {
return true;
}
}
return false;
}
for (int index = elements.position(), toIndex = elements.limit(); index < toIndex; index++) {
if (equals(elements.get(index), value)) {
return true;
}
}
return false;
}
/**
* Returns {@code true} if this array contains all of the elements in the specified {@code array}. Primitives and
* their object counterparts are regarded equal in this respect.
*
* <p>The Java Array Framework implementation performs a binary search if this array is sorted, otherwise all elements are
* traversed until the objects in specified array are found.</p>
*
* @param array array to be checked for containment in this array.
* @return {@code true} if this array contains all of the elements in the specified array.
* @throws NullPointerException if the specified array is null.
*/
@SuppressWarnings("InconsistentJavaDoc")
@Override
public boolean containsAll(@Nonnull Array<?> array) {
// Fastest: direct array access.
long[] backingArray = NativeArrays.longArray(array);
if (backingArray != null) {
for (int index = array.offset(), toIndex = index + array.length(); index < toIndex; index++) {
if (!containsLong(backingArray[index])) {
return false;
}
}
return true;
}
// Fast alternative: no unboxing.
LongArray cast = ArrayCast.toLongArray(array);
if (cast != null) {
final int length = array.length();
final ArrayIterator.OfLong iterator = cast.iterator(length);
for (int index = 0; index < length; index++) {
if (!containsLong(iterator.nextLong())) {
return false;
}
}
return true;
}
// Alternative: unboxing.
for (Object o : array) {
if (!(o instanceof Long) || !containsLong((Long) o)) {
return false; // Returns false for null elements.
}
}
return true;
}
/**
* Returns the index of the first occurrence of the specified object in the array, or {@code -1} if
* the array does not contain the object. The index is relative to the offset of the array.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed until the specified object is found.</p>
*
* @param object whose lowest index in this array is to be returned.
* @return lowest index of value in array or {@code -1} if value is not found.
*/
@SuppressWarnings("InconsistentJavaDoc")
@Override
public int indexOf(Object object) {
if (Tripwire.ENABLED) {
Tripwire.trip(getClass());
}
if (object instanceof Long) {
return indexOfLong((Long) object);
}
return -1;
}
/**
* Returns the index of the first occurrence of the specified value in the array, or {@code -1} if
* the array does not contain the value. The index is relative to the offset of the array.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed until the specified value is found.</p>
*
* @param value value whose lowest index in this array is to be returned.
* @return lowest index of value in array or {@code -1} if value is not found.
*/
@Override
public int indexOfLong(long value) {
if (hasCharacteristics(SORTED)) {
int index = Arrays.binarySearch(this, value);
if (index >= 0) {
return Arrays.binarySearchFirst(this, index);
}
return -1;
}
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
final int toIndex = fromIndex + elements.remaining();
for (int index = fromIndex; index < toIndex; index++) {
if (a[index] == value) {
return index - fromIndex;
}
}
return -1;
}
final int fromIndex = elements.position();
for (int index = fromIndex, toIndex = elements.limit(); index < toIndex; index++) {
if (equals(elements.get(index), value)) {
return index - fromIndex;
}
}
return -1;
}
/**
* Returns the index of the last occurrence of the specified object in the array, or {@code -1} if
* the array does not contain the object. The index is relative to the offset of the array.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed backwards until the specified object is found.</p>
*
* @param object object whose highest index in this array is to be returned.
* @return highest index of object in array or {@code -1} if value is not found.
*/
@SuppressWarnings("InconsistentJavaDoc")
@Override
public int lastIndexOf(Object object) {
if (Tripwire.ENABLED) {
Tripwire.trip(getClass());
}
if (object instanceof Long) {
return lastIndexOfLong((Long) object);
}
return -1;
}
/**
* Returns the index of the last occurrence of the specified value in the array, or {@code -1} if
* the array does not contain the value. The index is relative to the offset of the array.
*
* <p>The Java Array Framework implementation performs a binary search if this array reports {@code SORTED}
* characteristics, otherwise all elements are traversed backwards until the specified value is found.</p>
*
* @param value value whose highest index in this array is to be returned.
* @return highest index of value in array or {@code -1} if value is not found.
*/
@Override
public int lastIndexOfLong(long value) {
if (hasCharacteristics(SORTED)) {
int index = Arrays.binarySearch(this, value);
if (index >= 0) {
return Arrays.binarySearchLast(this, index);
}
return -1;
}
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
final int toIndex = fromIndex + elements.remaining();
for (int index = toIndex - 1; index >= fromIndex; index--) {
if (a[index] == value) {
return index - fromIndex;
}
}
return -1;
}
final int fromIndex = elements.position();
for (int toIndex = elements.limit(), index = toIndex - 1; index >= fromIndex; index--) {
if (equals(elements.get(index), value)) {
return index - fromIndex;
}
}
return -1;
}
/**
* Iterates through the array and invokes the consumer's {@code accept} method for each value within this array.
*
* @param consumer consumer that is called for each value within this array.
* @throws NullPointerException if the specified consumer is null.
*/
@Override
public void forEach(@Nonnull Consumer<? super Long> consumer) {
if (Tripwire.ENABLED) {
Tripwire.trip(getClass());
}
forEachLong(consumer::accept);
}
/**
* Iterates through the array and invokes the consumer's {@code accept} method for each value within this array.
*
* @param consumer consumer that is called for each value within this array.
* @throws NullPointerException if the specified consumer is null.
*/
@Override
public void forEachLong(@Nonnull LongConsumer consumer) {
requireNonNull(consumer);
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
for (int index = fromIndex, toIndex = index + elements.limit(); index < toIndex; index++) {
consumer.accept(a[index]);
}
} else {
final int fromIndex = elements.position();
final int toIndex = elements.limit();
for (int index = fromIndex; index < toIndex; index++) {
consumer.accept(elements.get(index));
}
}
}
/**
* Returns an native array of the elements specified by {@code this} array. This method always returns a defensive
* (range) copy of the backing array, even if this array is mutable.
*
* @return range copy of backing array.
*/
@Override
public long[] toArray() {
if (elements.hasArray()) {
return copyOfRange(elements.array(), elements.arrayOffset() + elements.position(), elements.limit());
}
long[] a = new long[elements.remaining()];
elements.mark();
elements.get(a).reset();
return a;
}
/**
* Returns an array containing all of the long values of {@code this} array. If the long values fit in the
* specified array, it is returned therein. Otherwise, a new long array is allocated.
*
* @param array the array into which the elements of this array are to be stored, if it is big enough; otherwise, a
* new array of the same runtime type is allocated for this purpose.
* @return an array containing all of the elements in the range specified by this array.
* @throws NullPointerException if the specified array is null.
*/
@Override
public long[] toArray(@Nonnull long[] array) {
int remaining = elements.remaining();
long[] a = array.length >= remaining ? array : new long[remaining];
elements.mark();
elements.get(a, 0, remaining).reset();
return a;
}
/**
* Stores elements from this array into the specified array.
*
* @param array the array into which the elements of this array are to be stored.
* @param offset the offset within the specified array of the first element to be written.
* @param length the number of elements to be stored. Must be smaller than or equal to length of this array.
* @throws IndexOutOfBoundsException if offset and length parameters are invalid.
* @throws NullPointerException if the specified array is null.
*/
@Override
public void toArray(@Nonnull long[] array, int offset, int length) {
if (elements.remaining() < length) {
throw new IndexOutOfBoundsException();
}
elements.mark();
elements.get(array, offset, length).reset();
}
/**
* <p>Returns a new sub array object for the specified {@code offset}. The specified {@code offset} is relative to
* the existing offset, as returned by {@link #offset()}. The length of the resulting array is reduced by
* the number of elements that are added to the current offset:</p>
*
* <pre>int newLength = length() - offset;</pre>
*
* <p>Effectively, the virtual {@code toIndex} of the array remains the same.</p>
*
* @param offset new relative offset.
* @return a new sub array object with the new {@code offset}.
*/
@Override
public LongArray offset(int offset) {
if (offset == 0) {
return this;
}
int newOffset = elements.position() + offset;
int newLength = elements.remaining() - offset;
subArrayCheck(newOffset, newLength);
LongBuffer copy = elements.duplicate();
copy.position(newOffset);
return new LongBufferArrayImpl(copy, characteristics, false);
}
/**
* <p>Returns a new sub array object for the specified {@code length}. Note that {@code length} must be smaller than
* or equal to the current length, as returned by {@code #length}.</p>
*
* @param length new length, must be smaller than or equal to current length.
* @return a new sub array object with the new {@code length}.
*/
@Override
public LongArray length(int length) {
if (elements.remaining() == length) {
return this;
}
int offset = elements.position();
subArrayCheck(offset, length);
LongBuffer copy = elements.duplicate();
copy.limit(offset + length);
return new LongBufferArrayImpl(copy, characteristics, false);
}
/**
* Convenience method, combining {@code offset(int)} and {@code length(int)}.
*
* @param fromIndex low endpoint (inclusive) of the sub array.
* @param toIndex high endpoint (exclusive) of the sub array.
* @return a view of the specified range within this array.
* @throws IndexOutOfBoundsException for an illegal endpoint index value ({@code fromIndex < 0 || toIndex > length ||
* fromIndex > toIndex}).
*/
@Override
public LongArray subArray(int fromIndex, int toIndex) {
int offset = elements.position();
int length = elements.remaining();
int newOffset = offset + fromIndex;
int newLength = toIndex - fromIndex;
if (newOffset == offset && newLength == length) {
return this;
}
subArrayCheck(newOffset, newLength);
LongBuffer copy = elements.duplicate();
copy.position(newOffset);
copy.limit(newOffset + newLength);
return new LongBufferArrayImpl(copy, characteristics, false);
}
@SuppressWarnings({"MissingMethodJavaDoc", "MissingFieldJavaDoc"})
private class ArrayIteratorImpl implements ArrayIterator.OfLong {
int index;
ArrayIteratorImpl() {
this(0);
}
ArrayIteratorImpl(int index) {
this.index = elements.position() + index;
}
@Override
public boolean hasNext() {
return index < elements.limit();
}
@Override
public long nextLong() {
int i = index;
if (i >= elements.limit()) {
throw new NoSuchElementException();
}
index = i + 1;
return elements.get(i);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasPrevious() {
return index > elements.position();
}
@Override
public long previousLong() {
int i = index - 1;
if (i < elements.position()) {
throw new NoSuchElementException();
}
assert i < elements.limit();
index = i;
return elements.get(i);
}
@Override
public int nextIndex() {
return index;
}
@Override
public int previousIndex() {
return index - 1;
}
@Override
public void setLong(long value) {
throw new UnsupportedOperationException();
}
@Override
public void addLong(long value) {
throw new UnsupportedOperationException();
}
}
/**
* Returns an array iterator over the elements in this array.
*
* @return an array iterator over the elements in this array.
*/
@Override
public ArrayIterator.OfLong iterator() {
return new ArrayIteratorImpl();
}
/**
* Returns an array iterator over the elements in this array.
*
* @param index index of the first element to be returned from the array iterator.
* @return a array iterator over the elements in this array.
* @throws IndexOutOfBoundsException if the index is out of range.
*/
@Override
public ArrayIterator.OfLong iterator(int index) {
rangeCheckForIterator(index);
return new ArrayIteratorImpl(index);
}
@SuppressWarnings("MissingMethodJavaDoc")
@Override
public String toString() {
if (elements.remaining() == 0) {
return "[]";
}
StringBuilder b = new StringBuilder();
b.append('[');
final int iMax = elements.limit() - 1;
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
for (int index = fromIndex; ; index++) {
b.append(a[index]);
if (index == iMax) {
return b.append(']').toString();
}
b.append(", ");
}
} else {
for (int index = elements.position(); ; index++) {
b.append(elements.get(index));
if (index == iMax) {
return b.append(']').toString();
}
b.append(", ");
}
}
}
@SuppressWarnings("MissingMethodJavaDoc")
@Override
public int hashCode() {
int result = 1;
if (elements.hasArray()) {
final long[] a = elements.array();
final int fromIndex = elements.arrayOffset() + elements.position();
for (int index = fromIndex, toIndex = index + elements.limit(); index < toIndex; index++) {
long element = a[index];
int elementHash = (int) (element ^ (element >>> 32));
result = 31 * result + elementHash;
}
} else {
for (int index = elements.position(), toIndex = elements.limit(); index < toIndex; index++) {
long element = elements.get(index);
int elementHash = (int) (element ^ (element >>> 32));
result = 31 * result + elementHash;
}
}
return result;
}
@SuppressWarnings("MissingMethodJavaDoc")
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Array) {
Array<?> array = (Array<?>) obj;
int length = elements.remaining();
if (length != array.length()) {
return false;
}
// Fastest: direct array access.
long[] backingArray = NativeArrays.longArray(array);
if (elements.hasArray() && backingArray != null) {
final long[] a = elements.array();
final int o1 = elements.arrayOffset() + elements.position();
final int o2 = array.offset();
for (int i = 0; i < length; i++) {
if (!equals(a[o1 + i], backingArray[o2 + i])) {
return false;
}
}
return true;
}
// Fast alternative: no unboxing.
LongArray cast = ArrayCast.toLongArray(array);
if (cast != null) {
final ArrayIterator.OfLong iterator = cast.iterator();
for (int index = elements.position(), toIndex = elements.limit(); index < toIndex; index++) {
if (!equals(elements.get(index), iterator.nextLong())) {
return false;
}
}
return true;
}
// Alternative.
return Arrays.equals(this, array);
}
return false;
}
/**
* Returns {@code true} if both values are equal, {@code false} otherwise.
*
* @param x first value to check.
* @param y second value to check.
* @return {@code true} if both values are equal, {@code false} otherwise.
*/
private static boolean equals(long x, long y) {
return x == y;
}
/**
* Write replace method for the serialization proxy pattern. This method must be overwritten by sub classes if their
* serialized form differs from this class.
*
* @return serialization proxy.
*/
Object writeReplace() {
return new SerializationProxy(this);
}
@SuppressWarnings("MissingMethodJavaDoc")
private void readObject(ObjectInputStream s) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
@SuppressWarnings({"MissingMethodJavaDoc", "MissingFieldJavaDoc"})
private static class SerializationProxy implements Serializable {
static final long serialVersionUID = -2086648729179719315L;
final int length;
final boolean direct;
final int characteristics;
transient LongBuffer elements;
SerializationProxy(LongBufferArrayImpl array) {
this.length = array.elements.remaining();
this.direct = array.elements.isDirect();
this.characteristics = array.characteristics;
this.elements = array.elements;
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
for (int i = 0; i < length; i++) {
s.writeLong(elements.get());
}
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
if (direct) {
elements = ByteBuffer.allocateDirect(Long.SIZE / Byte.SIZE * length).asLongBuffer();
} else {
elements = LongBuffer.allocate(length);
}
for (int i = 0; i < length; i++) {
elements.put(s.readLong());
}
elements.rewind();
}
private Object readResolve() {
return new LongBufferArrayImpl(elements, characteristics, false);
}
}
}