Various cleanuppery: added containsKey(), deprecated contains(), added
getOrElse() and removeOrElse() and encourage their use in the class documentation (I was tempted to deprecate get() and remove() but I think that's going too far). git-svn-id: https://samskivert.googlecode.com/svn/trunk@2550 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -26,23 +26,22 @@ import java.io.ObjectOutputStream;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An int int map is like an int map, but with integers as values as well
|
* An int int map is like an int map, but with integers as values as well as keys. Be careful:
|
||||||
* as keys. Note that in situations where null would normally be returned
|
* {@link #get} and {@link #remove} return -1 to indicate that no previous mapping existed. Use
|
||||||
* to indicate no value, -1 is returned instead. This means that you must
|
* {@link #getOrElse} and {@link #removeOrElse} to use a different "default" value.
|
||||||
* be careful if you intend to store -1 as a valid value in the table.
|
|
||||||
*/
|
*/
|
||||||
//
|
|
||||||
// TODO: make this a proper map, perhaps even an extension of HashIntMap
|
|
||||||
// or at least share a common abstract ancestor.
|
|
||||||
public class IntIntMap
|
public class IntIntMap
|
||||||
implements Serializable
|
implements Serializable
|
||||||
{
|
{
|
||||||
|
// TODO: make this a proper map, perhaps even an extension of HashIntMap or at least share a
|
||||||
|
// common abstract ancestor.
|
||||||
|
|
||||||
public interface IntIntEntry extends IntMap.IntEntry<Integer>
|
public interface IntIntEntry extends IntMap.IntEntry<Integer>
|
||||||
{
|
{
|
||||||
public int getIntValue ();
|
public int getIntValue ();
|
||||||
@@ -78,11 +77,17 @@ public class IntIntMap
|
|||||||
return _size == 0;
|
return _size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of mappings.
|
||||||
|
*/
|
||||||
public int size ()
|
public int size ()
|
||||||
{
|
{
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the supplied key/value mapping. Any previous mapping for that key will be overwritten.
|
||||||
|
*/
|
||||||
public void put (int key, int value)
|
public void put (int key, int value)
|
||||||
{
|
{
|
||||||
_modCount++;
|
_modCount++;
|
||||||
@@ -115,10 +120,22 @@ public class IntIntMap
|
|||||||
_size++; // we're bigger
|
_size++; // we're bigger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value mapped to the specified key or -1 if there is no mapping.
|
||||||
|
*/
|
||||||
public int get (int key)
|
public int get (int key)
|
||||||
|
{
|
||||||
|
return getOrElse(key, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value mapped to the specified key or the supplied default value if there is no
|
||||||
|
* mapping.
|
||||||
|
*/
|
||||||
|
public int getOrElse (int key, int defval)
|
||||||
{
|
{
|
||||||
Record rec = locateRecord(key);
|
Record rec = locateRecord(key);
|
||||||
return (rec == null) ? -1 : rec.value;
|
return (rec == null) ? defval : rec.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,11 +156,78 @@ public class IntIntMap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this map contains a mapping for the specified key.
|
||||||
|
*
|
||||||
|
* @Deprecated use {@link #containsKey}.
|
||||||
|
*/
|
||||||
public boolean contains (int key)
|
public boolean contains (int key)
|
||||||
{
|
{
|
||||||
return (null != locateRecord(key));
|
return (null != locateRecord(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this map contains a mapping for the specified key.
|
||||||
|
*/
|
||||||
|
public boolean containsKey (int key)
|
||||||
|
{
|
||||||
|
return (null != locateRecord(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the value mapped for the specified key.
|
||||||
|
*
|
||||||
|
* @return the value to which the key was mapped or -1 if there was no mapping for that key.
|
||||||
|
*/
|
||||||
|
public int remove (int key)
|
||||||
|
{
|
||||||
|
return removeOrElse(key, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the value mapped for the specified key.
|
||||||
|
*
|
||||||
|
* @return the value to which the key was mapped or the supplied default value if there was no
|
||||||
|
* mapping for that key.
|
||||||
|
*/
|
||||||
|
public int removeOrElse (int key, int defval)
|
||||||
|
{
|
||||||
|
_modCount++;
|
||||||
|
int removed = removeImpl(key, defval);
|
||||||
|
checkShrink();
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all mappings.
|
||||||
|
*/
|
||||||
|
public void clear ()
|
||||||
|
{
|
||||||
|
_modCount++;
|
||||||
|
|
||||||
|
// abandon all of our hash chains (the joy of garbage collection)
|
||||||
|
for (int i = 0; i < _buckets.length; i++) {
|
||||||
|
_buckets[i] = null;
|
||||||
|
}
|
||||||
|
// zero out our size
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that the hash can comfortably hold the specified number of elements. Calling this
|
||||||
|
* method is not necessary, but can improve performance if done prior to adding many elements.
|
||||||
|
*/
|
||||||
|
public void ensureCapacity (int minCapacity)
|
||||||
|
{
|
||||||
|
int size = _buckets.length;
|
||||||
|
while (minCapacity > (int) (size * _loadFactor)) {
|
||||||
|
size *= 2;
|
||||||
|
}
|
||||||
|
if (size != _buckets.length) {
|
||||||
|
resizeBuckets(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to locate the record for the specified key.
|
* Internal method to locate the record for the specified key.
|
||||||
*/
|
*/
|
||||||
@@ -158,15 +242,10 @@ public class IntIntMap
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int remove (int key)
|
/**
|
||||||
{
|
* Internal method for removing a mapping.
|
||||||
_modCount++;
|
*/
|
||||||
int removed = removeImpl(key);
|
protected int removeImpl (int key, int defval)
|
||||||
checkShrink();
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int removeImpl (int key)
|
|
||||||
{
|
{
|
||||||
int index = Math.abs(key)%_buckets.length;
|
int index = Math.abs(key)%_buckets.length;
|
||||||
Record prev = null;
|
Record prev = null;
|
||||||
@@ -185,35 +264,7 @@ public class IntIntMap
|
|||||||
prev = rec;
|
prev = rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1; // not found
|
return defval; // not found
|
||||||
}
|
|
||||||
|
|
||||||
public void clear ()
|
|
||||||
{
|
|
||||||
_modCount++;
|
|
||||||
|
|
||||||
// abandon all of our hash chains (the joy of garbage collection)
|
|
||||||
for (int i = 0; i < _buckets.length; i++) {
|
|
||||||
_buckets[i] = null;
|
|
||||||
}
|
|
||||||
// zero out our size
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that the hash can comfortably hold the specified number
|
|
||||||
* of elements. Calling this method is not necessary, but can improve
|
|
||||||
* performance if done prior to adding many elements.
|
|
||||||
*/
|
|
||||||
public void ensureCapacity (int minCapacity)
|
|
||||||
{
|
|
||||||
int size = _buckets.length;
|
|
||||||
while (minCapacity > (int) (size * _loadFactor)) {
|
|
||||||
size *= 2;
|
|
||||||
}
|
|
||||||
if (size != _buckets.length) {
|
|
||||||
resizeBuckets(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -419,102 +470,80 @@ public class IntIntMap
|
|||||||
|
|
||||||
class IntEntryIterator implements Iterator<IntIntEntry>
|
class IntEntryIterator implements Iterator<IntIntEntry>
|
||||||
{
|
{
|
||||||
public IntEntryIterator ()
|
public IntEntryIterator () {
|
||||||
{
|
|
||||||
this._modCount = IntIntMap.this._modCount;
|
this._modCount = IntIntMap.this._modCount;
|
||||||
_index = _buckets.length;
|
_index = _buckets.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean hasNext () {
|
||||||
* Check for concurrent modifications.
|
|
||||||
*/
|
|
||||||
protected void checkMods ()
|
|
||||||
{
|
|
||||||
if (this._modCount != IntIntMap.this._modCount) {
|
|
||||||
throw new ConcurrentModificationException("IntIntMapIterator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext ()
|
|
||||||
{
|
|
||||||
checkMods();
|
checkMods();
|
||||||
|
|
||||||
// if we're pointing to an entry, we've got more entries
|
// if we're pointing to an entry, we've got more entries
|
||||||
if (_next != null) {
|
if (_next != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// search backward through the buckets looking for the next non-empty hash chain
|
||||||
// search backward through the buckets looking for the next
|
|
||||||
// non-empty hash chain
|
|
||||||
while (_index-- > 0) {
|
while (_index-- > 0) {
|
||||||
if ((_next = _buckets[_index]) != null) {
|
if ((_next = _buckets[_index]) != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// found no non-empty hash chains, we're done
|
// found no non-empty hash chains, we're done
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntIntEntry next ()
|
public IntIntEntry next () {
|
||||||
{
|
// if we're not pointing to an entry, search for the next non-empty hash chain
|
||||||
// if we're not pointing to an entry, search for the next
|
|
||||||
// non-empty hash chain
|
|
||||||
if (hasNext()) {
|
if (hasNext()) {
|
||||||
_prev = _next;
|
_prev = _next;
|
||||||
_next = _next.next;
|
_next = _next.next;
|
||||||
return _prev;
|
return _prev;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new NoSuchElementException("IntIntMapIterator");
|
throw new NoSuchElementException("IntIntMapIterator");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove ()
|
public void remove () {
|
||||||
{
|
|
||||||
checkMods();
|
checkMods();
|
||||||
|
|
||||||
if (_prev == null) {
|
if (_prev == null) {
|
||||||
throw new IllegalStateException("IntIntMapIterator");
|
throw new IllegalStateException("IntIntMapIterator");
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise remove the hard way
|
// otherwise remove the hard way
|
||||||
removeImpl(_prev.key);
|
removeImpl(_prev.key, -1);
|
||||||
_prev = null;
|
_prev = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkMods () {
|
||||||
|
if (this._modCount != IntIntMap.this._modCount) {
|
||||||
|
throw new ConcurrentModificationException("IntIntMapIterator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int _index;
|
private int _index;
|
||||||
private Record _next, _prev;
|
private Record _next, _prev;
|
||||||
private int _modCount;
|
private int _modCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class KeyValueInterator
|
protected class KeyValueInterator implements Interator
|
||||||
implements Interator
|
|
||||||
{
|
{
|
||||||
public KeyValueInterator (boolean keys, IntEntryIterator eiter)
|
public KeyValueInterator (boolean keys, IntEntryIterator eiter) {
|
||||||
{
|
|
||||||
_keys = keys;
|
_keys = keys;
|
||||||
_eiter = eiter;
|
_eiter = eiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int nextInt ()
|
public int nextInt () {
|
||||||
{
|
|
||||||
IntIntEntry entry = _eiter.next();
|
IntIntEntry entry = _eiter.next();
|
||||||
return _keys ? entry.getIntKey() : entry.getIntValue();
|
return _keys ? entry.getIntKey() : entry.getIntValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext ()
|
public boolean hasNext () {
|
||||||
{
|
|
||||||
return _eiter.hasNext();
|
return _eiter.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer next ()
|
public Integer next () {
|
||||||
{
|
|
||||||
return Integer.valueOf(nextInt());
|
return Integer.valueOf(nextInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove ()
|
public void remove () {
|
||||||
{
|
|
||||||
_eiter.remove();
|
_eiter.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,9 +577,7 @@ public class IntIntMap
|
|||||||
|
|
||||||
private Record[] _buckets;
|
private Record[] _buckets;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
|
||||||
protected float _loadFactor;
|
protected float _loadFactor;
|
||||||
|
|
||||||
protected int _modCount = 0;
|
protected int _modCount = 0;
|
||||||
|
|
||||||
/** Change this if the fields or inheritance hierarchy ever changes. */
|
/** Change this if the fields or inheritance hierarchy ever changes. */
|
||||||
|
|||||||
Reference in New Issue
Block a user