All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.util.SimpleLongArray Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */

package com.tangosol.util;


import java.io.Serializable;

import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;


/**
* An implementation of LongArray that stores values in an array, thus is
* actually an "IntArray". Optimized for 0-based arrays. Null values are
* not considered to be entries, thus will not affect "first" and "last"
* and will not show up in the iterator. Note: not designed to be thread
* safe.
*
* @author cp
* @version 1.00 2003.04.09
*/
public class SimpleLongArray
        extends AbstractLongArray
        implements Serializable, LongArray
    {
    // ----- constructors ---------------------------------------------------

    /**
    * Construct an empty SimpleLongArray.
    */
    public SimpleLongArray()
        {
        clear();
        }

    /**
     * Create a {@link SimpleLongArray} with a single entry
     * at index zero.
     *
     * @param oValue  the value to add at index zero
     * @throws NullPointerException if the value is {@code null}
     */
    public SimpleLongArray(Object oValue)
        {
        if (oValue == null)
            {
            throw new NullPointerException("value cannot be null");
            }
        m_ao     = new Object[]{oValue};
        m_iFirst = 0;
        m_iLast  = 0;
        m_cItems = 1;
        }

    // ----- LongArray interface --------------------------------------------

    /**
    * Return the value stored at the specified index.
    *
    * @param lIndex  a long index value
    *
    * @return the object stored at the specified index, or null
    */
    public Object get(long lIndex)
        {
        if (lIndex < 0L || lIndex > MAX)
            {
            throw new IndexOutOfBoundsException("illegal index: " + lIndex);
            }

        int i = (int) lIndex;
        if (i < m_iFirst || i > m_iLast)
            {
            return null;
            }

        return m_ao[i];
        }

    @Override
    public long floorIndex(long lIndex)
        {
        int i = (int) lIndex;
        if (i < m_iFirst)
            {
            return NOT_FOUND;
            }
        else if (i > m_iLast)
            {
            return m_iLast;
            }
        else
            {
            return i;
            }
        }

    @Override
    public Object floor(long lIndex)
        {
        return get(floorIndex(lIndex));
        }

    @Override
    public long ceilingIndex(long lIndex)
        {
        int i = (int) lIndex;
        if (i < m_iFirst)
            {
            return m_iFirst;
            }
        else if (i > m_iLast)
            {
            return NOT_FOUND;
            }
        else
            {
            return i;
            }
        }

    @Override
    public Object ceiling(long lIndex)
        {
        return get(ceilingIndex(lIndex));
        }

    /**
    * Add the passed item to the LongArray at the specified index.
    * 

* If the index is already used, the passed value will replace the current * value stored with the key, and the replaced value will be returned. *

* It is expected that LongArray implementations will "grow" as necessary * to support the specified index. * * @param lIndex a long index value * @param oValue the object to store at the specified index * * @return the object that was stored at the specified index, or null */ public Object set(long lIndex, Object oValue) { // this implementation does not "manage" nulls if (oValue == null) { return remove(lIndex); } if (lIndex < 0L || lIndex > MAX) { throw new IndexOutOfBoundsException("illegal index: " + lIndex); } int iFirst = m_iFirst; int iLast = m_iLast; int cItems = m_cItems; Object[] ao = m_ao; int co = ao.length; int i = (int) lIndex; // ensure enough storage if (i >= co) { // grow at least to that 64 element block, and at least 25% int coNew = Math.max(((i >>> 5) + 1) << 5, co + (co >>> 2)); Object[] aoNew = new Object[coNew]; if (cItems > 0) { System.arraycopy(ao, iFirst, aoNew, iFirst, iLast - iFirst + 1); } m_ao = ao = aoNew; } // get the previous value, store the new value Object oOrig = ao[i]; ao[i] = oValue; // if it was previously null, the array size will change and the // first and/or last index could change if (oOrig == null) { if (cItems == 0) { m_iFirst = i; m_iLast = i; m_cItems = 1; } else { if (i < iFirst) { m_iFirst = i; } else if (i > iLast) { m_iLast = i; } m_cItems = cItems + 1; } } return oOrig; } /** * Add the passed element value to the LongArray and return the index at * which the element value was stored. * * @param oValue the object to add to the LongArray * * @return the long index value at which the element value was stored */ public long add(Object oValue) { int i = m_iLast + 1; set(i, oValue); return i; } /** * Determine if the specified index is in use. * * @param lIndex a long index value * * @return true if a value (including null) is stored at the specified * index, otherwise false */ public boolean exists(long lIndex) { if (lIndex >= 0L && lIndex < MAX) { int i = (int) lIndex; if (i >= m_iFirst && i <= m_iLast) { return m_ao[i] != null; } } return false; } /** * Remove the specified index from the LongArray, returning its associated * value. * * @param lIndex the index into the LongArray * * @return the associated value (which can be null) or null if the * specified index is not in the LongArray */ public Object remove(long lIndex) { if (lIndex < 0L || lIndex > MAX) { throw new IndexOutOfBoundsException("illegal index: " + lIndex); } // if it is out of the array bounds, then nothing to remove int iFirst = m_iFirst; int iLast = m_iLast; int i = (int) lIndex; if (i < iFirst || i > iLast) { return null; } // if it is null, then nothing to remove Object[] ao = m_ao; Object oOrig = ao[i]; if (oOrig == null) { return null; } int cItems = m_cItems; if (cItems == 1) { // last item clear(); } else { // remove the item ao[i] = null; m_cItems = cItems - 1; // check to see if it affects the bounds of the array if (i == iFirst) { while (ao[++iFirst] == null) { } m_iFirst = iFirst; } else if (i == iLast) { while (ao[--iLast] == null) { } m_iLast = iLast; } } return oOrig; } /** * Determine if the LongArray contains the specified element. *

* More formally, returns true if and only if this LongArray * contains at least one element e such that * (oValue==null ? e==null : oValue.equals(e)). * * @param oValue element whose presence in this list is to be tested * * @return true if this list contains the specified element */ public boolean contains(Object oValue) { // SimpleLongArray doesn't manage negative indices return indexOf(oValue, 0) != NOT_FOUND; } /** * Remove all nodes from the LongArray. */ public void clear() { m_ao = EMPTY; m_iFirst = -1; m_iLast = -1; m_cItems = 0; } /** * Test for empty LongArray. * * @return true if LongArray has no nodes */ public boolean isEmpty() { return m_cItems == 0; } /** * Determine the size of the LongArray. * * @return the number of nodes in the LongArray */ public int getSize() { return m_cItems; } /** * Obtain a LongArray.Iterator of the contents of the LongArray. * * @return an instance of LongArray.Iterator */ public LongArray.Iterator iterator() { return new Iterator(Math.max(0, m_iFirst), true); } /** * Obtain a LongArray.Iterator of the contents of the LongArray, starting * at a particular index such that the first call to next will * set the location of the iterator at the first existent index that is * greater than or equal to the specified index, or will throw a * NoSuchElementException if there is no such existent index. * * @param lIndex the LongArray index to iterate from * * @return an instance of LongArray.Iterator */ public LongArray.Iterator iterator(long lIndex) { if (lIndex < 0L || lIndex > MAX) { throw new IndexOutOfBoundsException("illegal index: " + lIndex); } return new Iterator((int) lIndex, true); } /** * Obtain a LongArray.Iterator of the contents of the LongArray in * reverse order (decreasing indices). * * @return an instance of LongArray.Iterator */ public LongArray.Iterator reverseIterator() { return new Iterator(Math.max(0, m_iLast), false); } /** * Obtain a LongArray.Iterator of the contents of the LongArray in * reverse order (decreasing indices), starting at a particular * index such that the first call to next will set the * location of the iterator at the first existent index that is * less than or equal to the specified index, or will throw a * NoSuchElementException if there is no such existent index. * * @param lIndex the LongArray index to iterate from * * @return an instance of LongArray.Iterator */ public LongArray.Iterator reverseIterator(long lIndex) { if (lIndex < 0L || lIndex > MAX) { throw new IndexOutOfBoundsException("illegal index: " + lIndex); } return new Iterator((int) lIndex, false); } /** * Determine the first index that exists in the LongArray. * * @return the lowest long value that exists in this LongArray, * or NOT_FOUND if the LongArray is empty */ public long getFirstIndex() { return m_iFirst == -1 ? NOT_FOUND : (long) m_iFirst; } /** * Determine the last index that exists in the LongArray. * * @return the highest long value that exists in this LongArray, * or NOT_FOUND if the LongArray is empty */ public long getLastIndex() { return m_iLast == -1 ? NOT_FOUND : (long) m_iLast; } /** * Return the index in this LongArray of the first occurrence of * the specified element such that (index >= lIndex), or * NOT_FOUND if this LongArray does not contain the specified element. */ public long indexOf(Object oValue, long lIndex) { if (oValue == null || m_iFirst == -1) { // this implementation does not "manage" nulls return NOT_FOUND; } // valid search range is [0, MAX] int iFirst = (int)Math.min(Math.max(0, lIndex), MAX); int iLast = m_iLast; // search through everything Object[] ao = m_ao; for (int i = iFirst; i <= iLast; ++i) { Object oElement = ao[i]; if (oElement != null && oValue.equals(oElement)) { return i; } } return NOT_FOUND; } /** * Return the index in this LongArray of the last occurrence of * the specified element such that (index <= lIndex), or * NOT_FOUND if this LongArray does not contain the specified element. */ public long lastIndexOf(Object oValue, long lIndex) { if (oValue == null || m_iFirst == -1) { // this implementation does not "manage" nulls return NOT_FOUND; } // valid search range is [0, MAX] int iFirst = m_iFirst; int iLast = (int)Math.min(lIndex, MAX); // search through everything Object[] ao = m_ao; for (int i = iLast; i >= iFirst; --i) { Object oElement = ao[i]; if (oElement != null && oValue.equals(oElement)) { return i; } } return NOT_FOUND; } // ----- cloneable interface -------------------------------------------- /** * Make a clone of the LongArray. The element values are not deep-cloned. * * @return a clone of this LongArray object */ public SimpleLongArray clone() { SimpleLongArray that = (SimpleLongArray) super.clone(); Object[] ao = that.m_ao; if (ao != null && ao.length != 0) { that.m_ao = (Object[]) ao.clone(); } return that; } // ----- inner class: Iterator ------------------------------------------ /** * An Iterator that adds a "current element" concept, similar to the * {@link java.util.Map.Entry} interface. */ public class Iterator implements LongArray.Iterator { // ----- constructors ------------------------------------------- /** * Construct an iterator that will iterate over the SimpleLongArray * starting with the specified index. * * @param iNext the index to start iterating from */ public Iterator(int iNext, boolean fForward) { m_iNext = (fForward ? Math.max(m_iFirst, iNext) : Math.min(m_iLast, iNext)); m_iPrev = -1; m_fForward = fForward; if (!exists(m_iNext)) { scanNext(); } } // ----- LongArray.Iterator interface --------------------------- /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an * element rather than throwing an exception.) * * @return true if the iterator has more elements */ public boolean hasNext() { return m_iNext >= m_iFirst && m_iNext <= m_iLast && m_iNext >= 0; } /** * Returns the next element in the iteration. * * @return the next element in the iteration * * @exception NoSuchElementException iteration has no more elements */ public Object next() { int i = m_iNext; if ((i > m_iLast) || (i < m_iFirst)) { throw new NoSuchElementException(); } Object o = get(i); if (o == null) { throw new ConcurrentModificationException(); } m_iPrev = i; scanNext(); return o; } /** * Returns the index of the current value, which is the value returned * by the most recent call to the next method. * * @exception IllegalStateException if the next method has * not yet been called, or the remove method has * already been called after the last call to the * next method. */ public long getIndex() { int i = m_iPrev; if (i < 0) { throw new IllegalStateException(); } return i; } /** * Returns the current value, which is the same value returned by the * most recent call to the next method, or the most recent * value passed to setValue if setValue were called * after the next method. * * @return the current value * * @exception IllegalStateException if the next method has * not yet been called, or the remove method has * already been called after the last call to the * next method. */ public Object getValue() { return get(getIndex()); } /** * Stores a new value at the current value index, returning the value * that was replaced. The index of the current value is obtainable by * calling the getIndex method. * * @return the replaced value * * @exception IllegalStateException if the next method has * not yet been called, or the remove method has * already been called after the last call to the * next method. */ public Object setValue(Object oValue) { Object oOrig = set(getIndex(), oValue); if (oValue == null) { m_iPrev = -1; } return oOrig; } /** * Removes from the underlying collection the last element returned by * the iterator (optional operation). This method can be called only * once per call to next. The behavior of an iterator is * unspecified if the underlying collection is modified while the * iteration is in progress in any way other than by calling this * method. * * @exception UnsupportedOperationException if the remove * operation is not supported by this Iterator * @exception IllegalStateException if the next method has * not yet been called, or the remove method has * already been called after the last call to the * next method. */ public void remove() { SimpleLongArray.this.remove(getIndex()); m_iPrev = -1; } // ----- internal ----------------------------------------------- /** * Find the next non-null element in the array. */ private void scanNext() { Object[] ao = m_ao; int iDelta = (m_fForward ? 1 : -1); int i = m_iNext; int iFirst = m_iFirst; int iLast = m_iLast; do { i += iDelta; } while (i >= iFirst && i <= iLast && i >= 0 && ao[i] == null); m_iNext = i; } // ----- data members ------------------------------------------- /** * Is the iteratation direction forward or backward. */ private boolean m_fForward; /** * Next index to return or greater than m_iLast if no more. */ private int m_iNext; /** * Previous returned object's index or -1 if n/a. */ private int m_iPrev; } // ----- constants ------------------------------------------------------ /** * Maximum index value. */ public static final long MAX = (long) Integer.MAX_VALUE; /** * Empty array of objects. */ public static final Object[] EMPTY = new Object[0]; // ----- data members --------------------------------------------------- /** * Contents of the array. */ Object[] m_ao; /** * First valid index or -1 if empty. */ int m_iFirst; /** * Last valid index of -1 if empty. */ int m_iLast; /** * Number of valid indexes (non-null values) in the array. */ int m_cItems; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy