/** * Copyright (c) 2002-2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM - Initial API and implementation */ package org.eclipse.emf.common.util; import java.io.Serializable; import java.util.AbstractCollection; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * A highly extensible map implementation. */ public class BasicEMap<K, V> implements EMap<K, V>, Serializable { private static final long serialVersionUID = 2L; /** * An extended implementation interface for caching hash values * and for updating an entry that may be manufactured as a uninitialized instance by a factory. * No client is expected to use this interface, * other than to implement it in conjunction with a map implementation. */ public interface Entry<K, V> extends Map.Entry<K, V> { /** * Sets the key. * This should only be called by the map implementation, * since the key of an entry already in the map must be immutable. * @param key the key. */ void setKey(K key); /** * Returns the hash code of the key. * Only the map implementation would really care. */ int getHash(); /** * Sets the hash code of the key. * This should only be called by the map implementation, * since the hash code of the key of an entry already in the map must be immutable. * @param hash the hash. */ void setHash(int hash); } /** * The underlying list of entries. */ protected transient EList<Entry<K, V>> delegateEList; /** * The size of the map. */ protected transient int size; /** * The array of entry lists into which the hash codes are indexed. */ protected transient BasicEList<Entry<K, V>> [] entryData; /** * The modification indicator used to ensure iterator integrity. */ protected transient int modCount; /** * An implementation class to hold the views. */ protected static class View<K, V> { /** * The map view. */ public transient Map<K, V> map; /** * The map key set view. */ public transient Set<K> keySet; /** * The entry set view. */ public transient Set<Map.Entry<K, V>> entrySet; /** * The values collection view. */ public transient Collection<V> values; /** * Creates an empty instance. */ public View() { super(); } } /** * The various alternative views of the map. */ protected transient View<K, V> view; /** * Creates an empty instance. */ public BasicEMap() { initializeDelegateEList(); } /** * Initializes the {@link #delegateEList}. * This implementation illustrates the precise pattern that is used to * delegate a list implementation's callback methods to the map implementation. */ protected void initializeDelegateEList() { delegateEList = new BasicEList<Entry<K, V>>() { private static final long serialVersionUID = 1L; @Override protected void didAdd(int index, Entry<K, V> newObject) { doPut(newObject); } @Override protected void didSet(int index, Entry<K, V> newObject, Entry<K, V> oldObject) { didRemove(index, oldObject); didAdd(index, newObject); } @Override protected void didRemove(int index, Entry<K, V> oldObject) { doRemove(oldObject); } @Override protected void didClear(int size, Object [] oldObjects) { doClear(); } @Override protected void didMove(int index, Entry<K, V> movedObject, int oldIndex) { doMove(movedObject); } }; } /** * Creates an empty instance with the given capacity. * @param initialCapacity the initial capacity of the map before it must grow. * @exception IllegalArgumentException if the <code>initialCapacity</code> is negative. */ public BasicEMap(int initialCapacity) { this(); if (initialCapacity < 0) { throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity); } entryData = newEntryData(initialCapacity); } /** * Creates an instance that is a copy of the map. * @param map the initial contents of the map. */ public BasicEMap(Map<? extends K, ? extends V> map) { this(); int mapSize = map.size(); if (mapSize > 0) { entryData = newEntryData(2 * mapSize); putAll(map); } } /** * Returns new allocated entry data storage. * Clients may override this to create typed storage, but it's not likely. * The cost of type checking via a typed array is negligible. * @param capacity the capacity of storage needed. * @return new entry data storage. */ @SuppressWarnings("unchecked") protected BasicEList<Entry<K, V>> [] newEntryData(int capacity) { return new BasicEList[capacity]; } /** * Ensures that the entry data is created * and is populated with contents of the delegate list. */ protected void ensureEntryDataExists() { if (entryData == null) { entryData = newEntryData(2 * size + 1); // This should be transparent. // int oldModCount = modCount; size = 0; for (Entry<K, V> entry : delegateEList) { doPut(entry); } modCount = oldModCount; } } /** * Returns a new allocated list of entries. * Clients may override this to create typed storage. * The cost of type checking via a typed array is negligible. * The type must be kept in synch with {@link #newEntry(int, Object, Object) newEntry}. * @return a new list of entries. * @see #newEntry(int, Object, Object) */ protected BasicEList<Entry<K, V>> newList() { return new BasicEList<Entry<K, V>>() { private static final long serialVersionUID = 1L; @Override public Object [] newData(int listCapacity) { return new BasicEMap.EntryImpl[listCapacity]; } }; } /** * Returns a new entry. * The key is {@link #validateKey validated} and the value is {@link #validateValue validated}. * Clients may override this to create typed storage. * The type must be kept in synch with {@link #newList newEntry}. * @param hash the cached hash code of the key. * @param key the key. * @param value the value. * @return a new entry. * @see #newList */ protected Entry<K, V> newEntry(int hash, K key, V value) { validateKey(key); validateValue(value); return new EntryImpl(hash, key, value); } /** * Sets the value of the entry, and returns the former value. * The value is {@link #validateValue validated}. * @param entry the entry. * @param value the value. * @return the former value, or <code>null</code>. */ protected V putEntry(Entry<K, V> entry, V value) { return entry.setValue(value); } /** * Returns whether <code>equals</code> rather than <code>==</code> should be used to compare keys. * The default is to return <code>true</code> but clients can optimize performance by returning <code>false</code>. * The performance difference is highly significant. * @return whether <code>equals</code> rather than <code>==</code> should be used to compare keys. */ protected boolean useEqualsForKey() { return true; } /** * Returns whether <code>equals</code> rather than <code>==</code> should be used to compare values. * The default is to return <code>true</code> but clients can optimize performance by returning <code>false</code>. * The performance difference is highly significant. * @return whether <code>equals</code> rather than <code>==</code> should be used to compare values. */ protected boolean useEqualsForValue() { return true; } /** * Resolves the value associated with the key and returns the result. * This implementation simply returns the <code>value</code>; * clients can use this to transform objects as they are fetched. * @param key the key of an entry. * @param value the value of an entry. * @return the resolved value. */ protected V resolve(K key, V value) { return value; } /** * Validates a new key. * This implementation does nothing, * but clients may throw runtime exceptions * in order to handle constraint violations. * @param key the new key. * @exception IllegalArgumentException if a constraint prevents the object from being added. */ protected void validateKey(K key) { // Do nothing. } /** * Validates a new key. * This implementation does nothing, * but clients may throw runtime exceptions * in order to handle constraint violations. * @param value the new value. * @exception IllegalArgumentException if a constraint prevents the object from being added. */ protected void validateValue(V value) { // Do nothing. } /** * Called to indicate that the entry has been added. * This implementation does nothing; * clients can use this to monitor additions to the map. * @param entry the added entry. */ protected void didAdd(Entry<K, V> entry) { // Do nothing. } /** * Called to indicate that the entry has an updated value. * This implementation does nothing; * clients can use this to monitor value changes in the map. * @param entry the new entry. */ protected void didModify(Entry<K, V> entry, V oldValue) { // Do nothing. } /** * Called to indicate that the entry has been removed. * This implementation does nothing; * clients can use this to monitor removals from the map. * @param entry the removed entry. */ protected void didRemove(Entry<K, V> entry) { // Do nothing. } /** * Called to indicate that the map has been cleared. * This implementation does calls {@link #didRemove didRemove} for each entry; * clients can use this to monitor clearing of the map. * @param oldEntryData the removed entries. */ protected void didClear(BasicEList<Entry<K, V>> [] oldEntryData) { if (oldEntryData != null) { for (int i = 0; i < oldEntryData.length; ++i) { BasicEList<Entry<K, V>> eList = oldEntryData[i]; if (eList != null) { @SuppressWarnings("unchecked") Entry<K, V> [] entries = (Entry<K, V> [])eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { Entry<K, V> entry = entries[j]; didRemove(entry); } } } } } /** * Returns the number of entries in the map. * @return the number of entries in the map. */ public int size() { return size; } /** * Returns whether the map has zero size. * @return whether the map has zero size. */ public boolean isEmpty() { return size == 0; } /* * Javadoc copied from interface. */ public int indexOfKey(Object key) { if (useEqualsForKey() && key != null) { for (int i = 0, size = delegateEList.size(); i < size; ++i) { Entry<K, V> entry = delegateEList.get(i); if (key.equals(entry.getKey())) { return i; } } } else { for (int i = 0, size = delegateEList.size(); i < size; ++i) { Entry<K, V> entry = delegateEList.get(i); if (key == entry.getKey()) { return i; } } } return -1; } /* * Javadoc copied from interface. */ public boolean containsKey(Object key) { if (size > 0) { ensureEntryDataExists(); int hash = hashOf(key); int index = indexOf(hash); int entryIndex = entryIndexForKey(index, hash, key); return entryIndex != -1; } else { return false; } } /* * Javadoc copied from interface. */ public boolean containsValue(Object value) { if (size > 0) { ensureEntryDataExists(); if (useEqualsForValue() && value != null) { for (int i = 0; i < entryData.length; ++i) { BasicEList<Entry<K, V>> eList = entryData[i]; if (eList != null) { @SuppressWarnings("unchecked") Entry<K, V> [] entries = (Entry<K, V> [])eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { Entry<K, V> entry = entries[j]; if (value.equals(entry.getValue())) { return true; } } } } } else { for (int i = 0; i < entryData.length; ++i) { BasicEList<Entry<K, V>> eList = entryData[i]; if (eList != null) { @SuppressWarnings("unchecked") Entry<K, V> [] entries = (Entry<K, V> [])eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { Entry<K, V> entry = entries[j]; if (value == entry.getValue()) { return true; } } } } } } return false; } /* * Javadoc copied from interface. */ public V get(Object key) { if (size > 0) { ensureEntryDataExists(); int hash = hashOf(key); int index = indexOf(hash); Entry<K, V> entry = entryForKey(index, hash, key); if (entry != null) { @SuppressWarnings("unchecked") K object = (K)key; return resolve(object, entry.getValue()); } } return null; } /* * Javadoc copied from interface. */ public V put(K key, V value) { ensureEntryDataExists(); int hash = hashOf(key); if (size > 0) { int index = indexOf(hash); Entry<K, V> entry = entryForKey(index, hash, key); if (entry != null) { V result = putEntry(entry, value); didModify(entry, result); return result; } } Entry<K, V> entry = newEntry(hash, key, value); delegateEList.add(entry); return null; } /** * Adds the new entry to the map. * @param entry the new entry. */ protected void doPut(Entry<K, V> entry) { if (entryData == null) { ++modCount; ++size; } else { int hash = entry.getHash(); grow(size + 1); int index = indexOf(hash); BasicEList<Entry<K, V>> eList = entryData[index]; if (eList == null) { eList = entryData[index] = newList(); } eList.add(entry); ++size; didAdd(entry); } } /* * Javadoc copied from source. */ public V removeKey(Object key) { ensureEntryDataExists(); int hash = hashOf(key); int index = indexOf(hash); Entry<K, V> entry = entryForKey(index, hash, key); if (entry != null) { remove(entry); return entry.getValue(); } else { return null; } } /** * Removes the entry from the map. * @param entry an entry in the map. */ protected void doRemove(Entry<K, V> entry) { if (entryData == null) { ++modCount; --size; } else { Object key = entry.getKey(); int hash = entry.getHash(); int index = indexOf(hash); removeEntry(index, entryIndexForKey(index, hash, key)); didRemove(entry); } } /** * Removes the fully indexed entry from the map and returns it's value. * @param index the index in the entry data * @param entryIndex the index in the list of entries. * @return the value of the entry. */ protected V removeEntry(int index, int entryIndex) { ++modCount; --size; Entry<K, V> entry = entryData[index].remove(entryIndex); return entry.getValue(); } /* * Javadoc copied from interface. */ public void putAll(Map<? extends K, ? extends V> map) { for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } /* * Javadoc copied from interface. */ public void putAll(EMap<? extends K, ? extends V> map) { for (Map.Entry<? extends K, ? extends V> entry : map) { put(entry.getKey(), entry.getValue()); } } /** * Clears the map. */ protected void doClear() { if (entryData == null) { ++modCount; size = 0; didClear(null); } else { ++modCount; BasicEList<Entry<K, V>> [] oldEntryData = entryData; entryData = null; size = 0; didClear(oldEntryData); } } /** * Increments the modification count. */ protected void doMove(Entry<K, V> entry) { ++modCount; } protected class DelegatingMap implements EMap.InternalMapView<K, V> { public DelegatingMap() { super(); } public EMap<K, V> eMap() { return BasicEMap.this; } public int size() { return BasicEMap.this.size(); } public boolean isEmpty() { return BasicEMap.this.isEmpty(); } public boolean containsKey(Object key) { return BasicEMap.this.containsKey(key); } public boolean containsValue(Object value) { return BasicEMap.this.containsValue(value); } public V get(Object key) { return BasicEMap.this.get(key); } public V put(K key, V value) { return BasicEMap.this.put(key, value); } public V remove(Object key) { return BasicEMap.this.removeKey(key); } public void putAll(Map<? extends K, ? extends V> map) { BasicEMap.this.putAll(map); } public void clear() { BasicEMap.this.clear(); } public Set<K> keySet() { return BasicEMap.this.keySet(); } public Collection<V> values() { return BasicEMap.this.values(); } public Set<Entry<K, V>> entrySet() { return BasicEMap.this.entrySet(); } @Override public boolean equals(Object object) { return BasicEMap.this.equals(object); } @Override public int hashCode() { return BasicEMap.this.hashCode(); } } /* * Javadoc copied from interface. */ public Map<K, V> map() { if (view == null) { view = new View<K, V>(); } if (view.map == null) { view.map = new DelegatingMap(); } return view.map; } /* * Javadoc copied from interface. */ public Set<K> keySet() { if (view == null) { view = new View<K, V>(); } if (view.keySet == null) { view.keySet = new AbstractSet<K>() { @Override public Iterator<K> iterator() { return BasicEMap.this.size == 0 ? ECollections.<K>emptyEList().iterator() : new BasicEMapKeyIterator(); } @Override public int size() { return BasicEMap.this.size; } @Override public boolean contains(Object key) { return BasicEMap.this.containsKey(key); } @Override public boolean remove(Object key) { int oldSize = BasicEMap.this.size; BasicEMap.this.removeKey(key); return BasicEMap.this.size != oldSize; } @Override public void clear() { BasicEMap.this.clear(); } }; } return view.keySet; } /* * Javadoc copied from interface. */ public Collection<V> values() { if (view == null) { view = new View<K, V>(); } if (view.values == null) { view.values = new AbstractCollection<V>() { @Override public Iterator<V> iterator() { return BasicEMap.this.size == 0 ? ECollections.<V>emptyEList().iterator() : new BasicEMapValueIterator(); } @Override public int size() { return size; } @Override public boolean contains(Object value) { return containsValue(value); } @Override public void clear() { BasicEMap.this.clear(); } }; } return view.values; } /* * Javadoc copied from interface. */ public Set<Map.Entry<K, V>> entrySet() { if (view == null) { view = new View<K, V>(); } if (view.entrySet == null) { view.entrySet = new AbstractSet<Map.Entry<K, V>>() { @Override public int size() { return BasicEMap.this.size; } @Override public boolean contains(Object object) { if (BasicEMap.this.size > 0 && object instanceof Map.Entry<?, ?>) { BasicEMap.this.ensureEntryDataExists(); @SuppressWarnings("unchecked") Map.Entry<K, V> otherEntry = (Map.Entry<K, V>)object; Object key = otherEntry.getKey(); int hash = key == null ? 0 : key.hashCode(); int index = BasicEMap.this.indexOf(hash); BasicEList<Entry<K, V>> eList = entryData[index]; if (eList != null) { @SuppressWarnings("unchecked") Entry<K, V> [] entries = (Entry<K, V> [])eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { Entry<K, V> entry = entries[j]; if (entry.getHash() == hash && entry.equals(otherEntry)) { return true; } } } } return false; } @Override public boolean remove(Object object) { if (BasicEMap.this.size > 0 && object instanceof Map.Entry<?, ?>) { BasicEMap.this.ensureEntryDataExists(); @SuppressWarnings("unchecked") Map.Entry<K, V> otherEntry = (Map.Entry<K, V>)object; Object key = otherEntry.getKey(); int hash = key == null ? 0 : key.hashCode(); int index = BasicEMap.this.indexOf(hash); BasicEList<Entry<K, V>> eList = entryData[index]; if (eList != null) { @SuppressWarnings("unchecked") Entry<K, V> [] entries = (Entry<K, V> [])eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { Entry<K, V> entry = entries[j]; if (entry.getHash() == hash && entry.equals(otherEntry)) { // BasicEMap.this.removeEntry(index, j); remove(otherEntry); return true; } } } } return false; } @Override public void clear() { BasicEMap.this.clear(); } @Override public Iterator<Map.Entry<K, V>> iterator() { return BasicEMap.this.size == 0 ? ECollections.<Map.Entry<K, V>>emptyEList().iterator() : new BasicEMapIterator<Map.Entry<K, V>>(); } }; } return view.entrySet; } /** * A simple and obvious entry implementation. */ protected class EntryImpl implements Entry<K, V> { /** * The cached hash code of the key. */ protected int hash; /** * The key. */ protected K key; /** * The value. */ protected V value; /** * Creates a fully initialized instance. * @param hash the hash code of the key. * @param key the key. * @param value the value. */ public EntryImpl(int hash, K key, V value) { this.hash = hash; this.key = key; this.value = value; } public int getHash() { return hash; } public void setHash(int hash) { this.hash = hash; } public K getKey() { return key; } public void setKey(K key) { throw new RuntimeException(); } public V getValue() { return value; } public V setValue(V value) { BasicEMap.this.validateValue(value); V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object object) { if (object instanceof Map.Entry<?, ?>) { @SuppressWarnings("unchecked") Map.Entry<K, V> entry = (Map.Entry<K, V>)object; return (BasicEMap.this.useEqualsForKey() && key != null ? key.equals(entry.getKey()) : key == entry.getKey()) && (BasicEMap.this.useEqualsForValue() && value != null ? value.equals(entry.getValue()) : value == entry.getValue()); } else { return false; } } @Override public int hashCode() { return hash ^ (value == null ? 0 : value.hashCode()); } @Override public String toString() { return key + "->" + value; } } /** * An iterator over the map entry data. */ protected class BasicEMapIterator<U> implements Iterator<U> { /** * The cursor in the entry data. */ protected int cursor; /** * The cursor in the list of entries. */ protected int entryCursor = -1; /** * The last cursor in the entry data. */ protected int lastCursor; /** * The cursor in the list of entries. */ protected int lastEntryCursor; /** * The modification count expected of the map. */ protected int expectedModCount = modCount; /** * Creates an instance. */ BasicEMapIterator() { if (BasicEMap.this.size > 0) { scan(); } } /** * Called to yield the iterator result for the entry. * This implementation returns the entry itself. * @param entry the entry. * @return the iterator result for the entry. */ @SuppressWarnings("unchecked") protected U yield(Entry<K, V> entry) { return (U)entry; } /** * Scans to the new entry. */ protected void scan() { BasicEMap.this.ensureEntryDataExists(); if (entryCursor != -1) { ++entryCursor; BasicEList<Entry<K, V>> eList = BasicEMap.this.entryData[cursor]; if (entryCursor < eList.size) { return; } ++cursor; } for (; cursor < BasicEMap.this.entryData.length; ++cursor) { BasicEList<Entry<K, V>> eList = BasicEMap.this.entryData[cursor]; if (eList != null && !eList.isEmpty()) { entryCursor = 0; return; } } entryCursor = -1; } /** * Returns whether there are more objects. * @return whether there are more objects. */ public boolean hasNext() { return entryCursor != -1; } /** * Returns the next object and advances the iterator. * @return the next object. * @exception NoSuchElementException if the iterator is done. */ public U next() { if (BasicEMap.this.modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (entryCursor == -1) { throw new NoSuchElementException(); } lastCursor = cursor; lastEntryCursor = entryCursor; scan(); @SuppressWarnings("unchecked") Entry<K, V> result = (Entry<K, V>)BasicEMap.this.entryData[lastCursor].data[lastEntryCursor]; return yield(result); } /** * Removes the entry of the last object returned by {@link #next()} from the map, * it's an optional operation. * @exception IllegalStateException * if <code>next</code> has not yet been called, * or <code>remove</code> has already been called after the last call to <code>next</code>. */ public void remove() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (lastEntryCursor == -1) { throw new IllegalStateException(); } delegateEList.remove(entryData[lastCursor].get(lastEntryCursor)); expectedModCount = BasicEMap.this.modCount; lastEntryCursor = -1; if (cursor == lastCursor && entryCursor != -1) { --entryCursor; } } } /** * An iterator over the map key data. */ protected class BasicEMapKeyIterator extends BasicEMapIterator<K> { /** * Creates an instance. */ BasicEMapKeyIterator() { super(); } /** * Called to yield the iterator result for the entry. * This implementation returns the key of the entry. * @param entry the entry. * @return the key of the entry. */ @Override protected K yield(Entry<K, V> entry) { return entry.getKey(); } } /** * An iterator over the map value data. */ protected class BasicEMapValueIterator extends BasicEMapIterator<V> { /** * Creates an instance. */ BasicEMapValueIterator() { super(); } /** * Called to yield the iterator result for the entry. * This implementation returns the value of the entry. * @param entry the entry. * @return the value of the entry. */ @Override protected V yield(Entry<K, V> entry) { return entry.getValue(); } } /** * Called to return the hash code of the key. * @param key the key. * @return the hash code of the object. */ protected int hashOf(Object key) { return key == null ? 0 : key.hashCode(); } /** * Called to return the entry data index corresponding to the hash code. * @param hash the hash code. * @return the index corresponding to the hash code. */ protected int indexOf(int hash) { return (hash & 0x7FFFFFFF) % entryData.length; } /** * Called to return the entry given the index, the hash, and the key. * @param index the entry data index of the key. * @param hash the hash code of the key. * @param key the key. * @return the entry. */ protected Entry<K, V> entryForKey(int index, int hash, Object key) { BasicEList<Entry<K, V>> eList = entryData[index]; if (eList != null) { Object [] entries = eList.data; int size = eList.size; if (useEqualsForKey() && key != null) { for (int j = 0; j < size; ++j) { @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)entries[j]; if (entry.getHash() == hash && key.equals(entry.getKey())) { return entry; } } } else { for (int j = 0; j < size; ++j) { @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)entries[j]; if (entry.getKey() == key) { return entry; } } } } return null; } /** * Called to return the entry list index given the index, the hash, and the key. * @param index the entry data index of the key. * @param hash the hash code of the key. * @param key the key. * @return the entry list index. */ protected int entryIndexForKey(int index, int hash, Object key) { if (useEqualsForKey() && key != null) { BasicEList<Entry<K, V>> eList = entryData[index]; if (eList != null) { Object [] entries = eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)entries[j]; if (entry.getHash() == hash && key.equals(entry.getKey())) { return j; } } } } else { BasicEList<Entry<K, V>> eList = entryData[index]; if (eList != null) { Object [] entries = eList.data; int size = eList.size; for (int j = 0; j < size; ++j) { @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)entries[j]; if (entry.getKey() == key) { return j; } } } } return -1; } /** * Grows the capacity of the map * to ensure that no additional growth is needed until the size exceeds the specified minimum capacity. */ protected boolean grow(int minimumCapacity) { ++modCount; int oldCapacity = entryData == null ? 0 : entryData.length; if (minimumCapacity > oldCapacity) { BasicEList<Entry<K, V>> [] oldEntryData = entryData; entryData = newEntryData(2 * oldCapacity + 4); for (int i = 0; i < oldCapacity; ++i) { BasicEList<Entry<K, V>> oldEList = oldEntryData[i]; if (oldEList != null) { Object [] entries = oldEList.data; int size = oldEList.size; for (int j = 0; j < size; ++j) { @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)entries[j]; int index = indexOf(entry.getHash()); BasicEList<Entry<K, V>> eList = entryData[index]; if (eList == null) { eList = entryData[index] = newList(); } eList.add(entry); } } } return true; } else { return false; } } /** * Delegates to {@link #delegateEList}. */ public boolean contains(Object object) { return delegateEList.contains(object); } /** * Delegates to {@link #delegateEList}. */ public boolean containsAll(Collection<?> collection) { return delegateEList.containsAll(collection); } /** * Delegates to {@link #delegateEList}. */ public int indexOf(Object object) { return delegateEList.indexOf(object); } /** * Delegates to {@link #delegateEList}. */ public int lastIndexOf(Object object) { return delegateEList.lastIndexOf(object); } /** * Delegates to {@link #delegateEList}. */ public Object[] toArray() { return delegateEList.toArray(); } /** * Delegates to {@link #delegateEList}. */ public <T> T[] toArray(T [] array) { return delegateEList.toArray(array); } /** * Delegates to {@link #delegateEList}. */ public Entry<K, V> get(int index) { return delegateEList.get(index); } /** * Delegates to {@link #delegateEList}. */ public Map.Entry<K, V> set(int index, Map.Entry<K, V> object) { return delegateEList.set(index, (Entry<K, V>)object); } /** * Delegates to {@link #delegateEList}. */ public boolean add(Map.Entry<K, V> object) { return delegateEList.add((Entry<K, V>)object); } /** * Delegates to {@link #delegateEList}. */ public void add(int index, Map.Entry<K, V> object) { delegateEList.add(index, (Entry<K, V>)object); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public boolean addAll(Collection<? extends Map.Entry<K, V>> collection) { return delegateEList.addAll((Collection<? extends Entry<K, V>>)collection); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public boolean addAll(int index, Collection<? extends Map.Entry<K, V>> collection) { return delegateEList.addAll(index, (Collection<? extends Entry<K, V>>)collection); } /** * Delegates to {@link #delegateEList}. */ public boolean remove(Object object) { if (object instanceof Map.Entry<?, ?>) { return delegateEList.remove(object); } else { boolean result = containsKey(object); removeKey(object); return result; } } /** * Delegates to {@link #delegateEList}. */ public boolean removeAll(Collection<?> collection) { return delegateEList.removeAll(collection); } /** * Delegates to {@link #delegateEList}. */ public Map.Entry<K, V> remove(int index) { return delegateEList.remove(index); } /** * Delegates to {@link #delegateEList}. */ public boolean retainAll(Collection<?> collection) { return delegateEList.retainAll(collection); } /** * Delegates to {@link #delegateEList}. */ public void clear() { delegateEList.clear(); } /** * Delegates to {@link #delegateEList}. */ public void move(int index, Map.Entry<K, V> object) { delegateEList.move(index, (Entry<K, V>)object); } /** * Delegates to {@link #delegateEList}. */ public Map.Entry<K, V> move(int targetIndex, int sourceIndex) { return delegateEList.move(targetIndex, sourceIndex); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public Iterator<Map.Entry<K, V>> iterator() { return (Iterator<Map.Entry<K, V>>)(Iterator<?>)delegateEList.iterator(); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public ListIterator<Map.Entry<K, V>> listIterator() { return (ListIterator<Map.Entry<K, V>>)(ListIterator<?>)(delegateEList.listIterator()); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public ListIterator<Map.Entry<K, V>> listIterator(int index) { return (ListIterator<Map.Entry<K, V>>)(ListIterator<?>)delegateEList.listIterator(index); } /** * Delegates to {@link #delegateEList}. */ @SuppressWarnings("unchecked") public List<Map.Entry<K, V>> subList(int start, int end) { return (List<Map.Entry<K, V>>)(List<?>)delegateEList.subList(start, end); } @Override public int hashCode() { return delegateEList.hashCode(); } @Override public boolean equals(Object object) { if (object instanceof EMap<?, ?>) { return delegateEList.equals(object); } else { return false; } } /** * Delegates to {@link #delegateEList}. */ @Override public String toString() { return delegateEList.toString(); } }