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

com.jidesoft.utils.CachedArrayList Maven / Gradle / Ivy

/*
 * @(#)CachedArrayList.java 10/5/2005
 *
 * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
 */
package com.jidesoft.utils;

import java.util.*;

/**
 * This is a fast access ArrayList that sacrifices memory for speed. It will reduce the speed of indexOf method from
 * O(n) to O(1). However it will at least double the memory used by ArrayList. So use it appropriately. 

Just * like ArrayList, this implementation is not synchronized. If you want a thread safe implementation, you can * use {@link com.jidesoft.utils.CachedVector}. */ public class CachedArrayList extends ArrayList { private static final long serialVersionUID = 3835017332487313880L; private Map _indexCache; private boolean _lazyCaching = false; private boolean _isDirty = false; public CachedArrayList() { } public CachedArrayList(Collection c) { super(c); if (!isLazyCaching()) { cacheAll(); } } public CachedArrayList(int initialCapacity) { super(initialCapacity); } @Override public int indexOf(Object elem) { if (_indexCache == null || _isDirty) { cacheAll(); } Integer o = _indexCache.get(elem); if (o != null) { return o; } else if (isLazyCaching()) { int i = super.indexOf(elem); if (i == -1) { uncacheIt(elem); } else { cacheIt(elem, i); } return i; } else { return -1; } } /** * Adjusts the cache so that all values that are greater than index will increase by the value specified by the * increase parameter. * * @param index the index. All values above this index will be changed. * @param increase a positive number to increase or a negative number to decrease. * @deprecated no longer being invoked since 3.4.0 */ @Deprecated protected synchronized void adjustCache(int index, int increase) { if (_indexCache != null) { Map newCache = createCache(); Set keys = _indexCache.keySet(); for (Object key : keys) { int value = _indexCache.get(key); if (value >= index) { newCache.put(key, value + increase); } else { newCache.put(key, value); } } _indexCache = newCache; } } protected Map createCache() { return new IdentityHashMap(); } /** * Caches the index of the element. * * @param o the element * @param index the index. */ public void cacheIt(Object o, int index) { if (_indexCache != null ) { Integer old = _indexCache.put(o, index); if (old != null && old < index) { _indexCache.put(o, old); } markDirtyIfNecessary(index); if (!_isDirty && !isLazyCaching()) { for (int i = size() - 1; i > index; i--) { Integer oldI = _indexCache.put(get(i), i); if (oldI != null && oldI < index) { _indexCache.put(get(i), oldI); } } } } } /** * Marks the entire cache dirty if necessary depends on where the index is. *

* By default, the cache is marked dirty when the index is smaller than half of the size. * * @param index the index that is changing. * @since 3.4.0 */ protected void markDirtyIfNecessary(int index) { if (index < size() / 2) { _isDirty = true; } } /** * Uncaches the index of the element. * * @param o the element */ public void uncacheIt(Object o) { if (_indexCache != null) { _indexCache.remove(o); } } @Override public boolean add(E o) { // In any cases, can't invoke add(int, E). Otherwise, StackOverflowError might be thrown. boolean added = super.add(o); if (!isLazyCaching() && _indexCache != null && added) { cacheIt(o, size() - 1); } return added; } @Override public void add(int index, E element) { // improve performance for most scenarios in HeaderTableModel if (index == size()) { add(element); // need make sure add(E) won't invoke this method. Otherwise, it will cause endless loop. return; } super.add(index, element); if (!isLazyCaching()) { cacheIt(element, index); } else if (_indexCache != null) { cacheIt(element, index); } } private void initializeCache() { if (_indexCache == null) { _indexCache = createCache(); } } @Override public E remove(int index) { E element = super.remove(index); if (element != null) { uncacheAll(); } return element; } @Override public boolean remove(Object o) { boolean removed = super.remove(o); if (removed) { uncacheAll(); } return removed; } @Override public boolean removeAll(Collection c) { uncacheAll(); return super.removeAll(c); } @Override public void clear() { uncacheAll(); super.clear(); } @Override public boolean addAll(Collection c) { // In any cases, can't invoke addAll(int, Collection). Otherwise, StackOverflowError might be thrown. int index = size(); boolean added = super.addAll(c); if (added && _indexCache != null) { for (E e : c) { cacheIt(e, index++); } } return added; } @Override public boolean addAll(int index, Collection c) { // improve performance for most scenarios in HeaderTableModel if (index == size()) { return this.addAll(c); // need make sure addAll(Collection) won't invoke this method. Otherwise, it will cause endless loop. } boolean added = super.addAll(index, c); if (added) { uncacheAll(); } return added; } @Override public E set(int index, E element) { if (!isLazyCaching()) { uncacheAll(); return super.set(index, element); } else { return super.set(index, element); } } /** * Invalidated the whole cache. */ public void invalidateCache() { uncacheAll(); } /** * Uncache the whole cache. It is the same as {@link #invalidateCache()}. */ public void uncacheAll() { if (_indexCache != null) { _indexCache.clear(); _indexCache = null; } } /** * Cache all the element index. */ public void cacheAll() { _indexCache = createCache(); // Integer i = 0; // for (Object elem : this) { // if (_indexCache.get(elem) == null) { // _indexCache.put(elem, i); // } // i++; // } // for (int i = 0; i < size(); i++) { // _indexCache.put(get(i), i); // } for (int i = size() - 1; i >= 0; i--) { _indexCache.put(get(i), i); } _isDirty = false; } public boolean isLazyCaching() { return _lazyCaching; } public void setLazyCaching(boolean lazyCaching) { _lazyCaching = lazyCaching; } @Override protected void removeRange(int fromIndex, int toIndex) { if (fromIndex == toIndex) { remove(fromIndex); } else { super.removeRange(fromIndex, toIndex); uncacheAll(); } } }