Same speed, but create our Entry instead of the int[].

git-svn-id: https://samskivert.googlecode.com/svn/trunk@2705 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
ray.j.greenwell
2010-01-18 09:56:06 +00:00
parent c48106695a
commit efad5d31f6
+82 -75
View File
@@ -1,6 +1,8 @@
// //
// $Id$ // $Id$
package com.samskivert.util;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.AbstractSet; import java.util.AbstractSet;
import java.util.HashMap; import java.util.HashMap;
@@ -19,13 +21,13 @@ public class CountMap<K> extends AbstractMap<K, Integer>
*/ */
public CountMap () public CountMap ()
{ {
this(new HashMap<K, int[]>()); this(new HashMap<K, CountEntry<K>>());
} }
/** /**
* For subclassing, etc. Not yet public. * For subclassing, etc. Not yet public.
*/ */
protected CountMap (Map<K, int[]> backing) protected CountMap (Map<K, CountEntry<K>> backing)
{ {
if (!backing.isEmpty()) { if (!backing.isEmpty()) {
throw new IllegalArgumentException("Map is non-empty"); throw new IllegalArgumentException("Map is non-empty");
@@ -54,12 +56,12 @@ public class CountMap<K> extends AbstractMap<K, Integer>
*/ */
public int add (K key, int amount) public int add (K key, int amount)
{ {
int[] val = _backing.get(key); CountEntry<K> entry = _backing.get(key);
if (val == null) { if (entry == null) {
_backing.put(key, val = new int[1]); _backing.put(key, entry = new CountEntry<K>(key, amount));
return 0;
} }
val[0] += amount; return (entry.count += amount);
return val[0];
} }
/** /**
@@ -67,8 +69,8 @@ public class CountMap<K> extends AbstractMap<K, Integer>
*/ */
public int getCount (K key) public int getCount (K key)
{ {
int[] val = _backing.get(key); CountEntry<K> entry = _backing.get(key);
return (val == null) ? 0 : val[0]; return (entry == null) ? 0 : entry.count;
} }
/** /**
@@ -76,8 +78,8 @@ public class CountMap<K> extends AbstractMap<K, Integer>
*/ */
public void compress () public void compress ()
{ {
for (Iterator<int[]> it = _backing.values().iterator(); it.hasNext(); ) { for (Iterator<CountEntry<K>> it = _backing.values().iterator(); it.hasNext(); ) {
if (it.next()[0] == 0) { if (it.next().count == 0) {
it.remove(); it.remove();
} }
} }
@@ -86,16 +88,14 @@ public class CountMap<K> extends AbstractMap<K, Integer>
@Override @Override
public Set<Map.Entry<K, Integer>> entrySet () public Set<Map.Entry<K, Integer>> entrySet ()
{ {
if (_entrySet == null) { Set<Map.Entry<K, Integer>> es = _entrySet;
_entrySet = new EntrySet(); return (es != null) ? es : (_entrySet = new EntrySet());
}
return _entrySet;
} }
@Override @Override
public Integer put (K key, Integer value) public Integer put (K key, Integer value)
{ {
return integer(_backing.put(key, new int[] { value.intValue() })); return integer(_backing.put(key, new CountEntry<K>(key, value.intValue())));
} }
@Override @Override
@@ -139,33 +139,22 @@ public class CountMap<K> extends AbstractMap<K, Integer>
*/ */
protected class EntrySet extends AbstractSet<Map.Entry<K, Integer>> protected class EntrySet extends AbstractSet<Map.Entry<K, Integer>>
{ {
public Iterator<Map.Entry<K, Integer>> iterator () { @SuppressWarnings("unchecked")
return new Iterator<Map.Entry<K, Integer>>() { public Iterator<Map.Entry<K, Integer>> iterator ()
public boolean hasNext () { {
return _it.hasNext(); // fuck if I know why I gotta jump through this hoop
} Iterator<?> it = _backing.values().iterator();
return (Iterator<Map.Entry<K, Integer>>) it;
public Map.Entry<K, Integer> next () {
// I don't see any way around creating a new Entry here
return adaptEntry(_it.next());
}
public void remove () {
_it.remove();
}
protected Iterator<Map.Entry<K, int[]>> _it = _backing.entrySet().iterator();
};
} }
@Override
public boolean contains (Object o) { public boolean contains (Object o) {
if (!(o instanceof Map.Entry)) { if (!(o instanceof Map.Entry)) {
return false; return false;
} }
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o; Map.Entry<?, ?> oentry = (Map.Entry<?, ?>) o;
Integer value = CountMap.this.get(entry.getKey()); CountEntry<K> entry = _backing.get(oentry.getKey());
// we don't allow storing null, so getting a null means there's no mapping, return (entry != null) && entry.getValue().equals(oentry.getValue());
// and we don't have to check containsKey
return (value != null) && value.equals(entry.getValue());
} }
public boolean remove (Object o) { public boolean remove (Object o) {
@@ -188,53 +177,71 @@ public class CountMap<K> extends AbstractMap<K, Integer>
/** /**
* Return null or the boxed value contained in the count. * Return null or the boxed value contained in the count.
*/ */
protected static final Integer integer (int[] val) protected static final Integer integer (CountEntry<?> val)
{ {
return (val == null) ? null : val[0]; return (val == null) ? null : val.count;
} }
/** protected static class CountEntry<K>
* Adapt an entry from our internal backing map to one visible to users of this class. implements Map.Entry<K, Integer>
* Grumble.
*/
protected static <K> Map.Entry<K, Integer> adaptEntry (final Map.Entry<K, int[]> entry)
{ {
return new Map.Entry<K, Integer>() { public CountEntry (K key, int initialCount)
public K getKey () { {
return entry.getKey(); this.key = key;
this.count = initialCount;
}
public final K getKey ()
{
return key;
}
public Integer getValue ()
{
return count;
}
public Integer setValue (Integer newValue)
{
int oldVal = count;
count = newValue;
return oldVal;
}
public int hashCode ()
{
return ((key == null) ? 0 : key.hashCode()) ^ count;
}
public boolean equals (Object o)
{
if (o == this) {
return true;
} }
public Integer getValue () { if (!(o instanceof Map.Entry)) {
return integer(entry.getValue()); return false;
} }
public Integer setValue (Integer newVal) { Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
int[] val = entry.getValue(); Object okey = e.getKey();
Integer ret = integer(val); return ((key == null) ? (okey == null) : key.equals(okey)) &&
val[0] = newVal.intValue(); getValue().equals(e.getValue());
return ret; }
}
public int hashCode () { public String toString ()
K key = getKey(); {
return ((key == null) ? 0 : key.hashCode()) ^ getValue().hashCode(); return key + "=" + count;
} }
public boolean equals (Object o) {
if (!(o instanceof Map.Entry)) { /** The key. */
return false; protected final K key;
}
Map.Entry<?, ?> e = (Map.Entry<?, ?>) o; /** The current count. */
K key = getKey(); protected int count;
Object key2 = e.getKey();
return ((key == null) ? (key2 == null) : key.equals(key2)) &&
getValue().equals(e.getValue());
}
public String toString () {
return getKey() + "=" + entry.getValue()[0];
}
};
} }
/** Our backing map */ /** Our backing map */
protected Map<K, int[]> _backing; protected Map<K, CountEntry<K>> _backing;
/** The entrySet, if created. */ /** The entrySet, if created. */
protected transient volatile Set<Map.Entry<K, Integer>> _entrySet = null; protected transient Set<Map.Entry<K, Integer>> _entrySet = null;
} }