/*******************************************************************************
* Copyright (c) 2011-2013 CWI
* 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:
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.parser.gtd.util;
import java.util.Iterator;
@SuppressWarnings({"unchecked", "cast"})
public class IntegerKeyedDoubleValueHashMap<V1, V2> {
private final static int DEFAULT_BIT_SIZE = 2;
private Entry<V1, V2>[] entries;
private int hashMask;
private int bitSize;
private int threshold;
private int load;
public IntegerKeyedDoubleValueHashMap(){
super();
int nrOfEntries = 1 << (bitSize = DEFAULT_BIT_SIZE);
hashMask = nrOfEntries - 1;
entries = (Entry<V1, V2>[]) new Entry[nrOfEntries];
threshold = nrOfEntries;
load = 0;
}
private void rehash(){
int nrOfEntries = 1 << (++bitSize);
int newHashMask = nrOfEntries - 1;
Entry<V1, V2>[] oldEntries = entries;
Entry<V1, V2>[] newEntries = (Entry<V1, V2>[]) new Entry[nrOfEntries];
Entry<V1, V2> currentEntryRoot = new Entry<V1, V2>(-1, null, null, null);
Entry<V1, V2> shiftedEntryRoot = new Entry<V1, V2>(-1, null, null, null);
int oldSize = oldEntries.length;
for(int i = oldSize - 1; i >= 0; --i){
Entry<V1, V2> e = oldEntries[i];
if(e != null){
Entry<V1, V2> lastCurrentEntry = currentEntryRoot;
Entry<V1, V2> lastShiftedEntry = shiftedEntryRoot;
int lastPosition = -1;
do{
int position = e.key & newHashMask;
if(position == i){
if(position != lastPosition) lastCurrentEntry.next = e;
lastCurrentEntry = e;
}else{
if(position != lastPosition) lastShiftedEntry.next = e;
lastShiftedEntry = e;
}
e = e.next;
}while(e != null);
lastCurrentEntry.next = null;
lastShiftedEntry.next = null;
newEntries[i] = currentEntryRoot.next;
newEntries[i | oldSize] = shiftedEntryRoot.next;
}
}
threshold <<= 1;
entries = newEntries;
hashMask = newHashMask;
}
private void ensureCapacity(){
if(load > threshold){
rehash();
}
}
public boolean put(int key, V1 value1, V2 value2){
ensureCapacity();
int position = key & hashMask;
Entry<V1, V2> currentStartEntry = entries[position];
if(currentStartEntry != null){
Entry<V1, V2> entry = currentStartEntry;
do{
if(entry.key == key){
entry.value1 = value1;
entry.value2 = value2;
return false;
}
}while((entry = entry.next) != null);
}
entries[position] = new Entry<V1, V2>(key, value1, value2, currentStartEntry);
++load;
return true;
}
public void putUnsafe(int key, V1 value1, V2 value2){
ensureCapacity();
int position = key & hashMask;
entries[position] = new Entry<V1, V2>(key, value1, value2, entries[position]);
++load;
}
public Entry<V1, V2> get(int key){
int position = key & hashMask;
Entry<V1, V2> entry = entries[position];
while(entry != null){
if(entry.key == key) return entry;
entry = entry.next;
}
return null;
}
public Entry<V1, V2> remove(int key){
int position = key & hashMask;
Entry<V1, V2> previous = null;
Entry<V1, V2> currentStartEntry = entries[position];
if(currentStartEntry != null){
Entry<V1, V2> entry = currentStartEntry;
do{
if(entry.key == key){
if(previous == null){
entries[position] = entry.next;
}else{
previous.next = entry.next;
}
--load;
return entry;
}
previous = entry;
}while((entry = entry.next) != null);
}
return null;
}
public int size() {
return load;
}
public void clear(){
int nrOfEntries = 1 << (bitSize = DEFAULT_BIT_SIZE);
hashMask = nrOfEntries - 1;
entries = (Entry<V1, V2>[]) new Entry[nrOfEntries];
threshold = nrOfEntries;
load = 0;
}
public Iterator<Entry<V1, V2>> entryIterator(){
return new EntryIterator<V1, V2>(this);
}
private static class EntryIterator<V1, V2> implements Iterator<Entry<V1, V2>>{
private final Entry<V1, V2>[] data;
private Entry<V1, V2> current;
private int index;
public EntryIterator(IntegerKeyedDoubleValueHashMap<V1, V2> integerKeyedDoubleValueHashMap){
super();
data = integerKeyedDoubleValueHashMap.entries;
index = data.length - 1;
current = new Entry<V1, V2>(-1, null, null, data[index]);
locateNext();
}
private void locateNext(){
Entry<V1, V2> next = current.next;
if(next != null){
current = next;
return;
}
for(int i = index - 1; i >= 0 ; i--){
Entry<V1, V2> entry = data[i];
if(entry != null){
current = entry;
index = i;
return;
}
}
current = null;
index = 0;
}
public boolean hasNext(){
return (current != null);
}
public Entry<V1, V2> next(){
if(!hasNext()) throw new UnsupportedOperationException("There are no more elements in this iterator.");
Entry<V1, V2> entry = current;
locateNext();
return entry;
}
public void remove(){
throw new UnsupportedOperationException("This iterator doesn't support removal.");
}
}
public static class Entry<V1, V2>{
public final int key;
public V1 value1;
public V2 value2;
public Entry<V1, V2> next;
public Entry(int key, V1 value1, V2 value2, Entry<V1, V2> next){
super();
this.key = key;
this.value1 = value1;
this.value2 = value2;
this.next = next;
}
}
}