Package org.squarebrackets

Source Code of org.squarebrackets.FloatBufferArrayImpl

/*
* ============================================================================
* 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 org.squarebrackets.function.FloatConsumer;

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.FloatBuffer;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;

import static java.util.Arrays.copyOfRange;
import static java.util.Objects.requireNonNull;

/**
* <p>Immutable wrapper for {@code FloatBuffer}s.</p>
*
* <p>This float array is constructed by the static interface methods of {@code FloatArray}. The {@code copyOf}
* method returns a new array representing a deep copy of the buffer argument. The
* {@code unsafeValueOf} methods wrap a new {@code FloatArray} 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 FloatBufferArrayImpl implements NativeArray<Float>, FloatArray, Serializable {

    /** Backing buffer. */
    protected final FloatBuffer 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.
     */
    FloatBufferArrayImpl(@Nonnull FloatBuffer 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<Float> getComponentType() {
        return Float.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 Float> 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 float[] 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 Float get(int index) {
        if (Tripwire.ENABLED) {
            Tripwire.trip(getClass());
        }
        return getFloat(index);
    }

    /**
     * Returns the float value found at {@code index}.
     *
     * @param index index relative to the offset of the array.
     * @return float value found at the specified index.
     * @throws IndexOutOfBoundsException if {@code index} position is invalid.
     */
    @Override
    public float getFloat(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 Float) {
            if (Tripwire.ENABLED) {
                Tripwire.trip(getClass());
            }
            return containsFloat((Float) 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 containsFloat(float value) {
        if (hasCharacteristics(SORTED)) {
            return Arrays.binarySearch(this, value) >= 0;
        }
        if (elements.hasArray()) {
            final float[] 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.
        float[] backingArray = NativeArrays.floatArray(array);
        if (backingArray != null) {
            for (int index = array.offset(), toIndex = index + array.length(); index < toIndex; index++) {
                if (!containsFloat(backingArray[index])) {
                    return false;
                }
            }
            return true;
        }
        // Fast alternative: no unboxing.
        FloatArray cast = ArrayCast.toFloatArray(array);
        if (cast != null) {
            final int length = array.length();
            final ArrayIterator.OfFloat iterator = cast.iterator();
            for (int index = 0; index < length; index++) {
                if (!containsFloat(iterator.nextFloat())) {
                    return false;
                }
            }
            return true;
        }
        // Alternative: unboxing.
        for (Object o : array) {
            if (!(o instanceof Float) || !containsFloat((Float) 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 Float) {
            return indexOfFloat((Float) 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 indexOfFloat(float value) {
        if (hasCharacteristics(SORTED)) {
            int index = Arrays.binarySearch(this, value);
            if (index >= 0) {
                return Arrays.binarySearchFirst(this, index);
            }
            return -1;
        }
        if (elements.hasArray()) {
            final float[] 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 Float) {
            return lastIndexOfFloat((Float) 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 lastIndexOfFloat(float value) {
        if (hasCharacteristics(SORTED)) {
            int index = Arrays.binarySearch(this, value);
            if (index >= 0) {
                return Arrays.binarySearchLast(this, index);
            }
            return -1;
        }
        if (elements.hasArray()) {
            final float[] 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 Float> consumer) {
        if (Tripwire.ENABLED) {
            Tripwire.trip(getClass());
        }
        forEachFloat(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 forEachFloat(@Nonnull FloatConsumer consumer) {
        requireNonNull(consumer);
        if (elements.hasArray()) {
            final float[] 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 float[] toArray() {
        if (elements.hasArray()) {
            return copyOfRange(elements.array(), elements.arrayOffset() + elements.position(), elements.limit());
        }
        float[] a = new float[elements.remaining()];
        elements.mark();
        elements.get(a).reset();
        return a;
    }

    /**
     * Returns an array containing all of the float values of {@code this} array. If the float values fit in the
     * specified array, it is returned therein. Otherwise, a new float 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 float[] toArray(@Nonnull float[] array) {
        int remaining = elements.remaining();
        float[] a = array.length >= remaining ? array : new float[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 float[] 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 FloatArray offset(int offset) {
        if (offset == 0) {
            return this;
        }
        int newOffset = elements.position() + offset;
        int newLength = elements.remaining() - offset;
        subArrayCheck(newOffset, newLength);
        FloatBuffer copy = elements.duplicate();
        copy.position(newOffset);
        return new FloatBufferArrayImpl(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 FloatArray length(int length) {
        if (elements.remaining() == length) {
            return this;
        }
        int offset = elements.position();
        subArrayCheck(offset, length);
        FloatBuffer copy = elements.duplicate();
        copy.limit(offset + length);
        return new FloatBufferArrayImpl(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 FloatArray 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);
        FloatBuffer copy = elements.duplicate();
        copy.position(newOffset);
        copy.limit(newOffset + newLength);
        return new FloatBufferArrayImpl(copy, characteristics, false);
    }

    @SuppressWarnings({"MissingMethodJavaDoc", "MissingFieldJavaDoc"})
    private class ArrayIteratorImpl implements ArrayIterator.OfFloat {
        int index;

        ArrayIteratorImpl() {
            this(0);
        }

        ArrayIteratorImpl(int index) {
            this.index = elements.position() + index;
        }

        @Override
        public boolean hasNext() {
            return index < elements.limit();
        }

        @Override
        public float nextFloat() {
            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 float previousFloat() {
            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 setFloat(float value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void addFloat(float 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.OfFloat 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.OfFloat 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 float[] 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 float[] a = elements.array();
            final int fromIndex = elements.arrayOffset() + elements.position();
            for (int index = fromIndex, toIndex = index + elements.limit(); index < toIndex; index++) {
                float element = a[index];
                result = 31 * result + Float.floatToIntBits(element);
            }
        } else {
            for (int index = elements.position(), toIndex = elements.limit(); index < toIndex; index++) {
                float element = elements.get(index);
                result = 31 * result + Float.floatToIntBits(element);
            }
        }
        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.
            float[] backingArray = NativeArrays.floatArray(array);
            if (elements.hasArray() && backingArray != null) {
                final float[] 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.
            FloatArray cast = ArrayCast.toFloatArray(array);
            if (cast != null) {
                final ArrayIterator.OfFloat iterator = cast.iterator();
                for (int index = elements.position(), toIndex = elements.limit(); index < toIndex; index++) {
                    if (!equals(elements.get(index), iterator.nextFloat())) {
                        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(float x, float y) {
        return Arrays.equals(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 = 8469254328436213749L;

        final int length;
        final boolean direct;
        final int characteristics;
        transient FloatBuffer elements;

        SerializationProxy(FloatBufferArrayImpl 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.writeFloat(elements.get());
            }
        }

        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            if (direct) {
                elements = ByteBuffer.allocateDirect(Float.SIZE / Byte.SIZE * length).asFloatBuffer();
            } else {
                elements = FloatBuffer.allocate(length);
            }
            for (int i = 0; i < length; i++) {
                elements.put(s.readFloat());
            }
            elements.rewind();
        }

        private Object readResolve() {
            return new FloatBufferArrayImpl(elements, characteristics, false);
        }
    }
}
TOP

Related Classes of org.squarebrackets.FloatBufferArrayImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.