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

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

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, 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 java.util.AbstractList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Set;

import java.lang.reflect.Array;
import java.util.Spliterator;


/**
* Implementation of the List interface in a read-only fashion based on a
* collection of arrays.
* 

* 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} methods should be used. * * @author gg, mf 2009.1.20 * @see ImmutableArrayList */ public class ImmutableMultiList extends AbstractList implements List, Set { // ----- constructors --------------------------------------------------- /** * Construct a List containing the elements of the specified array of * Object arrays. * * @param aao the array of arrays backing the MultiList */ public ImmutableMultiList(Object[][] aao) { m_cTotal = calculateTotalLength(aao); m_aao = aao; } /** * Construct a List containing the elements of the specified Collection of * Object arrays. * * @param collection the Collection of arrays to fill this MultiList from */ public ImmutableMultiList(Collection collection) { this((Object[][]) collection.toArray(new Object[collection.size()][])); } // ----- accessors ------------------------------------------------------ /** * Return a java.util.List view of this ImmutableMultiList. * * @return a List view of this ImmutableMultiList */ public List getList() { return new ListView(); } /** * Return a java.util.Set view of this ImmutableMultiList. *

* Note: this method does not ensure that the underlying ImmutableMultiList * 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 SortedSet. * * @return a Set view of this ImmutableMultiList */ public Set getSet() { return new SetView(); } // ----- 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_cTotal; } /** * 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) { Object[][] aao = m_aao; for (int iaa = 0, caa = aao.length; iaa < caa; ++iaa) { int c = aao[iaa].length; if (i < c) { return aao[iaa][i]; } i -= c; } throw new IndexOutOfBoundsException(); } /** * 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) { int i = 0; Object[][] aao = m_aao; for (int iaa = 0, caa = aao.length; iaa < caa; ++iaa) { Object[] ao = aao[iaa]; for (int ia = 0, ca = ao.length; ia < ca; ++ia, ++i) { if (Base.equals(ao[ia], 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) { int i = m_cTotal - 1; Object[][] aao = m_aao; for (int iaa = aao.length - 1; iaa >= 0; --iaa) { Object[] ao = aao[iaa]; for (int ia = ao.length - 1; ia >= 0; --ia, --i) { if (Base.equals(ao[ia], 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) { Set set = m_set; if (set == null) { if (m_cTotal < 32) { return indexOf(o) >= 0; } // We have a decent number of elements and it appears that we're // being accessed as a Set. The ImmutableMultiList data-structure // is sub-optimal for Set based operations, and thus for large // sets we inflate and delegate to a real Set implementation. m_set = set = new HashSet(this); } return set.contains(o); } /** * 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() { return toArray((Object[]) null); } /** * 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, a new * array is allocated with the runtime type of the specified array and the * size of this List. *

* If the elements of the MultiList fit in the specified array with room to * spare (i.e., the array has more elements than the MultuList), the element * in the array immediately following the end of the last element is set to * null. * * @param ao the array into which the elements of the MultiList 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 all the elements of the MultiList * * @throws ArrayStoreException if the runtime type of the specified array * is not ao supertype of the runtime type of every element in this * MultiList */ public Object[] toArray(Object ao[]) { return flatten(m_aao, m_cTotal, ao); } /** * {@inheritDoc} */ public ListIterator listIterator() { return new MultiIterator(0); } /** * {@inheritDoc} */ public ListIterator listIterator(int i) { return new MultiIterator(i); } /** * {@inheritDoc} */ public List subList(int iFrom, int iTo) { int cTotal = m_cTotal; if (iTo == -1) { iTo = cTotal - 1; } if (iFrom > iTo) { throw new IllegalArgumentException("iFrom > iTo"); } if (iFrom >= cTotal) { throw new IllegalArgumentException("iFrom >= cTotal"); } if (iTo > cTotal) { throw new IllegalArgumentException("iTo > cTotal"); } Object[][] aao = m_aao; // find the array for the "from" element int iaaFrom = 0; Object[] aFrom = aao[iaaFrom]; for (; iFrom >= aFrom.length; aFrom = aao[++iaaFrom]) { iFrom -= aFrom.length; } // find the array for the "to" element int iaaTo = iaaFrom; Object[] aTo = aFrom; for (; iTo > aTo.length; aTo = aao[++iaaTo]) { iTo -= aTo.length; } // construct multi-array sub-list; and trim the edge arrays int caaSub = iaaTo - iaaFrom + 1; Object[][] aaSub = new Object[caaSub][]; System.arraycopy(aao, iaaFrom, aaSub, 0, caaSub); if (iFrom != 0) { int c = aFrom.length - iFrom; System.arraycopy(aFrom, iFrom, aaSub[0] = new Object[c], 0, c); } if (iTo != aTo.length) { int c = iTo + 1; System.arraycopy(aFrom, iFrom, aaSub[caaSub - 1] = new Object[c], 0, c); } return new ImmutableMultiList(aaSub); } /** * 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 listIterator(); } // ----- Object methods ------------------------------------------------- /** * Compare this Collection / List / Set 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; } } // ----- inner class: MultiIterator ------------------------------------- /** * ListIterator implementation based on the ImmutableMultiList. */ protected class MultiIterator implements ListIterator { // ----- constructors ------------------------------------------- public MultiIterator(int i) { // advance array as needed if (i == -1) { i = ImmutableMultiList.this.m_cTotal; } while (i-- > 0) { next(); } } // ----- Iterator interface ----------------------------------------- public void remove() { throw new UnsupportedOperationException("collection is read-only"); } public void add(Object o) { throw new UnsupportedOperationException("collection is read-only"); } public void set(Object o) { throw new UnsupportedOperationException("collection is read-only"); } public boolean hasNext() { return m_i < ImmutableMultiList.this.m_cTotal; } public Object next() { if (m_i == m_cTotal) { throw new NoSuchElementException(); } ++m_i; Object[][] aao = ImmutableMultiList.this.m_aao; int ia = m_ia; Object[] ao = aao[m_iaa]; while (ia == ao.length) { // no more elements in this array; move on to the next // populated array ao = aao[++m_iaa]; ia = 0; } m_ia = ia + 1; // prepare for the next iteration return ao[ia]; } public int nextIndex() { return m_i; } public int previousIndex() { return m_i - 1; } public boolean hasPrevious() { return m_i > 0; } public Object previous() { if (m_i == 0) { throw new NoSuchElementException(); } --m_i; Object[][] aao = ImmutableMultiList.this.m_aao; int ia = m_ia; Object[] ao = aao[m_iaa]; while (ia == 0) { // no more elements in this array; move on to the previous // populated array ao = aao[--m_iaa]; ia = ao.length; } m_ia = --ia; // prepare for the next iteration return ao[ia]; } private int m_i; // index of next to be returned private int m_ia; // index into current array private int m_iaa; // index into array of arrays } // ----- helpers -------------------------------------------------------- /** * Calculate the total number of element in the array of arrays. * * @param aao an array of arrays * * @return the total number of elements */ public static int calculateTotalLength(Object[][] aao) { int cnt = 0; for (int i = 0, c = aao.length; i < c; ++i) { cnt += aao[i].length; } return cnt; } /** * Create a single dimensional array containing all elements of the specified * array of arrays. * * @param aaoFrom an array of arrays to copy from * @param cTotal the total length of the flattened array; pass -1 for it * to be calculated * @param aoTo an array to copy the elements into (optional) * * @return an array containing all the elements of the array of arrays * * @throws ArrayIndexOutOfBoundsException if the total length parameter * was not sufficient to hold the flattened array */ public static Object[] flatten(Object[][] aaoFrom, int cTotal, Object[] aoTo) { if (cTotal < 0) { cTotal = calculateTotalLength(aaoFrom); } if (aoTo == null) { // implied Object[] type aoTo = new Object[cTotal]; } else if (aoTo.length < cTotal) { // if it is not big enough, ao new array of the same runtime // type is allocated aoTo = (Object[]) Array.newInstance(aoTo.getClass().getComponentType(), cTotal); } else if (aoTo.length > cTotal) { // 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 aoTo[cTotal] = null; } for (int i = 0, of = 0, c = aaoFrom.length; i < c; ++i) { Object[] aoNext = aaoFrom[i]; int cNext = aoNext.length; System.arraycopy(aoNext, 0, aoTo, of, cNext); of += cNext; } return aoTo; } // ----- inner class: ListView ------------------------------------------- /** * ListView exposes the underlying ImmutableMultiList 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 ImmutableMultiList. */ protected ListView() { super(ImmutableMultiList.this); } // ----- Object methods --------------------------------------------- /** * Compares the specified object with this list for equality. Returns * true if and only if the specified object is also a list, both * lists have the same size, and all corresponding pairs of elements in * the two lists are equal. (Two elements e1 and * e2 are equal if (e1==null ? e2==null : * e1.equals(e2)).) In other words, two lists are defined to be * equal if they contain the same elements in the same order. This * definition ensures that the equals method works properly across * different implementations of the List interface. * * @param o the object to be compared for equality with this list. * * @return true if the specified object is equal to this list. */ 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()); } /** * Returns the hash code value for this list. The hash code of a list * is defined to be the result of the following calculation: *

        *  hashCode = 1;
        *  Iterator i = list.iterator();
        *  while (i.hasNext()) {
        *      Object obj = i.next();
        *      hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
        *  }
        * 
* This ensures that list1.equals(list2) implies that * list1.hashCode()==list2.hashCode() for any two lists, * list1 and list2, as required by the general * contract of Object.hashCode. * * @return the hash code value for this list. * @see Object#hashCode() * @see Object#equals(Object) * @see #equals(Object) */ public int hashCode() { int nHash = 1; for (Iterator iter = iterator(); iter.hasNext(); ) { nHash = 31 * nHash + Base.hashCode(iter.next()); } return nHash; } } // ----- inner class: SetView ------------------------------------------- /** * SetView exposes the underlying ImmutableMultiList through the {@link * java.util.Set} interface, maintaining correct equals() and * hashCode() semantics */ protected class SetView extends WrapperCollections.AbstractWrapperSet { // ----- constructor ------------------------------------------------ /** * Create a SetView over this ImmutableMultiList. */ protected SetView() { super(ImmutableMultiList.this); } // ----- Object methods --------------------------------------------- /** * Compares the specified object with this set for equality. Returns * true if the specified object is also a set, the two sets * have the same size, and every member of the specified set is * contained in this set (or equivalently, every member of this set is * contained in the specified set). This definition ensures that the * equals method works properly across different implementations of the * set interface. * * @param o Object to be compared for equality with this set. * @return true if the specified Object is equal to this set. */ 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); } /** * Returns the hash code value for this set. The hash code of a set is * defined to be the sum of the hash codes of the elements in the set, * where the hashcode of a null element is defined to be zero. * This ensures that s1.equals(s2) implies that * s1.hashCode()==s2.hashCode() for any two sets * s1 and s2, as required by the general * contract of the Object.hashCode method. * * @return the hash code value for this set. * @see Object#hashCode() * @see Object#equals(Object) * @see Set#equals(Object) */ public int hashCode() { int nHash = 0; for (Iterator iter = iterator(); iter.hasNext(); ) { nHash += Base.hashCode(iter.next()); } return nHash; } } // ----- data members --------------------------------------------------- /** * The array of Object arrays. */ private Object[][] m_aao; /** * A fully realized HashSet of this collections contents. This is inflated * and used for doing Set based operations if it is detected that this * collection is large and being accessed as a Set. */ private Set m_set; /** * The total number of items. */ private int m_cTotal; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy