remove dead Fast* classes

git-svn-id: https://svn.apache.org/repos/asf/incubator/cassandra/trunk@887544 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Ellis 2009-12-05 14:22:25 +00:00
parent b8c65fadeb
commit fb2cbc8922
4 changed files with 0 additions and 1345 deletions

View File

@ -1,399 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.utils;
import java.util.Random;
/**
* Base class for hashtables that use open addressing to resolve collisions.
*/
abstract public class FastHash implements Cloneable
{
/** the current number of occupied slots in the hash. */
protected transient int size_;
/** the current number of free slots in the hash. */
protected transient int free_;
/** the load above which rehashing occurs. */
protected static final float DEFAULT_LOAD_FACTOR = 0.5f;
/**
* the default initial capacity for the hash table. This is one less than a
* prime value because one is added to it when searching for a prime
* capacity to account for the free slot required by open addressing. Thus,
* the real default capacity is 11.
*/
protected static final int DEFAULT_INITIAL_CAPACITY = 10;
/**
* Determines how full the internal table can become before rehashing is
* required. This must be a value in the range: 0.0 < loadFactor < 1.0. The
* default value is 0.5, which is about as large as you can get in open
* addressing without hurting performance. Cf. Knuth, Volume 3., Chapter 6.
*/
protected float loadFactor_;
/**
* The maximum number of elements allowed without allocating more space.
*/
protected int maxSize_;
/**
* The number of removes that should be performed before an auto-compaction
* occurs.
*/
protected int autoCompactRemovesRemaining_;
/**
* The auto-compaction factor for the table.
*
* @see #setAutoCompactionFactor
*/
protected float autoCompactionFactor_;
/**
* @see
*/
private boolean autoCompactTemporaryDisable_ = false;
/**
* Creates a new <code>THash</code> instance with the default capacity and
* load factor.
*/
public FastHash()
{
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new <code>THash</code> instance with a prime capacity at or
* near the specified capacity and with the default load factor.
*
* @param initialCapacity
* an <code>int</code> value
*/
public FastHash(int initialCapacity)
{
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new <code>THash</code> instance with a prime capacity at or
* near the minimum needed to hold <tt>initialCapacity</tt> elements with
* load factor <tt>loadFactor</tt> without triggering a rehash.
*
* @param initialCapacity
* an <code>int</code> value
* @param loadFactor
* a <code>float</code> value
*/
public FastHash(int initialCapacity, float loadFactor)
{
super();
loadFactor_ = loadFactor;
// Through testing, the load factor (especially the default load factor)
// has been
// found to be a pretty good starting auto-compaction factor.
autoCompactionFactor_ = loadFactor;
setUp((int) Math.ceil(initialCapacity / loadFactor));
}
public Object clone()
{
try
{
return super.clone();
}
catch (CloneNotSupportedException cnse)
{
return null; // it's supported
}
}
/**
* Tells whether this set is currently holding any elements.
*
* @return a <code>boolean</code> value
*/
public boolean isEmpty()
{
return 0 == size_;
}
/**
* Returns the number of distinct elements in this collection.
*
* @return an <code>int</code> value
*/
public int size()
{
return size_;
}
/**
* @return the current physical capacity of the hash table.
*/
abstract protected int capacity();
/**
* Ensure that this hashtable has sufficient capacity to hold
* <tt>desiredCapacity<tt> <b>additional</b> elements without
* requiring a rehash. This is a tuning method you can call
* before doing a large insert.
*
* @param desiredCapacity an <code>int</code> value
*/
public void ensureCapacity(int desiredCapacity)
{
if (desiredCapacity > (maxSize_ - size()))
{
rehash(PrimeFinder.nextPrime((int) Math.ceil(desiredCapacity
+ size() / loadFactor_) + 1));
computeMaxSize(capacity());
}
}
/**
* Compresses the hashtable to the minimum prime size (as defined by
* PrimeFinder) that will hold all of the elements currently in the table.
* If you have done a lot of <tt>remove</tt> operations and plan to do a
* lot of queries or insertions or iteration, it is a good idea to invoke
* this method. Doing so will accomplish two things:
*
* <ol>
* <li> You'll free memory allocated to the table but no longer needed
* because of the remove()s.</li>
*
* <li> You'll get better query/insert/iterator performance because there
* won't be any <tt>REMOVED</tt> slots to skip over when probing for
* indices in the table.</li>
* </ol>
*/
public void compact()
{
// need at least one free spot for open addressing
rehash(PrimeFinder.nextPrime((int) Math.ceil(size() / loadFactor_) + 1));
computeMaxSize(capacity());
// If auto-compaction is enabled, re-determine the compaction interval
if (autoCompactionFactor_ != 0)
{
computeNextAutoCompactionAmount(size());
}
}
/**
* The auto-compaction factor controls whether and when a table performs a
* {@link #compact} automatically after a certain number of remove
* operations. If the value is non-zero, the number of removes that need to
* occur for auto-compaction is the size of table at the time of the
* previous compaction (or the initial capacity) multiplied by this factor.
* <p>
* Setting this value to zero will disable auto-compaction.
*/
public void setAutoCompactionFactor(float factor)
{
if (factor < 0)
{
throw new IllegalArgumentException("Factor must be >= 0: " + factor);
}
autoCompactionFactor_ = factor;
}
/**
* @see #setAutoCompactionFactor
*/
public float getAutoCompactionFactor()
{
return autoCompactionFactor_;
}
/**
* This simply calls {@link #compact compact}. It is included for symmetry
* with other collection classes. Note that the name of this method is
* somewhat misleading (which is why we prefer <tt>compact</tt>) as the
* load factor may require capacity above and beyond the size of this
* collection.
*
* @see #compact
*/
public final void trimToSize()
{
compact();
}
/**
* Delete the record at <tt>index</tt>. Reduces the size of the
* collection by one.
*
* @param index
* an <code>int</code> value
*/
protected void removeAt(int index)
{
size_--;
// If auto-compaction is enabled, see if we need to compact
if (autoCompactionFactor_ != 0)
{
autoCompactRemovesRemaining_--;
if (!autoCompactTemporaryDisable_
&& autoCompactRemovesRemaining_ <= 0)
{
// Do the compact
// NOTE: this will cause the next compaction interval to be
// calculated
compact();
}
}
}
/**
* Empties the collection.
*/
public void clear()
{
size_ = 0;
free_ = capacity();
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity
* an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp(int initialCapacity)
{
int capacity;
capacity = PrimeFinder.nextPrime(initialCapacity);
computeMaxSize(capacity);
computeNextAutoCompactionAmount(initialCapacity);
return capacity;
}
/**
* Rehashes the set.
*
* @param newCapacity
* an <code>int</code> value
*/
protected abstract void rehash(int newCapacity);
/**
* Temporarily disables auto-compaction. MUST be followed by calling
* {@link #reenableAutoCompaction}.
*/
protected void tempDisableAutoCompaction()
{
autoCompactTemporaryDisable_ = true;
}
/**
* Re-enable auto-compaction after it was disabled via
* {@link #tempDisableAutoCompaction()}.
*
* @param check_for_compaction
* True if compaction should be performed if needed before
* returning. If false, no compaction will be performed.
*/
protected void reenableAutoCompaction(boolean check_for_compaction)
{
autoCompactTemporaryDisable_ = false;
if (check_for_compaction && autoCompactRemovesRemaining_ <= 0
&& autoCompactionFactor_ != 0)
{
// Do the compact
// NOTE: this will cause the next compaction interval to be
// calculated
compact();
}
}
/**
* Computes the values of maxSize. There will always be at least one free
* slot required.
*
* @param capacity
* an <code>int</code> value
*/
private final void computeMaxSize(int capacity)
{
// need at least one free slot for open addressing
maxSize_ = Math.min(capacity - 1, (int) Math.floor(capacity
* loadFactor_));
free_ = capacity - size_; // reset the free element count
}
/**
* Computes the number of removes that need to happen before the next
* auto-compaction will occur.
*/
private void computeNextAutoCompactionAmount(int size)
{
if (autoCompactionFactor_ != 0)
{
autoCompactRemovesRemaining_ = Math.round(size
* autoCompactionFactor_);
}
}
/**
* After an insert, this hook is called to adjust the size/free values of
* the set and to perform rehashing if necessary.
*/
protected final void postInsertHook(boolean usedFreeSlot)
{
if (usedFreeSlot)
{
free_--;
}
// rehash whenever we exhaust the available space in the table
if (++size_ > maxSize_ || free_ == 0)
{
// choose a new capacity suited to the new state of the table
// if we've grown beyond our maximum size, double capacity;
// if we've exhausted the free spots, rehash to the same capacity,
// which will free up any stale removed slots for reuse.
int newCapacity = size_ > maxSize_ ? PrimeFinder
.nextPrime(capacity() << 1) : capacity();
rehash(newCapacity);
computeMaxSize(capacity());
}
}
protected int calculateGrownCapacity()
{
return capacity() << 1;
}
}// THash

View File

@ -1,600 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.utils;
import java.io.*;
import java.util.*;
/**
* An implementation of the Map interface which uses an open addressed hash
* table to store its contents
*/
public class FastHashMap<K, V> extends FastObjectHash<K> implements Map<K, V>, Serializable
{
static final long serialVersionUID = 1L;
/** the values of the map */
protected transient V[] values_;
/**
* Creates a new <code>FastHashMap</code> instance with the default capacity
* and load factor.
*/
public FastHashMap()
{
super();
}
/**
* Creates a new <code>FastHashMap</code> instance with a prime capacity
* equal to or greater than <tt>initialCapacity</tt> and with the default
* load factor.
*
* @param initialCapacity
* an <code>int</code> value
*/
public FastHashMap(int initialCapacity)
{
super(initialCapacity);
}
/**
* Creates a new <code>FastHashMap</code> instance with a prime capacity
* equal to or greater than <tt>initialCapacity</tt> and with the
* specified load factor.
*
* @param initialCapacity
* an <code>int</code> value
* @param loadFactor
* a <code>float</code> value
*/
public FastHashMap(int initialCapacity, float loadFactor)
{
super(initialCapacity, loadFactor);
}
/**
* Creates a new <code>FastHashMap</code> instance which contains the
* key/value pairs in <tt>map</tt>.
*
* @param map
* a <code>Map</code> value
*/
public FastHashMap(Map<K, V> map)
{
this(map.size());
putAll(map);
}
/**
* @return a shallow clone of this collection
*/
public FastHashMap<K, V> clone()
{
FastHashMap<K, V> m = (FastHashMap<K, V>) super.clone();
m.values_ = this.values_.clone();
return m;
}
/**
* initialize the value array of the map.
*
* @param initialCapacity
* an <code>int</code> value
* @return an <code>int</code> value
*/
protected int setUp(int initialCapacity)
{
int capacity;
capacity = super.setUp(initialCapacity);
values_ = (V[]) new Object[capacity];
return capacity;
}
void addEntry(Object key, int index)
{
}
void removeEntry(Object key, int index)
{
}
/**
* Inserts a key/value pair into the map.
*
* @param key
* an <code>Object</code> value
* @param value
* an <code>Object</code> value
* @return the previous value associated with <tt>key</tt>, or null if
* none was found.
*/
public V put(K key, V value)
{
V previous = null;
Object oldKey;
int index = insertionIndex(key);
boolean isNewMapping = true;
if (index < 0)
{
index = -index - 1;
previous = values_[index];
isNewMapping = false;
}
oldKey = set_[index];
if ( oldKey == FREE )
{
/* This is used as a hook to process new put() operations */
addEntry(key, index);
}
set_[index] = key;
values_[index] = value;
if (isNewMapping)
{
postInsertHook(oldKey == FREE);
}
return previous;
}
/**
* rehashes the map to the new capacity.
*
* @param newCapacity
* an <code>int</code> value
*/
protected void rehash(int newCapacity)
{
int oldCapacity = set_.length;
Object oldKeys[] = set_;
V oldVals[] = values_;
set_ = new Object[newCapacity];
Arrays.fill(set_, FREE);
values_ = (V[]) new Object[newCapacity];
for (int i = oldCapacity; i-- > 0;)
{
if (oldKeys[i] != FREE && oldKeys[i] != REMOVED)
{
Object o = oldKeys[i];
int index = insertionIndex((K) o);
if (index < 0)
{
throwObjectContractViolation(set_[(-index - 1)], o);
}
set_[index] = o;
values_[index] = oldVals[i];
}
}
}
/**
* retrieves the value for <tt>key</tt>
*
* @param key
* an <code>Object</code> value
* @return the value of <tt>key</tt> or null if no such mapping exists.
*/
public V get(Object key)
{
int index = index((K) key);
return index < 0 ? null : values_[index];
}
/**
* Empties the map.
*
*/
public void clear()
{
if (size() == 0)
return; // optimization
super.clear();
Object[] keys = set_;
V[] vals = values_;
for (int i = keys.length; i-- > 0;)
{
keys[i] = FREE;
vals[i] = null;
}
}
/**
* Deletes a key/value pair from the map.
*
* @param key an <code>Object</code> value
* @return an <code>Object</code> value
*/
public V remove(Object key)
{
V prev = null;
int index = index((K)key);
if (index >= 0)
{
prev = values_[index];
/* clear key,state; adjust size */
removeAt(index);
/* This is used as hook to process deleted items */
removeEntry(key, index);
}
return prev;
}
/**
* removes the mapping at <tt>index</tt> from the map.
*
* @param index an <code>int</code> value
*/
protected void removeAt(int index)
{
values_[index] = null;
/* clear key, state; adjust size */
super.removeAt(index);
}
/**
* Returns a view on the values of the map.
*
* @return a <code>Collection</code> value
*/
public Collection<V> values()
{
return Arrays.asList(values_);
}
/**
* returns a Set view on the keys of the map.
*
* @return a <code>Set</code> value
*/
public Set<K> keySet()
{
return new KeyView();
}
/**
* Returns a Set view on the entries of the map.
*
* @return a <code>Set</code> value
*/
public Set<Map.Entry<K, V>> entrySet()
{
throw new UnsupportedOperationException(
"This operation is currently not supported.");
}
/**
* checks for the presence of <tt>val</tt> in the values of the map.
*
* @param val
* an <code>Object</code> value
* @return a <code>boolean</code> value
*/
public boolean containsValue(Object val)
{
Object[] set = set_;
V[] vals = values_;
// special case null values so that we don't have to
// perform null checks before every call to equals()
if (null == val)
{
for (int i = vals.length; i-- > 0;)
{
if ((set[i] != FREE && set[i] != REMOVED) && val == vals[i])
{
return true;
}
}
}
else
{
for (int i = vals.length; i-- > 0;)
{
if ((set[i] != FREE && set[i] != REMOVED)
&& (val == vals[i] || val.equals(vals[i])))
{
return true;
}
}
} // end of else
return false;
}
/**
* checks for the present of <tt>key</tt> in the keys of the map.
*
* @param key
* an <code>Object</code> value
* @return a <code>boolean</code> value
*/
public boolean containsKey(Object key)
{
return contains(key);
}
/**
* copies the key/value mappings in <tt>map</tt> into this map.
*
* @param map
* a <code>Map</code> value
*/
public void putAll(Map<? extends K, ? extends V> map)
{
ensureCapacity(map.size());
// could optimize this for cases when map instanceof FastHashMap
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = map
.entrySet().iterator(); i.hasNext();)
{
Map.Entry<? extends K, ? extends V> e = i.next();
put(e.getKey(), e.getValue());
}
}
private abstract class MapBackedView<E> extends AbstractSet<E> implements Set<E>, Iterable<E>
{
public abstract Iterator<E> iterator();
public abstract boolean removeElement(E key);
public abstract boolean containsElement(E key);
public boolean contains(Object key)
{
return containsElement((E) key);
}
public boolean remove(Object o)
{
return removeElement((E) o);
}
public boolean containsAll(Collection<?> collection)
{
for (Iterator i = collection.iterator(); i.hasNext();)
{
if (!contains(i.next()))
{
return false;
}
}
return true;
}
public void clear()
{
FastHashMap.this.clear();
}
public boolean add(E obj)
{
throw new UnsupportedOperationException();
}
public int size()
{
return FastHashMap.this.size();
}
public Object[] toArray()
{
Object[] result = new Object[size()];
Iterator e = iterator();
for (int i = 0; e.hasNext(); i++)
result[i] = e.next();
return result;
}
public <T> T[] toArray(T[] a)
{
int size = size();
if (a.length < size)
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
Object[] result = a;
for (int i = 0; i < size; i++)
{
result[i] = it.next();
}
if (a.length > size)
{
a[size] = null;
}
return a;
}
public boolean isEmpty()
{
return FastHashMap.this.isEmpty();
}
public boolean addAll(Collection<? extends E> collection)
{
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> collection)
{
boolean changed = false;
Iterator i = iterator();
while (i.hasNext())
{
if (!collection.contains(i.next()))
{
i.remove();
changed = true;
}
}
return changed;
}
}
protected class FastHashMapIterator<T> implements Iterator<T>
{
private int nextIndex_;
private int expectedSize_;
private FastObjectHash<T> tMap_;
FastHashMapIterator(FastObjectHash<T> tMap)
{
nextIndex_ = -1;
expectedSize_ = tMap.size();
tMap_ = tMap;
}
public boolean hasNext()
{
return (expectedSize_ > 0);
}
public T next()
{
moveToNextIndex();
int index = nextIndex_;
/*
* Decrement so that we can track how many
* elements we have already looked at.
*/
--expectedSize_;
return (T)tMap_.set_[index];
}
private void moveToNextIndex()
{
int i = nextIndex_ + 1;
for ( ; i < tMap_.set_.length; ++i )
{
if ( tMap_.set_[i].equals(FREE) || tMap_.set_[i].equals(REMOVED) )
{
continue;
}
else
{
break;
}
}
nextIndex_ = i;
}
public void remove()
{
tMap_.removeAt(nextIndex_);
--expectedSize_;
}
}
/**
* a view onto the keys of the map.
*/
protected class KeyView extends MapBackedView<K>
{
public Iterator<K> iterator()
{
return new FastHashMapIterator(FastHashMap.this);
}
public boolean removeElement(K key)
{
return null != FastHashMap.this.remove(key);
}
public boolean containsElement(K key)
{
return FastHashMap.this.contains(key);
}
}
final class Entry implements Map.Entry<K, V>
{
private K key;
private V val;
private final int index;
Entry(final K key, V value, final int index)
{
this.key = key;
this.val = value;
this.index = index;
}
void setKey(K aKey)
{
this.key = aKey;
}
void setValue0(V aValue)
{
this.val = aValue;
}
public K getKey()
{
return key;
}
public V getValue()
{
return val;
}
public V setValue(V o)
{
if (values_[index] != val)
{
throw new ConcurrentModificationException();
}
values_[index] = o;
o = val; // need to return previous value
val = o; // update this entry's value, in case
// setValue is called again
return o;
}
public boolean equals(Object o)
{
if (o instanceof Map.Entry)
{
Map.Entry e1 = this;
Map.Entry e2 = (Map.Entry) o;
return (e1.getKey() == null ? e2.getKey() == null : e1.getKey().equals(e2.getKey()))
&& (e1.getValue() == null ? e2.getValue() == null : e1.getValue().equals(e2.getValue()));
}
return false;
}
public int hashCode()
{
return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
}
}
public static void main(String[] args) throws Throwable
{
Map<String, String> map = new FastHashMap<String, String>();
map.put("Avinash", "Avinash");
map.put("Avinash", "Srinivas");
}
}

View File

@ -1,24 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.utils;
public class FastLinkedHashMap<K,V> extends FastHashMap<K,V>
{
}

View File

@ -1,322 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.utils;
import java.util.Arrays;
/**
* An open addressed hashing implementation for Object types.
*/
abstract public class FastObjectHash<T> extends FastHash
{
static final long serialVersionUID = -3461112548087185871L;
/** the set of Objects */
protected transient Object[] set_;
protected static final Object REMOVED = new Object(), FREE = new Object();
/**
* Creates a new <code>TObjectHash</code> instance with the default
* capacity and load factor.
*/
public FastObjectHash()
{
super();
}
/**
* Creates a new <code>TObjectHash</code> instance whose capacity is the
* next highest prime above <tt>initialCapacity + 1</tt> unless that value
* is already prime.
*
* @param initialCapacity
* an <code>int</code> value
*/
public FastObjectHash(int initialCapacity)
{
super(initialCapacity);
}
/**
* Creates a new <code>TObjectHash</code> instance with a prime value at
* or near the specified capacity and load factor.
*
* @param initialCapacity
* used to find a prime capacity for the table.
* @param loadFactor
* used to calculate the threshold over which rehashing takes
* place.
*/
public FastObjectHash(int initialCapacity, float loadFactor)
{
super(initialCapacity, loadFactor);
}
/**
* @return a shallow clone of this collection
*/
public FastObjectHash<T> clone()
{
FastObjectHash<T> h = (FastObjectHash<T>) super.clone();
h.set_ = (Object[]) this.set_.clone();
return h;
}
/**
* This method is invoked every time a key is
* added into the Map.
* @param key key that is inserted
* @param index index position of the key being
* inserted
*/
abstract void addEntry(Object key, int index);
/**
* This method is invoked every time a key is
* deleted from the Map.
* @param key key being deleted
* @param index index position of the key being
* deleted
*/
abstract void removeEntry(Object key, int index);
protected int capacity()
{
return set_.length;
}
protected void removeAt(int index)
{
set_[index] = REMOVED;
super.removeAt(index);
}
/**
* initializes the Object set of this hash table.
*
* @param initialCapacity
* an <code>int</code> value
* @return an <code>int</code> value
*/
protected int setUp(int initialCapacity)
{
int capacity;
capacity = super.setUp(initialCapacity);
set_ = new Object[capacity];
Arrays.fill(set_, FREE);
return capacity;
}
/**
* Searches the set for <tt>obj</tt>
*
* @param obj
* an <code>Object</code> value
* @return a <code>boolean</code> value
*/
public boolean contains(Object obj)
{
return index((T) obj) >= 0;
}
/**
* Locates the index of <tt>obj</tt>.
*
* @param obj
* an <code>Object</code> value
* @return the index of <tt>obj</tt> or -1 if it isn't in the set.
*/
protected int index(Object obj)
{
final Object[] set = set_;
final int length = set.length;
final int hash = obj.hashCode() & 0x7fffffff;
int index = hash % length;
Object cur = set[index];
if (cur == FREE)
return -1;
// NOTE: here it has to be REMOVED or FULL (some user-given value)
if (cur == REMOVED || cur.equals(obj))
{
// see Knuth, p. 529
final int probe = 1 + (hash % (length - 2));
while (cur != FREE&& (cur == REMOVED || !cur.equals(obj)))
{
index -= probe;
if (index < 0)
{
index += length;
}
cur = set[index];
}
}
return cur == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>obj</tt> can be inserted. if there is
* already a value equal()ing <tt>obj</tt> in the set, returns that
* value's index as <tt>-index - 1</tt>.
*
* @param obj
* an <code>Object</code> value
* @return the index of a FREE slot at which obj can be inserted or, if obj
* is already stored in the hash, the negative value of that index,
* minus 1: -index -1.
*/
protected int insertionIndex(T obj)
{
final Object[] set = set_;
final int length = set.length;
final int hash = obj.hashCode() & 0x7fffffff;
int index = hash % length;
Object cur = set[index];
if (cur == FREE)
{
return index; // empty, all done
}
else if (cur != REMOVED && cur.equals(obj))
{
return -index - 1; // already stored
}
else
{ // already FULL or REMOVED, must probe
// compute the double token
final int probe = 1 + (hash % (length - 2));
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if (cur != REMOVED)
{
// starting at the natural offset, probe until we find an
// offset that isn't full.
do
{
index -= probe;
if (index < 0)
{
index += length;
}
cur = set[index];
}
while (cur != FREE && cur != REMOVED
&& !cur.equals(obj));
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if (cur == REMOVED)
{
int firstRemoved = index;
while (cur != FREE
&& (cur == REMOVED || !cur.equals(obj)))
{
index -= probe;
if (index < 0)
{
index += length;
}
cur = set[index];
}
// NOTE: cur cannot == REMOVED in this block
return (cur != FREE) ? -index - 1 : firstRemoved;
}
// if it's full, the key is already stored
// NOTE: cur cannot equal REMOVE here (would have returned already
// (see above)
return (cur != FREE) ? -index - 1 : index;
}
}
/**
* This is the default implementation of TObjectHashingStrategy: it
* delegates hashing to the Object's hashCode method.
*
* @param o
* for which the hashcode is to be computed
* @return the hashCode
* @see Object#hashCode()
*/
public final int computeHashCode(T o)
{
return o == null ? 0 : o.hashCode();
}
/**
* This is the default implementation of TObjectHashingStrategy: it
* delegates equality comparisons to the first parameter's equals() method.
*
* @param o1
* an <code>Object</code> value
* @param o2
* an <code>Object</code> value
* @return true if the objects are equal
* @see Object#equals(Object)
*/
public final boolean equals(T o1, T o2)
{
return o1 == null ? o2 == null : o1.equals(o2);
}
/**
* Convenience methods for subclasses to use in throwing exceptions about
* badly behaved user objects employed as keys. We have to throw an
* IllegalArgumentException with a rather verbose message telling the user
* that they need to fix their object implementation to conform to the
* general contract for java.lang.Object.
*
* @param o1
* the first of the equal elements with unequal hash codes.
* @param o2
* the second of the equal elements with unequal hash codes.
* @exception IllegalArgumentException
* the whole point of this method.
*/
protected final void throwObjectContractViolation(Object o1, Object o2)
throws IllegalArgumentException
{
throw new IllegalArgumentException(
"Equal objects must have equal hashcodes. "
+ "During rehashing, Trove discovered that "
+ "the following two objects claim to be "
+ "equal (as in java.lang.Object.equals()) "
+ "but their hashCodes (or those calculated by "
+ "your TObjectHashingStrategy) are not equal."
+ "This violates the general contract of "
+ "java.lang.Object.hashCode(). See bullet point two "
+ "in that method's documentation. " + "object #1 ="
+ o1 + "; object #2 =" + o2);
}
} // TObjectHash