Package com.carrotsearch.hppc

Source Code of com.carrotsearch.hppc.FloatArrayDeque$ValueIterator

package com.carrotsearch.hppc;

import java.util.*;

import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.hash.FloatHashFunction;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import com.carrotsearch.hppc.procedures.FloatProcedure;

/**
* An array-backed deque (doubly linked queue) of floats. A single array is used to store and
* manipulate all elements. Reallocations are governed by a {@link ArraySizingStrategy}
* and may be expensive if they move around really large chunks of memory.
*
* A brief comparison of the API against the Java Collections framework:
* <table class="nice" summary="Java Collections ArrayDeque and HPPC FloatArrayDeque, related methods.">
* <caption>Java Collections ArrayDeque and HPPC {@link FloatArrayDeque}, related methods.</caption>
* <thead>
*     <tr class="odd">
*         <th scope="col">{@linkplain ArrayDeque java.util.ArrayDeque}</th>
*         <th scope="col">{@link FloatArrayDeque}</th> 
*     </tr>
* </thead>
* <tbody>
* <tr            ><td>addFirst       </td><td>addFirst       </td></tr>
* <tr class="odd"><td>addLast        </td><td>addLast        </td></tr>
* <tr            ><td>removeFirst    </td><td>removeLast     </td></tr>
* <tr class="odd"><td>getFirst       </td><td>getFirst       </td></tr>                    
* <tr            ><td>getLast        </td><td>getLast        </td></tr>
* <tr class="odd"><td>removeFirstOccurrence,
*                     removeLastOccurrence
*                                    </td><td>removeFirstOccurrence,
*                                             removeLastOccurrence
*                                                            </td></tr>
* <tr            ><td>size           </td><td>size           </td></tr>
* <tr class="odd"><td>Object[] toArray()</td><td>float[] toArray()</td></tr>
* <tr            ><td>iterator       </td><td>{@linkplain #iterator cursor over values}</td></tr>
* <tr class="odd"><td>other methods inherited from Stack, Queue</td><td>not implemented</td></tr>
* </tbody>
* </table>
*/
public class FloatArrayDeque
    extends AbstractFloatCollection implements FloatDeque
{
    /**
     * Default capacity if no other capacity is given in the constructor.
     */
    public final static int DEFAULT_CAPACITY = 5;

    /* removeIf:applied. */

    /**
     * Internal array for storing elements.
     */
    public float [] buffer;

    /**
     * The index of the element at the head of the deque or an
     * arbitrary number equal to tail if the deque is empty.
     */
    public int head;

    /**
     * The index at which the next element would be added to the tail
     * of the deque.
     */
    public int tail;

    /**
     * Buffer resizing strategy.
     */
    protected final ArraySizingStrategy resizer;

    /**
     * Hash function for entries, required for {@link #hashCode()}. The default is
     * {@link FloatHashFunction} (weak hash for primitive types).
     */
    public final FloatHashFunction hashFunction;

    /**
     * Create with default sizing strategy and initial capacity for storing
     * {@value #DEFAULT_CAPACITY} elements.
     *
     * @see BoundedProportionalArraySizingStrategy
     */
    public FloatArrayDeque()
    {
        this(DEFAULT_CAPACITY);
    }

    /**
     * Create with default sizing strategy and the given initial capacity.
     *
     * @see BoundedProportionalArraySizingStrategy
     */
    public FloatArrayDeque(int initialCapacity)
    {
        this(initialCapacity, new BoundedProportionalArraySizingStrategy());
    }

    /**
     * Create with a custom buffer resizing strategy.
     */
    public FloatArrayDeque(int initialCapacity, ArraySizingStrategy resizer)
    {
        this(initialCapacity, resizer, new FloatHashFunction());
    }

    /**
     * Create with a custom buffer resizing strategy.
     */
    public FloatArrayDeque(int initialCapacity, ArraySizingStrategy resizer,
        FloatHashFunction hashFunction)
    {
        assert initialCapacity >= 0 : "initialCapacity must be >= 0: " + initialCapacity;
        assert resizer != null;
        assert hashFunction != null;

        this.hashFunction = hashFunction;
        this.resizer = resizer;
        initialCapacity = resizer.round(initialCapacity);
        buffer = new float [initialCapacity];
    }

    /**
     * Creates a new deque from elements of another container, appending them
     * at the end of this deque.
     */
    public FloatArrayDeque(FloatContainer container)
    {
        this(container.size());
        addLast(container);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addFirst(float e1)
    {
        int h = oneLeft(head, buffer.length);
        if (h == tail)
        {
            ensureBufferSpace(1);
            h = oneLeft(head, buffer.length);
        }
        buffer[head = h] = e1;
    }

    /**
     * Vararg-signature method for adding elements at the front of this deque.
     *
     * <p><b>This method is handy, but costly if used in tight loops (anonymous
     * array passing)</b></p>
     */
    public void addFirst(float... elements)
    {
        ensureBufferSpace(elements.length);

        // For now, naive loop.
        for (int i = 0; i < elements.length; i++)
            addFirst(elements[i]);
    }

    /**
     * Inserts all elements from the given container to the front of this deque.
     *
     * @return Returns the number of elements actually added as a result of this
     * call.
     */
    public final int addFirst(FloatContainer container)
    {
        int size = container.size();
        ensureBufferSpace(size);

        for (FloatCursor cursor : container)
        {
            addFirst(cursor.value);
        }

        return size;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addLast(float e1)
    {
        int t = oneRight(tail, buffer.length);
        if (head == t)
        {
            ensureBufferSpace(1);
            t = oneRight(tail, buffer.length);
        }
        buffer[tail] = e1;
        tail = t;
    }
   
    /**
     * Vararg-signature method for adding elements at the end of this deque.
     *
     * <p><b>This method is handy, but costly if used in tight loops (anonymous
     * array passing)</b></p>
     */
    public void addLast(float... elements)
    {
        ensureBufferSpace(1);

        // For now, naive loop.
        for (int i = 0; i < elements.length; i++)
            addLast(elements[i]);
    }

    /**
     * Inserts all elements from the given container to the end of this deque.
     *
     * @return Returns the number of elements actually added as a result of this
     * call.
     */
    public final int addLast(FloatContainer container)
    {
        int size = container.size();
        ensureBufferSpace(size);

        for (FloatCursor cursor : container)
        {
            addLast(cursor.value);
        }

        return size;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public float removeFirst()
    {
        assert size() > 0 : "The deque is empty.";

        final float result = buffer[head];
        buffer[head] = ((float) 0);
        head = oneRight(head, buffer.length);
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public float removeLast()
    {
        assert size() > 0 : "The deque is empty.";

        tail = oneLeft(tail, buffer.length);
        final float result = buffer[tail];
        buffer[tail] = ((float) 0);
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public float getFirst()
    {
        assert size() > 0 : "The deque is empty.";

        return buffer[head];
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public float getLast()
    {
        assert size() > 0 : "The deque is empty.";

        return buffer[oneLeft(tail, buffer.length)];
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int removeFirstOccurrence(float e1)
    {
        final int index = bufferIndexOf(e1);
        if (index >= 0) removeAtBufferIndex(index);
        return index;
    }

    /**
     * Return the index of the first (counting from head) element equal to
     * <code>e1</code>. The index points to the {@link #buffer} array.
     *  
     * @param e1 The element to look for.
     * @return Returns the index of the first element equal to <code>e1</code>
     * or <code>-1</code> if not found.
     */
    public int bufferIndexOf(float e1)
    {
        final int last = tail;
        final int bufLen = buffer.length;
        for (int i = head; i != last; i = oneRight(i, bufLen))
        {
            if ((e1 ==  buffer[i]))
                return i;
        }

        return -1;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int removeLastOccurrence(float e1)
    {
        final int index = lastBufferIndexOf(e1);
        if (index >= 0) removeAtBufferIndex(index);
        return index;
    }

    /**
     * Return the index of the last (counting from tail) element equal to
     * <code>e1</code>. The index points to the {@link #buffer} array.
     *  
     * @param e1 The element to look for.
     * @return Returns the index of the first element equal to <code>e1</code>
     * or <code>-1</code> if not found.
     */
    public int lastBufferIndexOf(float e1)
    {
        final int bufLen = buffer.length;
        final int last = oneLeft(head, bufLen);
        for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen))
        {
            if ((e1 ==  buffer[i]))
                return i;
        }

        return -1;
    }
   
    /**
     * {@inheritDoc}
     */
    @Override
    public int removeAllOccurrences(float e1)
    {
        int removed = 0;
        final int last = tail;
        final int bufLen = buffer.length;
        int from, to;
        for (from = to = head; from != last; from = oneRight(from, bufLen))
        {
            if ((e1 ==  buffer[from]))
            {
                buffer[from] = ((float) 0);
                removed++;
                continue;
            }
   
            if (to != from)
            {
                buffer[to] = buffer[from];
                buffer[from] = ((float) 0);
            }
   
            to = oneRight(to, bufLen);
        }
   
        tail = to;
        return removed;
    }

    /**
     * Removes the element at <code>index</code> in the internal
     * {#link {@link #buffer}} array, returning its value.
     *
     * @param index Index of the element to remove. The index must be located between
     * {@link #head} and {@link #tail} in modulo {@link #buffer} arithmetic.
     */
    public void removeAtBufferIndex(int index)
    {
        assert (head <= tail
            ? index >= head && index < tail
            : index >= head || index < tail) : "Index out of range (head="
                + head + ", tail=" + tail + ", index=" + index + ").";

        // Cache fields in locals (hopefully moved to registers).
        final float [] b = this.buffer;
        final int bufLen = b.length;
        final int lastIndex = bufLen - 1;
        final int head = this.head;
        final int tail = this.tail;

        final int leftChunk = Math.abs(index - head) % bufLen;
        final int rightChunk = Math.abs(tail - index) % bufLen;

        if (leftChunk < rightChunk)
        {
            if (index >= head)
            {
                System.arraycopy(b, head, b, head + 1, leftChunk);
            }
            else
            {
                System.arraycopy(b, 0, b, 1, index);
                b[0] = b[lastIndex];
                System.arraycopy(b, head, b, head + 1, lastIndex - head);
            }
            b[head] = ((float) 0);
            this.head = oneRight(head, bufLen);
        }
        else
        {
            if (index < tail)
            {
                System.arraycopy(b, index + 1, b, index, rightChunk);
            }
            else
            {
                System.arraycopy(b, index + 1, b, index, lastIndex - index);
                b[lastIndex] = b[0];
                System.arraycopy(b, 1, b, 0, tail);
            }
            b[tail] = ((float) 0);
            this.tail = oneLeft(tail, bufLen);
        }
    }
   
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isEmpty()
    {
        return size() == 0;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int size()
    {
        if (head <= tail)
            return tail - head;
        else
            return (tail - head + buffer.length);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The internal array buffers are not released as a result of this call.</p>
     *
     * @see #release()
     */
    @Override
    public void clear()
    {
        if (head < tail)
        {
            Arrays.fill(buffer, head, tail, ((float) 0));
        }
        else
        {
            Arrays.fill(buffer, 0, tail, ((float) 0));
            Arrays.fill(buffer, head, buffer.length, ((float) 0));
        }
        this.head = tail = 0;
    }

    /**
     * Release internal buffers of this deque and reallocate the smallest buffer possible.
     */
    public void release()
    {
        this.head = tail = 0;
        final int size = resizer.round(DEFAULT_CAPACITY);
        buffer = new float [size];
    }

    /**
     * Ensures the internal buffer has enough free slots to store
     * <code>expectedAdditions</code>. Increases internal buffer size if needed.
     */
    protected final void ensureBufferSpace(int expectedAdditions)
    {
        final int bufferLen = (buffer == null ? 0 : buffer.length);
        final int elementsCount = size();
        // +1 because there is always one empty slot in a deque.
        final int requestedMinimum = 1 + elementsCount + expectedAdditions;
        if (requestedMinimum >= bufferLen)
        {
            final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions + 1);
            assert newSize >= requestedMinimum : "Resizer failed to" +
                    " return sensible new size: " + newSize + " <= "
                    + (elementsCount + expectedAdditions);

            final float [] newBuffer = new float [newSize];
            if (bufferLen > 0)
            {
                toArray(newBuffer);
                tail = elementsCount;
                head = 0;

                /* removeIf:applied. */
            }
            this.buffer = newBuffer;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public float [] toArray()
    {
        final int size = size();
        return toArray(new float [size]);
    }

    /**
     * Copies elements of this deque to an array. The content of the <code>target</code>
     * array is filled from index 0 (head of the queue) to index <code>size() - 1</code>
     * (tail of the queue).
     *
     * @param target The target array must be large enough to hold all elements.
     */
    public float [] toArray(float [] target)
    {
        assert target.length >= size() : "Target array must be >= " + size();

        if (head < tail)
        {
            // The contents is not wrapped around. Just copy.
            System.arraycopy(buffer, head, target, 0, size());
        }
        else if (head > tail)
        {
            // The contents is split. Merge elements from the following indexes:
            // [head...buffer.length - 1][0, tail - 1]
            final int rightCount = buffer.length - head;
            System.arraycopy(buffer, head, target, 0, rightCount);
            System.arraycopy(buffer,    0, target, rightCount, tail);
        }

        return target;
    }

    /**
     * Move one index to the left, wrapping around buffer.
     */
    final static int oneLeft(int index, int modulus)
    {
        if (index >= 1) return index - 1;
        return modulus - 1;
    }

    /**
     * Move one index to the right, wrapping around buffer.
     */
    final static int oneRight(int index, int modulus)
    {
        if (index + 1 == modulus) return 0;
        return index + 1;
    }

    /**
     * An iterator implementation for {@link FloatArrayDeque#iterator}.
     */
    private final class ValueIterator implements Iterator<FloatCursor>
    {
        private final FloatCursor cursor;
        private int remaining;

        public ValueIterator()
        {
            cursor = new FloatCursor();
            cursor.index = oneLeft(head, buffer.length);
            this.remaining = size();
        }

        public boolean hasNext()
        {
            return remaining > 0;
        }

        public FloatCursor next()
        {
            if (remaining == 0)
                throw new NoSuchElementException();

            remaining--;
            cursor.index = oneRight(cursor.index, buffer.length);
            cursor.value = buffer[cursor.index];
            return cursor;
        }

        public void remove()
        {
            /*
             * It will be much more efficient to have a removal using a closure-like
             * structure (then we can simply move elements to proper slots as we iterate
             * over the array as in #removeAll).
             */
            throw new UnsupportedOperationException();
        }
    }

    /**
     * An iterator implementation for {@link FloatArrayDeque#descendingIterator()}.
     */
    private final class DescendingIterator implements Iterator<FloatCursor>
    {
        private final FloatCursor cursor;
        private int remaining;

        public DescendingIterator()
        {
            cursor = new FloatCursor();
            cursor.index = tail;
            this.remaining = size();
        }

        public boolean hasNext()
        {
            return remaining > 0;
        }

        public FloatCursor next()
        {
            if (remaining == 0)
                throw new NoSuchElementException();

            remaining--;
            cursor.index = oneLeft(cursor.index, buffer.length);
            cursor.value = buffer[cursor.index];
            return cursor;
        }

        public void remove()
        {
            /*
             * It will be much more efficient to have a removal using a closure-like
             * structure (then we can simply move elements to proper slots as we iterate
             * over the array as in #removeAll).
             */
            throw new UnsupportedOperationException();
        }
    }

    /**
     * Returns a cursor over the values of this deque (in head to tail order). The
     * iterator is implemented as a cursor and it returns <b>the same cursor instance</b>
     * on every call to {@link Iterator#next()} (to avoid boxing of primitive types). To
     * read the current value (or index in the deque's buffer) use the cursor's public
     * fields. An example is shown below.
     *
     * <pre>
     * for (IntValueCursor c : intDeque)
     * {
     *     System.out.println(&quot;buffer index=&quot;
     *         + c.index + &quot; value=&quot; + c.value);
     * }
     * </pre>
     */
    public Iterator<FloatCursor> iterator()
    {
        return new ValueIterator();
    }

    /**
     * Returns a cursor over the values of this deque (in tail to head order). The
     * iterator is implemented as a cursor and it returns <b>the same cursor instance</b>
     * on every call to {@link Iterator#next()} (to avoid boxing of primitive types). To
     * read the current value (or index in the deque's buffer) use the cursor's public
     * fields. An example is shown below.
     *
     * <pre>
     * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext(); )
     * {
     *     final IntCursor c = i.next();
     *     System.out.println(&quot;buffer index=&quot;
     *         + c.index + &quot; value=&quot; + c.value);
     * }
     * </pre>
     */
    public Iterator<FloatCursor> descendingIterator()
    {
        return new DescendingIterator();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends FloatProcedure> T forEach(T procedure)
    {
        forEach(procedure, head, tail);
        return procedure;
    }

    /**
     * Applies <code>procedure</code> to a slice of the deque,
     * <code>fromIndex</code>, inclusive, to <code>toIndex</code>,
     * exclusive.
     */
    private void forEach(FloatProcedure procedure, int fromIndex, final int toIndex)
    {
        final float [] buffer = this.buffer;
        for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length))
        {
            procedure.apply(buffer[i]);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends FloatPredicate> T forEach(T predicate)
    {
        int fromIndex = head;
        int toIndex = tail;

        final float [] buffer = this.buffer;
        for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length))
        {
            if (!predicate.apply(buffer[i]))
                break;
        }
       
        return predicate;
    }

    /**
     * Applies <code>procedure</code> to all elements of this deque, tail to head.
     */
    @Override
    public <T extends FloatProcedure> T descendingForEach(T procedure)
    {
        descendingForEach(procedure, head, tail);
        return procedure;
    }

    /**
     * Applies <code>procedure</code> to a slice of the deque,
     * <code>toIndex</code>, exclusive, down to <code>fromIndex</code>, inclusive.
     */
    private void descendingForEach(FloatProcedure procedure,
        int fromIndex, final int toIndex)
    {
        if (fromIndex == toIndex)
            return;

        final float [] buffer = this.buffer;
        int i = toIndex;
        do
        {
            i = oneLeft(i, buffer.length);
            procedure.apply(buffer[i]);
        } while (i != fromIndex);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends FloatPredicate> T descendingForEach(T predicate)
    {
        descendingForEach(predicate, head, tail);
        return predicate;
    }
   
    /**
     * Applies <code>predicate</code> to a slice of the deque,
     * <code>toIndex</code>, exclusive, down to <code>fromIndex</code>, inclusive
     * or until the predicate returns <code>false</code>.
     */
    private void descendingForEach(FloatPredicate predicate,
        int fromIndex, final int toIndex)
    {
        if (fromIndex == toIndex)
            return;

        final float [] buffer = this.buffer;
        int i = toIndex;
        do
        {
            i = oneLeft(i, buffer.length);
            if (!predicate.apply(buffer[i]))
                break;
        } while (i != fromIndex);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int removeAll(FloatPredicate predicate)
    {
        int removed = 0;
        final int last = tail;
        final int bufLen = buffer.length;
        int from, to;
        from = to = head;
        try
        {
            for (from = to = head; from != last; from = oneRight(from, bufLen))
            {
                if (predicate.apply(buffer[from]))
                {
                    buffer[from] = ((float) 0);
                    removed++;
                    continue;
                }
   
                if (to != from)
                {
                    buffer[to] = buffer[from];
                    buffer[from] = ((float) 0);
                }
       
                to = oneRight(to, bufLen);
            }
        }
        finally
        {
            // Keep the deque in consistent state even if the predicate throws an exception.
            for (; from != last; from = oneRight(from, bufLen))
            {
                if (to != from)
                {
                    buffer[to] = buffer[from];
                    buffer[from] = ((float) 0);
                }
       
                to = oneRight(to, bufLen);
            }
            tail = to;
        }

        return removed;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean contains(float e)
    {
        int fromIndex = head;
        int toIndex = tail;

        final float [] buffer = this.buffer;
        for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length))
        {
            if ((e ==  buffer[i]))
                return true;
        }

        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
        int h = 1;
        int fromIndex = head;
        int toIndex = tail;

        final float [] buffer = this.buffer;
        for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length))
        {
            h = 31 * h + hashFunction.hash(this.buffer[i]);
        }
        return h;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    /* removeIf:applied. */
    public boolean equals(Object obj)
    {
        if (obj != null)
        {
            if (obj instanceof FloatDeque)
            {
                FloatDeque other = (FloatDeque) obj;
                if (other.size() == this.size())
                {
                    int fromIndex = head;
                    final float [] buffer = this.buffer;
                    int i = fromIndex;
                    for (FloatCursor c : other)
                    {
                        if (!(c.value ==  buffer[i]))
                            return false;
                        i = oneRight(i, buffer.length);                       
                    }
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Create a new deque by pushing a variable number of arguments to the end of it.
     */
    public static /* removeIf:applied. */
        FloatArrayDeque from(float... elements)
    {
        final FloatArrayDeque coll = new FloatArrayDeque(elements.length);
        coll.addLast(elements);
        return coll;
    }

    /**
     * Create a new deque by pushing a variable number of arguments to the end of it.
     */
    public static /* removeIf:applied. */
        FloatArrayDeque from(FloatContainer container)
    {
        return new FloatArrayDeque(container);
    }
}
TOP

Related Classes of com.carrotsearch.hppc.FloatArrayDeque$ValueIterator

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.