/*******************************************************************************
* Copyright (c) 2009-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;
@SuppressWarnings("unchecked")
public class ObjectIntegerKeyedHashSet<E>{
private Entry<E>[] entries;
private int hashMask;
private int bitSize = 2;
private int threshold;
private int load;
public ObjectIntegerKeyedHashSet(){
super();
int nrOfEntries = 1 << bitSize;
hashMask = nrOfEntries - 1;
entries = new Entry[nrOfEntries];
threshold = nrOfEntries;
load = 0;
}
private void rehash(){
int nrOfEntries = 1 << (++bitSize);
int newHashMask = nrOfEntries - 1;
Entry<E>[] oldEntries = entries;
Entry<E>[] newEntries = new Entry[nrOfEntries];
Entry<E> currentEntryRoot = new Entry<E>(null, 0, 0, null);
Entry<E> shiftedEntryRoot = new Entry<E>(null, 0, 0, null);
int oldSize = oldEntries.length;
for(int i = oldSize - 1; i >= 0; --i){
Entry<E> e = oldEntries[i];
if(e != null){
Entry<E> lastCurrentEntry = currentEntryRoot;
Entry<E> lastShiftedEntry = shiftedEntryRoot;
int lastPosition = -1;
do{
int position = e.hash & 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(E element, int element2){
ensureCapacity();
int hash = element.hashCode() ^ (element2 << 5);
int position = hash & hashMask;
Entry<E> currentStartEntry = entries[position];
if(currentStartEntry != null){
Entry<E> entry = currentStartEntry;
do{
if(hash == entry.hash && entry.element2 == element2 && entry.element.equals(element)){
return false;
}
}while((entry = entry.next) != null);
}
entries[position] = new Entry<E>(element, element2, hash, currentStartEntry);
++load;
return true;
}
public void putUnsafe(E element, int element2){
ensureCapacity();
int hash = element.hashCode() ^ (element2 << 5);
int position = hash & hashMask;
entries[position] = new Entry<E>(element, element2, hash, entries[position]);
++load;
}
public boolean remove(E element, int element2){
int hash = element.hashCode() ^ (element2 << 5);
int position = hash & hashMask;
Entry<E> previous = null;
Entry<E> currentStartEntry = entries[position];
if(currentStartEntry != null){
Entry<E> entry = currentStartEntry;
do{
if(hash == entry.hash && entry.element2 == element2 && entry.element.equals(element)){
if(previous == null){
entries[position] = entry.next;
}else{
previous.next = entry.next;
}
load--;
return true;
}
previous = entry;
}while((entry = entry.next) != null);
}
return false;
}
public boolean contains(E element, int element2){
int hash = element.hashCode() ^ (element2 << 5);
int position = hash & hashMask;
Entry<E> entry = entries[position];
while(entry != null){
if(hash == entry.hash && element2 == entry.element2 && element.equals(entry.element)) return true;
entry = entry.next;
}
return false;
}
public E getEquivalent(E element, int element2){
int hash = element.hashCode() ^ (element2 << 5);
int position = hash & hashMask;
Entry<E> entry = entries[position];
while(entry != null){
if(hash == entry.hash && element2 == entry.element2 && element.equals(entry.element)) return entry.element;
entry = entry.next;
}
return null;
}
public void clear(){
entries = new Entry[entries.length];
load = 0;
}
private static class Entry<E>{
public final int hash;
public final E element;
public final int element2;
public Entry<E> next;
public Entry(E element, int element2, int hash, Entry<E> next){
super();
this.element = element;
this.element2 = element2;
this.hash = hash;
this.next = next;
}
}
}