/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.util; import java.util.Iterator; import java.util.NoSuchElementException; /** * Stripped down implementation of HashSet for use * by core parts of the JikesRVM runtime. */ public final class VM_HashSet<T> implements Iterable<T> { private static final int DEFAULT_SIZE = 7; private static final float LOAD = 3; /* bias to save space by default */ private Bucket<T>[] buckets; private int numElems = 0; public VM_HashSet() { this(DEFAULT_SIZE); } @SuppressWarnings("unchecked") // the java generic array problem private Bucket<T>[] newBucketArray(int size) { return new Bucket[size]; } public VM_HashSet(int size) { buckets = newBucketArray(size); } public int size() { return numElems; } public void add(T key) { if (numElems > (buckets.length * LOAD)) { growMap(); } int bucketIdx = bucketIndex(key, buckets.length); Bucket<T> cur = buckets[bucketIdx]; while (cur != null && !cur.key.equals(key)) { cur = cur.next; } if (cur == null) { Bucket<T> newBucket = new Bucket<T>(key); newBucket.next = buckets[bucketIdx]; buckets[bucketIdx] = newBucket; numElems++; } } public T get(T key) { int bucketIdx = bucketIndex(key, buckets.length); Bucket<T> cur = buckets[bucketIdx]; while (cur != null && !cur.key.equals(key)) { cur = cur.next; } if (cur == null) { return null; } else { return cur.key; } } public boolean contains(T key) { return get(key) != null; } public void addAll(VM_HashSet<T> c) { for (T t : c) { add(t); } } private void growMap() { Bucket<T>[] newBuckets = newBucketArray(buckets.length * 2 + 1); for (Bucket<T> cur : buckets) { while (cur != null) { Bucket<T> next = cur.next; int newIdx = bucketIndex(cur.key, newBuckets.length); cur.next = newBuckets[newIdx]; newBuckets[newIdx] = cur; cur = next; } } buckets = newBuckets; } public void remove(T key) { int bucketIdx = bucketIndex(key, buckets.length); Bucket<T> cur = buckets[bucketIdx]; Bucket<T> prev = null; while (cur != null && !cur.key.equals(key)) { prev = cur; cur = cur.next; } if (cur != null) { if (prev == null) { // removing first bucket in chain. buckets[bucketIdx] = cur.next; } else { prev.next = cur.next; } numElems--; } } public Iterator<T> iterator() { return new SetIterator(); } private int bucketIndex(T key, int divisor) { if (key == null) { return 0; } else { return (key.hashCode() & 0x7fffffff) % divisor; } } private static final class Bucket<T> { final T key; Bucket<T> next; Bucket(T key) { this.key = key; } } /** * Iterator */ private class SetIterator implements Iterator<T> { private int bucketIndex = 0; private Bucket<T> next = null; private Bucket<T> last = null; private int numVisited = 0; public T next() { if (!hasNext()) { throw new NoSuchElementException(); } while (next == null) { next = buckets[bucketIndex++]; } Bucket<T> ans = next; next = ans.next; numVisited++; return ans.key; } public boolean hasNext() { return numVisited < numElems; } public void remove() { if (last == null) { throw new IllegalStateException(); } VM_HashSet.this.remove(last.key); last = null; } } }