/*******************************************************************************
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package hr.fer.zemris.vhdllab.applets.editor.schema2.misc;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
//TODO: implement double hashing
public class IntHashSet implements IntCollection, IntSet {
// TODO: improve iterator if possible
private class IntSetIterator implements Iterator<Integer> {
private int pos, last;
private Integer entry;
public IntSetIterator() {
pos = 0;
last = -1;
while (pos < space.length && space[pos] == EMPTY_CELL) pos++;
}
public boolean hasNext() {
return (pos < space.length);
}
public Integer next() {
if (pos >= space.length) throw new NoSuchElementException();
entry = Integer.valueOf(space[pos]);
last = pos;
pos++;
while (pos < space.length && space[pos] == EMPTY_CELL) pos++;
return entry;
}
public void remove() {
if (last == -1) throw new IllegalStateException();
IntHashSet.this.remove(last);
last = -1;
}
}
private final static float DEFAULT_LOAD_FACTOR = 0.65f;
private final static float MINIMAL_LOAD_FACTOR = 0.06f;
private final static float MAXIMAL_LOAD_FACTOR = 0.94f;
private final static int DUPL_FACTOR = 2;
private final static int EMPTY_CELL = Integer.MIN_VALUE;
private final static int[] SIZES = {
17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949,
21911, 43853, 87719, 175447, 350899, 701819, 1403641,
2807303
}; // TODO
protected int[] space;
private float loadfactor, loadstate;
private int size;
public IntHashSet() {
space = new int[SIZES[0]];
loadfactor = DEFAULT_LOAD_FACTOR;
init();
}
/**
* A copied IntSet does not have copies
* of the elements that are stored, but
* merely references to original objects.
* This IntSet's internal data structures
* are, on the other hand, constructed from
* scratch.
*
* @param other
*/
public IntHashSet(IntHashSet other) {
this.space = new int[other.space.length];
this.loadfactor = other.loadfactor;
this.loadstate = other.loadstate;
this.size = other.size;
for (int i = 0; i < other.space.length; i++) {
this.space[i] = other.space[i];
}
}
private final void init() {
size = 0;
loadstate = 0.f;
Arrays.fill(space, EMPTY_CELL);
}
/* (non-Javadoc)
* @see hr.fer.zemris.rg.axel.collections.IntSet#add(int)
*/
public final void add(int key) {
if (loadstate > loadfactor) resize(space.length * DUPL_FACTOR);
private_put(key);
}
private final void private_put(int key) {
int hval = hash(key);
while (space[hval] != EMPTY_CELL && space[hval] != key) hval = (hval + 1) % space.length;
if (space[hval] != key) size++;
space[hval] = key;
loadstate = 1.f * size / space.length;
}
/* (non-Javadoc)
* @see hr.fer.zemris.rg.axel.collections.IntSet#contains(int)
*/
public final boolean contains(int key) {
int hval = hash(key);
while (space[hval] != EMPTY_CELL && space[hval] != key) hval = (hval + 1) % space.length;
if (space[hval] == EMPTY_CELL) return false;
return true;
}
/* (non-Javadoc)
* @see hr.fer.zemris.rg.axel.collections.IntSet#remove(int)
*/
public final void remove(int key) { // TODO: implement shrinking
int hval = hash(key);
while (space[hval] != EMPTY_CELL && space[hval] != key) hval = (hval + 1) % space.length;
if (space[hval] != EMPTY_CELL) {
space[hval] = EMPTY_CELL;
size--;
loadstate = 1.f * size / space.length;
}
}
// TODO
/* (non-Javadoc)
* @see hr.fer.zemris.rg.axel.collections.IntSet#setLoadFactor(float)
*/
public final void setLoadFactor(float hashLoadFactor) {
if (hashLoadFactor <= MINIMAL_LOAD_FACTOR || hashLoadFactor >= MAXIMAL_LOAD_FACTOR) {
throw new RuntimeException("NI");
}
throw new RuntimeException("NI");
}
public final int capacity() {
return space.length;
}
public final void clear() {
init();
}
public final void reset() {
space = new int[SIZES[0]];
init();
}
/* (non-Javadoc)
* @see hr.fer.zemris.rg.axel.collections.IntSet#reset(int)
*/
public final void reset(int newsize) {
// find correct size (binary search)
int r = SIZES.length - 1, l = 0, x = 0;
while (r >= l) {
x = (l + r) / 2;
if (newsize < SIZES[x]) r = x - 1; else l = x + 1;
}
if (newsize < SIZES[x]) newsize = SIZES[x]; else newsize = SIZES[x+1];
space = new int[newsize];
}
public final boolean empty() {
return (size == 0);
}
// TODO
public final Iterator<Integer> iterator() {
return new IntSetIterator();
}
public final int size() {
return size;
}
private final int hash(int num) {
return num % space.length;
}
private final void resize(int newsize) {
// find correct size (binary search)
int r = SIZES.length - 1, l = 0, x = 0;
while (r >= l) {
x = (l + r) / 2;
if (newsize < SIZES[x]) r = x - 1; else l = x + 1;
}
if (newsize < SIZES[x]) newsize = SIZES[x]; else newsize = SIZES[x+1];
// put values to new hash space
int[] oldkeys = space;
l = size;
space = new int[newsize];
init();
for (r = 0; r < l; r++) {
if (oldkeys[r] != EMPTY_CELL) private_put(oldkeys[r]);
}
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof IntHashSet)) return false;
IntHashSet other = (IntHashSet)obj;
// lazy check
if (other.size != this.size || other.loadfactor != this.loadfactor) return false;
for (Integer entry : other) {
if (!this.contains(entry)) return false;
}
return true;
}
@Override
public int hashCode() {
int sum = 0, pos = 0;
while (pos < space.length) {
while (pos < space.length && space[pos] != EMPTY_CELL) pos++;
sum += space[pos];
pos++;
}
return sum;
}
@Override
public String toString() {
return super.toString() + "_IntHashSet";
}
}