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

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

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

package com.tangosol.util;


import com.tangosol.io.ExternalizableLite;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.NotActiveException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

import java.lang.reflect.Array;

import java.util.AbstractList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.Spliterator;


/**
* Implementation of the Collection Framework interface "List" in a read-
* only fashion on top of an array data structure.
* 

* This class also implements the Set interface, although the contents are * not checked to determine whether each element is unique. It is the * responsibility of the user to ensure that the elements are unique if the * object is used as a Set. *

* Note: while preserved for backward compatibility, as of Coherence 3.6, use of * this class specifically as a List or a Set is deprecated. Instead, the * {@link #getList}, {@link #getSet}, and {@link #getSortedSet} methods * should be used. * * @author cp 2001.10.09 */ public class ImmutableArrayList extends AbstractList implements Collection, List, Set, SortedSet, Comparable, Cloneable, ExternalizableLite { // ----- constructors --------------------------------------------------- /** * Construct a List from a specified number of items in an array starting at * the specified offset. * * @param ao a non-null array of Objects * @param of an offset of the first item in the array * @param c the number of items to use */ public ImmutableArrayList(Object[] ao, int of, int c) { Base.azzert(ao != null); Base.azzert(ao.length >= of + c); m_ao = ao; m_of = of; m_c = c; } /** * Construct a List from an array. * * @param ao a non-null array of Objects */ public ImmutableArrayList(Object[] ao) { this(ao, 0, ao == null ? 0 : ao.length); } /** * Construct a List containing the elements of the specified Collection. * * @param collection the Collection to fill this List from */ public ImmutableArrayList(Collection collection) { this(collection.toArray()); } /** * Default constructor (necessary for the ExternalizableLite interface). */ public ImmutableArrayList() { } // ----- accessors ------------------------------------------------------ /** * Return a java.util.List view of this ImmutableArrayList. * * @return a List view of this ImmutableArrayList */ public List getList() { return new ListView(); } /** * Return a java.util.Set view of this ImmutableArrayList. *

* Note: this method does not ensure that the underlying ImmutableArrayList * adheres to the Set contract. It is the responsibility of the * user to ensure that the elements are unique if the object is used * as a Set. * * @return a Set view of this ImmutableArrayList */ public Set getSet() { return new SetView(); } /** * Return a java.util.SortedSet view of this ImmutableArrayList. *

* Note: this method does not ensure that the underlying ImmutableArrayList * adheres to the SortedSet contract. It is the responsibility of the * user to ensure that the elements are unique and ordered if the * object is used as a SortedSet. * * @return a SortedSet view of this ImmutableArrayList */ public SortedSet getSortedSet() { return new SortedSetView(); } // ----- List interface ------------------------------------------------- @Override public Spliterator spliterator() { return super.spliterator(); } /** * Returns the number of elements in this List. * * @return the number of elements in this List */ public int size() { return m_c; } /** * Returns the element at the specified position in this List. * * @param i the index of the element to return * * @return the element at the specified position in this List * * @throws IndexOutOfBoundsException if the index is out of range (index * < 0 || index >= size()). */ public Object get(int i) { int of = m_of + i; if (of >= m_c) { throw new IndexOutOfBoundsException(m_of + "+" + i + ">=" + m_c); } return m_ao[of]; } /** * Returns the index in this List of the first occurrence of the specified * element, or -1 if this List does not contain this element. More * formally, returns the lowest index i such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * * @param o element to search for. * * @return the index in this List of the first occurrence of the specified * element, or -1 if this List does not contain this element. */ public int indexOf(Object o) { // check index Map map = getValueIndex(); if (map != null) { Integer I = (Integer) map.get(o); return I == null ? -1 : I.intValue(); } // sequential search Object[] ao = m_ao; for (int i = 0, of = m_of, c = m_c; i < c; ++i) { if (Base.equals(ao[of + i], o)) { return i; } } return -1; } /** * Returns the index in this List of the last occurrence of the specified * element, or -1 if this List does not contain this element. More * formally, returns the highest index i such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * * @param o element to search for. * * @return the index in this List of the last occurrence of the specified * element, or -1 if this List does not contain this element. */ public int lastIndexOf(Object o) { // check index Map map = getValueIndex(); if (map != null) { Integer I = (Integer) map.get(o); // three possibilities: // 1) the value is not in the index, so it is not in the List // 2) the value is in the index, so the answer is known // 3) the value is in the index, but the index size is not the // same as the List size because the values in the List are // not all unique if (I == null) { return -1; } else if (size() == map.size()) { return I.intValue(); } // since there are duplicates, fall through and do a sequential // search } // sequential search Object[] ao = m_ao; int of = m_of; for (int i = m_c - 1; i >= 0; --i) { if (Base.equals(ao[of + i], o)) { return i; } } return -1; } /** * Returns true if this List contains the specified element. * More formally, returns true if and only if this List contains * at least one element e such that * (o==null ? e==null : o.equals(e)). * * @param o element whose presence in this List is to be tested * * @return true if this List contains the specified element */ public boolean contains(Object o) { return indexOf(o) != -1; } /** * Returns an array containing all of the elements in this List in the * order that the elements occur in the List. The returned array will * be "safe" in that no references to it are maintained by the List. * The caller is thus free to modify the returned array.

* * @return an array containing all of the elements in this List */ public Object[] toArray() { Object[] ao = m_ao; int c = m_c; if (c == ao.length) { return ao.clone(); } else { Object[] aoTemp = new Object[c]; System.arraycopy(ao, m_of, aoTemp, 0, c); return aoTemp; } } /** * Returns an array with ao runtime type is that of the specified array and * that contains all of the elements in this List. If the elements all * fit in the specified array, it is returned therein. Otherwise, ao new * array is allocated with the runtime type of the specified array and the * size of this List.

* * If the List fits in the specified array with room to spare (i.e., the * array has more elements than the List), the element in the array * immediately following the end of the last element is set to * null. This is useful in determining the length of the List * only if the caller knows that the List does not contain any * null elements.)

* * @param ao the array into which the elements of the List are to be * stored, if it is big enough; otherwise, ao new array of the * same runtime type is allocated for this purpose * * @return an array containing the elements of the List * * @throws ArrayStoreException if the runtime type of the specified array * is not ao supertype of the runtime type of every element in this * List */ public Object[] toArray(Object ao[]) { // create the array to store the map contents int c = m_c; if (ao == null) { // implied Object[] type ao = new Object[c]; } else if (ao.length < c) { // if it is not big enough, ao new array of the same runtime // type is allocated ao = (Object[]) Array.newInstance(ao.getClass().getComponentType(), c); } else if (ao.length > c) { // if the collection fits in the specified array with room to // spare, the element in the array immediately following the // end of the collection is set to null ao[c] = null; } System.arraycopy(m_ao, m_of, ao, 0, c); return ao; } /** * Returns an iterator over the elements in this list in proper * sequence. * * @return an iterator over the elements in this list in proper sequence. */ public Iterator iterator() { return new SimpleEnumerator(m_ao, m_of, m_c); } // ----- SortedSet interface -------------------------------------------- /** * Returns the comparator associated with this sorted set, or * null if it uses its elements' natural ordering. * * @return the comparator associated with this sorted set, or * null if it uses its elements' natural ordering */ public Comparator comparator() { return (o1, o2) -> { int iPos1 = indexOf(o1); if (iPos1 == -1) { throw new IllegalArgumentException("missing element: " + o1); } int iPos2 = indexOf(o2); if (iPos2 == -1) { throw new IllegalArgumentException("missing element: " + o2); } return iPos1 - iPos2; }; } /** * Returns the first element currently in this sorted set. * * @return the first element currently in this sorted set * * @throws NoSuchElementException if the sorted set is empty */ public Object first() { if (isEmpty()) { throw new NoSuchElementException(); } return get(0); } /** * Returns the last element currently in this sorted set. * * @return the last element currently in this sorted set * * @throws NoSuchElementException if the sorted set is empty */ public Object last() { if (isEmpty()) { throw new NoSuchElementException(); } return get(size() - 1); } /** * Returns a view of the portion of this sorted set whose elements are * found in the set in a position before toElement. * * @param toElement high endpoint (exclusive) of the headSet * * @return a view of the specified initial range of this sorted set * * @throws IllegalArgumentException if toElement is not found in * the SortedSet */ public SortedSet headSet(Object toElement) { int iPos = indexOf(toElement); if (iPos < 0) { throw new IllegalArgumentException("no such element: " + toElement); } return new ImmutableArrayList(m_ao, m_of, iPos); } /** * Returns a view of the portion of this sorted set whose elements are * found in the set in a position at and after the position of * fromElement. * * @param fromElement the first element to include in the resulting set * * @return a view of the specified final range of this sorted set * * @throws IllegalArgumentException if fromElement is not found * in the SortedSet */ public SortedSet tailSet(Object fromElement) { int iPos = lastIndexOf(fromElement); if (iPos < 0) { throw new IllegalArgumentException("no such element: " + fromElement); } return new ImmutableArrayList(m_ao, m_of + iPos, m_c - iPos); } /** * Returns a view of the portion of this sorted set whose elements are * found in the set in a position at and after the position of * fromElement and in a position before toElement. * * @param fromElement the first element to include in the resulting set * @param toElement the first element following fromElement to * not include in the resulting set * * @return a view of the specified range of this sorted set * * @throws IllegalArgumentException if either fromElement or * toElement is not found in the SortedSet */ public SortedSet subSet(Object fromElement, Object toElement) { int iPosBegin = lastIndexOf(fromElement); if (iPosBegin < 0) { throw new IllegalArgumentException("no such element: " + fromElement); } int iPosEnd = indexOf(toElement); if (iPosEnd < 0) { throw new IllegalArgumentException("no such element: " + toElement); } return iPosBegin < iPosEnd ? new ImmutableArrayList(m_ao, m_of + iPosBegin, iPosEnd - iPosBegin) : new ImmutableArrayList(m_ao, 0, 0); } // ----- Cloneable interface -------------------------------------------- /** * Create a clone of the ImmutableArrayList. * * @return a clone of this list */ public Object clone() { try { // since the array is immutable we can return a shallow clone return super.clone(); } catch (CloneNotSupportedException e) { throw Base.ensureRuntimeException(e); } } // ----- ExternalizableLite interface ----------------------------------- /** * {@inheritDoc} */ public void readExternal(DataInput in) throws IOException { if (m_c > 0) { throw new NotActiveException(); } int c = m_c = ExternalizableHelper.readInt(in); if (c == 0) { m_ao = new Object[0]; } else if (in.readBoolean()) // fLite { m_ao = c < ExternalizableHelper.CHUNK_THRESHOLD >> 4 ? ExternalizableHelper.readObjectArray(in, c) : ExternalizableHelper.readLargeObjectArray(in, c); } else { try { m_ao = (Object[]) ExternalizableHelper.getObjectInput(in, null).readObject(); } catch (ClassNotFoundException e) { throw new IOException("readObject failed: " + e + "\n" + Base.getStackTrace(e)); } } } /** * {@inheritDoc} */ public void writeExternal(DataOutput out) throws IOException { int c = m_c; Object[] ao = m_ao; ExternalizableHelper.writeInt(out, c); if (c == 0) { return; } // scan through the contents searching for anything that cannot be // streamed to a DataOutput (i.e. anything that requires Java Object // serialization); boolean fLite = true; final int FMT_OBJ_SER = ExternalizableHelper.FMT_OBJ_SER; for (int i = 0; i < c; ++i) { if (ExternalizableHelper.getStreamFormat(ao[i]) == FMT_OBJ_SER) { fLite = false; break; } } out.writeBoolean(fLite); if (fLite) { for (int i = 0; i < c; ++i) { ExternalizableHelper.writeObject(out, ao[i]); } } else { ObjectOutput outObj = ExternalizableHelper.getObjectOutput(out); outObj.writeObject(ao); outObj.close(); } } // ----- Serializable interface ----------------------------------------- /** * Write this object to an ObjectOutputStream. * * @param out the ObjectOutputStream to write this object to * * @throws IOException thrown if an exception occurs writing this object */ private void writeObject(ObjectOutputStream out) throws IOException { out.writeInt(m_of); out.writeInt(m_c); out.writeObject(m_ao); } /** * Read this object from an ObjectInputStream. * * @param in the ObjectInputStream to read this object from * * @throws IOException if an exception occurs reading this object * @throws ClassNotFoundException if the class for an object being * read cannot be found */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { m_of = in.readInt(); m_c = in.readInt(); m_ao = (Object[]) in.readObject(); } // ----- Comparable interface ------------------------------------------- /** * Compare this ImmutableArrayList with the passed Object to determine * order. *

* All elements contained in both Lists must implement the Comparable * interface. This method will compare the corresponding list element * left-to-right and will immediately return the first non-zero comparison * result. (A null element is always considered to be "less than" any * non-null element.) *

* If all corresponding elements are equal, this method will return a * negative integer if the size of this List is less than the size of the * specified List, a positive integer if the size of this List is greater, * and zero if the Lists are equal. * * @param o the Object to be compared * * @return a negative integer, zero, or a positive integer as this List * evaluates to less than, equal to, or greater than the * specified List object * * @throws ClassCastException if the specified object does not implement * the {@link List} interface, some elements of either list do * not implement the {@link Comparable} interface, or if an * element object type prevents it from being compared to another * element * @throws NullPointerException if the specified List itself or any of its * elements are null * @since Coherence 3.2 */ public int compareTo(Object o) { Object[] aoThis = m_ao; int ofThis = m_of; int cThis = m_c; Object[] aoThat; int ofThat; int cThat; if (o instanceof ImmutableArrayList) { ImmutableArrayList that = (ImmutableArrayList) o; aoThat = that.m_ao; ofThat = that.m_of; cThat = that.m_c; } else { aoThat = ((Collection) o).toArray(); ofThat = 0; cThat = aoThat.length; } for (int i = 0, c = Math.min(cThis, cThat); i < c; i++) { Object oThis = aoThis[ofThis + i]; Object oThat = aoThat[ofThat + i]; int iResult; if (oThis == null || oThat == null) { iResult = oThis == null ? (oThat == null ? 0 : -1) : +1; } else { iResult = ((Comparable) oThis).compareTo(oThat); } if (iResult != 0) { return iResult; } } return cThis - cThat; } // ----- Object methods ------------------------------------------------- /** * Compare this Collection / List / Set / SortedSet with some other Object * and determine if the caller would believe this Object to equal that * other Object. * * @param o some other Object that is likely to be a Collection or some * more specific type (with its related overloaded definition of * what it thinks that equals() means) * * @return true iff this Object believes that it can make a defensible * case that this Object is equal to the passed Object */ public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof List) { return super.equals(o); } else if (o instanceof Collection) { Collection that = (Collection) o; return this.size() == that.size() && this.containsAll(that); } else { return false; } } // ----- internal ------------------------------------------------------- /** * Create a reverse index from value to position if this List is big * enough to warrant it. * * @return a Map that is keyed by the values in this List, with a * corresponding Map value being the index within this List that * the value is located */ protected Map getValueIndex() { Map map = m_mapValueIndex; if (map == null) { Object[] ao = m_ao; int c = m_c; if (c > 32) // some arbitrarily "larger than a breadbasket" size { map = new HashMap(c + (c >>> 2), 1.0f); // we have to iterate backwards to deal with duplicate values for (int of = m_of, i = c - 1; i >= 0; --i) { map.put(ao[of + i], Integer.valueOf(i)); } m_mapValueIndex = map; } } return map; } // ----- inner class: ListView ------------------------------------------- /** * ListView exposes the underlying ImmutableArrayList through the {@link * java.util.List} interface, maintaining correct equals() and * hashCode() semantics */ protected class ListView extends WrapperCollections.AbstractWrapperList { // ----- constructors --------------------------------------------- /** * Create a ListView over this ImmutableArrayList. */ protected ListView() { super(ImmutableArrayList.this); } // ----- Object methods --------------------------------------------- /** * {@inheritDoc} */ public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof List)) { return false; } Iterator iterThis = iterator(); Iterator iterThat = ((List) o).iterator(); while(iterThis.hasNext() && iterThat.hasNext()) { if (!Base.equals(iterThis.next(), iterThat.next())) { return false; } } return !(iterThis.hasNext() || iterThat.hasNext()); } /** * {@inheritDoc} */ public int hashCode() { int nHash = 1; for (Iterator iter = iterator(); iter.hasNext(); ) { nHash = 31 * nHash + Base.hashCode(iter.next()); } return nHash; } /** * {@inheritDoc} */ public String toString() { return ImmutableArrayList.this.toString(); } } // ----- inner class: SetView ------------------------------------------- /** * SetView exposes the underlying ImmutableArrayList through the {@link * java.util.Set} interface, maintaining correct equals() and * hashCode() semantics */ protected class SetView extends WrapperCollections.AbstractWrapperSet { // ----- constructors --------------------------------------------- /** * Create a SetView over this ImmutableArrayList. */ protected SetView() { super(ImmutableArrayList.this); } // ----- Object methods --------------------------------------------- /** * {@inheritDoc} */ public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Set)) { return false; } Set setOther = (Set) o; return setOther.size() == size() && setOther.containsAll(this); } /** * {@inheritDoc} */ public int hashCode() { int nHash = 0; for (Iterator iter = iterator(); iter.hasNext(); ) { nHash += Base.hashCode(iter.next()); } return nHash; } /** * {@inheritDoc} */ public String toString() { return ImmutableArrayList.this.toString(); } } // ----- inner class: SortedSetView ------------------------------------- /** * SetView exposes the underlying ImmutableArrayList through the {@link * java.util.SortedSet} interface, maintaining correct equals() and * hashCode() semantics */ protected class SortedSetView extends WrapperCollections.AbstractWrapperSortedSet { // ----- constructors ---------------------------------------------- /** * Create a SortedSetView over this ImmutableArrayList. */ protected SortedSetView() { super(ImmutableArrayList.this); } // ----- Object methods --------------------------------------------- /** * {@inheritDoc} */ public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Set)) { return false; } Set setOther = (Set) o; return setOther.size() == size() && setOther.containsAll(this); } /** * {@inheritDoc} */ public int hashCode() { int nHash = 0; for (Iterator iter = iterator(); iter.hasNext(); ) { nHash += Base.hashCode(iter.next()); } return nHash; } /** * {@inheritDoc} */ public String toString() { return ImmutableArrayList.this.toString(); } } // ----- data members --------------------------------------------------- /** * The Object array. */ private Object[] m_ao; /** * The index of the first array element to include in the list. */ private int m_of; /** * The number of the Object array elements to include in the list. */ private int m_c; /** * Lazy-instantiated hashed Map for implementing contains(), indexOf() and * lastIndexOf() for large lists and sets. */ private transient Map m_mapValueIndex; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy