/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.util;
/**
* @author Franck WOLFF
*/
public abstract class AbstractIndexedCache<T> {
protected static final int MAXIMUM_CAPACITY = 1 << 30;
protected static final int DEFAULT_INITIAL_CAPACITY = 1 << 6;
protected static final float DEFAULT_LOAD_FACTOR = 0.75f;
protected int initialCapacity;
protected Entry[] entries;
protected int threshold;
protected int size;
protected final void init(int capacity) {
this.initialCapacity = capacity;
this.entries = new Entry[capacity];
this.threshold = (int)Math.min(capacity * DEFAULT_LOAD_FACTOR, MAXIMUM_CAPACITY + 1);
this.size = 0;
}
public abstract int putIfAbsent(T key);
public final int size() {
return size;
}
public final void clear() {
init(initialCapacity);
}
protected final int resize(int newCapacity) {
Entry[] oldEntries = entries;
if (oldEntries.length == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return (MAXIMUM_CAPACITY - 1);
}
final int indexMask = newCapacity - 1;
Entry[] newEntries = new Entry[newCapacity];
for (Entry entry : oldEntries) {
while (entry != null) {
int i = entry.hash & indexMask;
Entry next = entry.next;
entry.next = newEntries[i];
newEntries[i] = entry;
entry = next;
}
}
entries = newEntries;
threshold = (int)Math.min(newCapacity * DEFAULT_LOAD_FACTOR, MAXIMUM_CAPACITY + 1);
return indexMask;
}
protected static int roundUpToPowerOf2(int number) {
if (number >= MAXIMUM_CAPACITY)
return MAXIMUM_CAPACITY;
int rounded = Integer.highestOneBit(number);
if (rounded == 0)
return 1;
if (Integer.bitCount(number) > 1)
return rounded << 1;
return rounded;
}
protected final static class Entry {
public final Object key;
public final int hash;
public final int index;
public Entry next;
public Entry(Object key, int hash, int index, Entry next) {
this.key = key;
this.hash = hash;
this.index = index;
this.next = next;
}
}
}