importjava.util.Arrays;
importjava.util.Collection;
importjava.util.Iterator;
importjava.util.Map;
/**
* A map with circular references so that all entries have a next entry and the
* table is pre-populated with null-key and null-value entries to hold the
* initial chain of entries. Having circular references enables quick iteration
* of entries. This map implementation also supports multiple entries with the
* same key value via the {@link #add(Object, Object)} method.
* <p>
* There are supporting methods to handle multiple keys like
* {@link #entriesWithKey(Object)}, {@link #removeAll(Object)},
* {@link #countOf(Object)}, {@link #removeAll(Object...)},
* {@link #getAll(Object, Collection)}, and {@link #removeAll(Iterable)}.
* </p>
* <p>
* There are also supporting methods to handle multiple values like
* {@link #entriesWithValue(Object)}, {@link #removeAllValue(Iterable)},
* {@link #removeAllValue(Object...)}, {@link #getAllKeys(Object, Collection)},
* and {@link #countOfValue(Object)}.
* </p>
* <p>
* This map implementation caches iterators for it's entries, values, keys,
* entries with a specific key, and entries with a specific value. This is to
* avoid needless allocation of iterators. The one drawback with this design
* however is that you must avoid nested iterations over the same iterator -
* this will not work.
* </p>
* <p>
* This map implementation can also cache entries and reuse them between all
* instances via the {@link #initPool(int)} method.
* </p>
* <p>
* This map was built with speed and minimizing garbage in mind.
* </p>
* <p>
* The fields of the Entry class are all public, do not modify these values.
* </p>
*
* @author Philip Diffenderfer
*
* @param <K>
* The key type.
* @param <V>
* The value type.
*/@SuppressWarnings ({"rawtypes","unchecked"})
publicclassCyclicMap<K, V>
{
publicstaticfinalintSIZE_1 = 0;
publicstaticfinalintSIZE_2 = 1;
publicstaticfinalintSIZE_4 = 2;
publicstaticfinalintSIZE_8 = 3;
publicstaticfinalintSIZE_16 = 4;
publicstaticfinalintSIZE_32 = 5;
publicstaticfinalintSIZE_64 = 6;
publicstaticfinalintSIZE_128 = 7;
publicstaticfinalintSIZE_256 = 8;
publicstaticfinalintSIZE_512 = 9;
publicstaticfinalintSIZE_1024 = 10;
publicstaticfinalintSIZE_2048 = 11;
publicstaticfinalintSIZE_4096 = 12;
privatefinalintcapacity;
privatefinalintmod;
privatefinalEntry<K, V>[] table;
privateintsize;
privatefinalEntryIterableentries;
privatefinalValueIterablevalues;
privatefinalKeyIterablekeys;
privatefinalMultiKeyIterablemultiKey;
privatefinalMultiValueIterablemultiValue;
/**
* Initializes a CycleMap with a table size of 2<sup>tablePower</sup>.
*/publicCyclicMap( inttablePower )
{
this.capacity = (1 << tablePower);
this.mod = capacity - 1;
this.table = newEntry[capacity];
this.entries = newEntryIterable();
this.values = newValueIterable();
this.keys = newKeyIterable();
this.multiKey = newMultiKeyIterable();
this.multiValue = newMultiValueIterable();
for (inti = 0; i < capacity; i++) {
table[i] = newEntry();
table[i].hash = i;
}
this.clear( false );
}
/**
* Adds an entry to the map with the given key and value, ignoring whether
* the key exists in the map already (for opposite behavior see
* {@link #put(Object, Object)}).
*/publicvoidadd(finalKkey, finalVvalue)
{
finalinthash = hash( key );
finalinttableIndex = hash & mod;
finalEntry<K, V> first = table[ tableIndex ];
finalEntry<K, V> next = newEntry();
next.key = key;
next.value = value;
next.hash = hash;
next.next = first.next;
first.next = next;
size++;
}
/**
* Adds all entries that exist in the given map to this map.
* @see #add(Object, Object)
*/publicvoidaddAll(finalMap<K, V> map)
{
for (Map.Entry<K, V> entry : map.entrySet())
{
add( entry.getKey(), entry.getValue() );
}
}
/**
* Adds all entries that exist in the given map to this map.
* @see #add(Object, Object)
*/publicvoidaddAll(finalCyclicMap<K, V> map)
{
for (Entry<K, V> entry : map.entries)
{
add( entry.key, entry.value );
}
}
/**
* Adds the value to the map if an entry with the given key does not exist
* already, if it does this method has no affect. Returns true if the
* value was added, otherwise false.
*/publicbooleanaddIfAbsent(finalKkey, finalVvalue)
{
finalEntry<K, V> before = beforeKey( key );
finalbooleanabsent = (before == null);
if (absent)
{
add( key, value );
}
returnabsent;
}
/**
* Adds the value to the map if an entry with the key doesn't exist,
* otherwise the old entry with a matching key will have it's value
* replaced and the previous value returned. If there are multiple
* entries in the map with the given key the last added entry will
* have it's value overridden.
*/publicVput(finalKkey, finalVvalue)
{
finalEntry<K, V> before = beforeKey( key );
VpreviousValue = null;
if ( before == null )
{
add( key, value );
}
else
{
Entry<K, V> entry = before.next;
previousValue = entry.value;
entry.value = value;
}
returnpreviousValue;
}
/**
* Puts all keys and values from the given map into this map overwriting
* any entries with the same keys. If the given map has entries with
* duplicate keys the value of the oldest entry will be the one taken. If
* a destination Collection is given all non-null previous values will
* be added to it. If the given map has duplicate keys AND a destination is
* given there is a chance multiple values will be inserted into the
* destination that had the same key. Returns the destination passed in.
*/public <DextendsCollection<V>> DputAll(finalCyclicMap<K, V> map, finalDdestination)
{
for (Entry<K, V> entry : map.entries)
{
Vprevious = put( entry.key, entry.value );
if ( previous != null && destination != null )
{
destination.add( previous );
}
}
returndestination;
}
/**
* Puts all keys and values from the given map into this map overwriting
* any entries with the same keys. If the given map has entries with
* duplicate keys the value of the oldest entry will be the one taken. If
* a destination Collection is given all non-null previous values will
* be added to it. If the given map has duplicate keys AND a destination is
* given there is a chance multiple values will be inserted into the
* destination that had the same key. Returns the destination passed in.
*/public <DextendsCollection<V>> DputAll(finalMap<K, V> map, finalDdestination)
{
for (Map.Entry<K, V> entry : map.entrySet())
{
Vprevious = put( entry.getKey(), entry.getValue() );
if ( previous != null && destination != null )
{
destination.add( previous );
}
}
returndestination;
}
/**
* Returns the value of the last added entry with the given key.
*/publicVget(finalKkey)
{
finalEntry<K, V> before = beforeKey( key );
return ( before == null ? null : before.next.value );
}
/**
* Adds all values that exist with the given key to the given destination
* and returns the reference to that destination.
*/public <DextendsCollection<V>> DgetAll(finalKkey, finalDdestination)
{
returnstripValues( entriesWithKey( key ), destination );
}
/**
* Returns the key of the first entry in the map with the given value.
*/publicKgetKey(finalVvalue)
{
finalEntry<K, V> before = beforeValue( value );
return ( before == null ? null : before.next.key );
}
/**
* Adds all keys that exist with the given value to the given destination
* and returns the reference to that destination.
*/public <DextendsCollection<K>> DgetAllKeys(finalVvalue, finalDdestination)
{
returnstripKeys( entriesWithValue( value ), destination );
}
/**
* Removes the last added entry from the map with the given key and
* returns the associated value.
*/publicVremove(finalKkey)
{
finalEntry<K, V> before = beforeKey( key );
if ( before == null )
{
returnnull;
}
finalEntry<K, V> removing = before.next;
finalVremovingValue = removing.value;
before.next = removing.next;
free( removing );
size--;
returnremovingValue;
}
/**
* Removes all entries with the given key.
*/publicvoidremoveAll(finalKkey)
{
removeAllFromIterator( entriesWithKey( key ) );
}
/**
* Removes all entries with the given keys.
*/publicvoidremoveAll(finalK ... keyArray)
{
for (Kkey : keyArray)
{
removeAllFromIterator( entriesWithKey( key ) );
}
}
/**
* Removes all entries with the given keys.
*/publicvoidremoveAll(finalIterable<K> keyIterable)
{
for (Kkey : keyIterable)
{
removeAllFromIterator( entriesWithKey( key ) );
}
}
/**
* Returns the number of entries with the given key.
*/publicintcountOf(finalKkey)
{
returncountIterator( entriesWithKey( key ) );
}
/**
* Removes the first entry found in the table with the given value and
* returns it's key.
*/publicKremoveValue(finalVvalue)
{
finalEntry<K, V> before = beforeValue( value );
if ( before == null )
{
returnnull;
}
finalEntry<K, V> removing = before.next;
finalKremovingKey = removing.key;
before.next = removing.next;
free( removing );
size--;
returnremovingKey;
}
/**
* Removes all entries with the given value.
*/publicvoidremoveAllValue(finalVvalue)
{
removeAllFromIterator( entriesWithValue( value ) );
}
/**
* Removes all entries with the given values.
*/publicvoidremoveAllValue(finalV ... valueyArray)
{
for (Vvalue : valueyArray)
{
removeAllFromIterator( entriesWithValue( value ) );
}
}
/**
* Removes all entries with the given values.
*/publicvoidremoveAllValue(finalIterable<V> valueIterable)
{
for (Vvalue : valueIterable)
{
removeAllFromIterator( entriesWithValue( value ) );
}
}
/**
* Returns the number of entries with the given key.
*/publicintcountOfValue(finalVvalue)
{
returncountIterator( entriesWithValue( value ) );
}
/**
* Returns whether the given key exists in the map at least once.
*/publicbooleanhas(finalKkey)
{
returnbeforeKey( key ) != null;
}
/**
* Returns whether the given value exists in the map at least once.
*/publicbooleanhasValue(finalVvalue)
{
returnbeforeValue( value ) != null;
}
/**
* Returns the entry directly before the key or null if the key doesn't
* exist in the map.
*/publicEntry<K, V> beforeKey(finalKkey)
{
finalinthash = hash( key );
finalinttableIndex = hash & mod;
finalEntry<K, V> ending = table[ (tableIndex + 1) & mod ];
Entry<K, V> before = table[ tableIndex ];
Entry<K, V> current = before.next;
while ( current != ending )
{
if ( current.hash == hash && (current.key == key || (key.equals( current.key ) ) ) )
{
returnbefore;
}
before = current;
current = current.next;
}
returnnull;
}
/**
* Returns the entry directly before the value or null if the value doesn't
* exist in the map.
*/publicEntry<K, V> beforeValue(finalVvalue)
{
finalEntry<K, V> ending = table[0];
Entry<K, V> before = ending;
Entry<K, V> current = before.next;
while (current != ending)
{
if ( current.value == value || value.equals( current.value ) )
{
returnbefore;
}
before = current;
current = current.next;
}
returnnull;
}
/**
* Hashes the given key. This can he overridden by subclasses to provide
* better hashes based on Key type.
*/publicinthash(finalKkey)
{
returnkey.hashCode();
}
/**
* Removes the first key from the map. If no entries exists then null is returned.
*/publicKremoveFirstKey()
{
finalEntry<K, V> removed = removeFirstEntry();
Kfirst = null;
if ( removed != null )
{
first = removed.key;
free( removed );
}
returnfirst;
}
/**
* Removes the first value from the map. If no entries exists then null is returned.
*/publicVremoveFirstValue()
{
finalEntry<K, V> removed = removeFirstEntry();
Vfirst = null;
if ( removed != null )
{
first = removed.value;
free( removed );
}
returnfirst;
}
/**
* Removes the first entry from the map. This entry must be freed if you
* have pooling initialized an expect it to perform properly. If no entries
* exist then null is returned.
* @see #free(Entry)
*/publicEntry<K, V> removeFirstEntry()
{
finalEntry<K, V> ending = table[0];
Entry<K, V> before = ending;
Entry<K, V> current = before.next;
while ( current != ending )
{
Entry<K, V> next = current.next;
if ( current.key != null )
{
before.next = next;
size--;
returncurrent;
}
before = current;
current = next;
}
returnnull;
}
/**
* An Iterable of all entries in the map.
*/publicIterable<Entry<K, V>> entries()
{
returnentries;
}
/**
* An Iterable of all entries in the map with the given key.
*/publicIterable<Entry<K, V>> entriesWithKey(finalKkey)
{
multiKey.reset( key );
returnmultiKey;
}
/**
* An Iterable of all entries in the map with the given value.
*/publicIterable<Entry<K, V>> entriesWithValue(finalVvalue)
{
multiValue.reset( value );
returnmultiValue;
}
/**
* An Iterable of all values in the map.
*/publicIterable<V> values()
{
returnvalues;
}
/**
* An Iterable of all keys in the map. Keys may be repeated if there are
* multiple entries in the map with the same key.
*/publicIterable<K> keys()
{
returnkeys;
}
/**
* Clears the map of all entries.
*
* @param freeEntries
* Whether the entries should be returned to the pool, or ignored.
*/publicvoidclear( finalbooleanfreeEntries )
{
if ( freeEntries )
{
Entry<K, V> entry = table[0].next;
while (entry != table[0])
{
Entry<K, V> next = entry.next;
if ( entry.key != null )
{
free( entry );
}
entry = next;
}
}
for ( inti = 0; i < capacity; i++ )
{
table[i].next = table[(i + 1) & mod];
}
size = 0;
}
/**
* The number of entries in the map.
*/publicintsize()
{
returnsize;
}
/**
* Whether the map is empty or not.
*/publicbooleanisEmpty()
{
return (size == 0);
}
/**
* Frees a removed Entry.
*
* @param entry
* The removed Entry to free.
*/publicvoidfree( finalEntry<K, V> entry )
{
entry.value = null;
entry.next = null;
entry.key = null;
freeEntry( entry );
}
/*
* UTILITY METHODS
*//**
* Removes all elements in the given Iterable.
*/publicstaticvoidremoveAllFromIterator( finalIterable<?> iterable )
{
finalIterator<?> iterator = iterable.iterator();
while (iterator.hasNext())
{
iterator.next();
iterator.remove();
}
}
/**
* Removes all elements in the given Iterable and adds them to the destination.
*/publicstatic <E, CextendsCollection<E>> CremoveAllFromIterator( finalIterable<E> iterable, finalCdestination )
{
finalIterator<E> iterator = iterable.iterator();
while (iterator.hasNext())
{
destination.add( iterator.next() );
iterator.remove();
}
returndestination;
}
/**
* Returns the number of elements in the Iterable.
*/publicstaticintcountIterator( finalIterable<?> iterable )
{
finalIterator<?> iterator = iterable.iterator();
intcount = 0;
while (iterator.hasNext())
{
iterator.next();
count++;
}
returncount;
}
/**
* Adds all values from the entries in the Iterable to the given
* destination collection.
*/publicstatic <K, V, DextendsCollection<V>> DstripValues( finalIterable<Entry<K, V>> entries, finalDdestination )
{
for ( Entry<K, V> entry : entries )
{
destination.add( entry.value );
}
returndestination;
}
/**
* Adds all keys from the entries in the Iterable to the given
* destination collection.
*/publicstatic <K, V, DextendsCollection<K>> DstripKeys( finalIterable<Entry<K, V>> entries, finalDdestination )
{
for ( Entry<K, V> entry : entries )
{
destination.add( entry.key );
}
returndestination;
}
/*
* ENTRY POOLING (optional)
*/privatestaticEntry[] pool = {};
privatestaticintpoolSize;
privatestatic <K, V> Entry<K, V> newEntry()
{
return (poolSize == 0 ? newEntry<K, V>() : pool[--poolSize] );
}
privatestaticvoidfreeEntry( finalEntryentry )
{
if (poolSize < pool.length)
{
pool[poolSize++] = entry;
}
}
/**
* Initializes the pool of entries to some maximum size. By default the
* pool has a size of zero so no entries are cached.
*/publicstaticvoidinitPool(finalintsize)
{
pool = Arrays.copyOf( pool, size );
}
/*
* ENTRY
*/publicstaticclassEntry<K, V>
{
publicinthash;
publicKkey;
publicVvalue;
publicEntry<K, V> next;
}
/*
* ITERABLES
*/privateabstractclassAbstractIterable<E> implementsIterable<E>, Iterator<E>
{
protectedEntry<K, V> prev0;
protectedEntry<K, V> curr0;
protectedEntry<K, V> prev1;
protectedEntry<K, V> curr1;
protectedEntry<K, V> end;
@OverridepublicfinalIterator<E> iterator()
{
end = end();
curr1 = (prev1 = findPrev( start() )).next;
returnthis;
}
@OverridepublicfinalbooleanhasNext()
{
return (curr1 != end);
}
@Overridepublicfinalvoidremove()
{
prev0.next = curr0.next;
free( curr0 );
}
publicfinalEntry<K, V> nextEntry()
{
prev0 = prev1;
curr0 = curr1;
curr1 = (prev1 = findPrev( curr1 )).next;
returncurr0;
}
protectedabstractEntry<K, V> findPrev( Entry<K, V> prev );
protectedabstractEntry<K, V> start();
protectedabstractEntry<K, V> end();
}
privateclassMultiKeyIterableextendsAbstractIterable<Entry<K, V>>
{
privateKkey;
privateinthash;
publicvoidreset(finalKkey)
{
this.key = key;
this.hash = hash( key );
}
@OverridepublicEntry<K, V> next()
{
returnnextEntry();
}
@OverrideprotectedEntry<K, V> findPrev(Entry<K, V> start)
{
Entry<K, V> next;
while (((next = start.next).hash != hash || !key.equals(next.key)) && next != end)
{
start = next;
}
returnstart;
}
@OverrideprotectedEntry<K, V> start()
{
returntable[ (hash & mod) ];
}
@OverrideprotectedEntry<K, V> end()
{
returntable[ ((hash & mod) + 1) & mod ];
}
}
privateclassMultiValueIterableextendsAbstractIterable<Entry<K, V>>
{
privateVvalue;
publicvoidreset(finalVvalue)
{
this.value = value;
}
@OverridepublicEntry<K, V> next()
{
returnnextEntry();
}
@OverrideprotectedEntry<K, V> findPrev(Entry<K, V> prev)
{
Entry<K, V> next;
while ( ((next = prev.next).value == null || !value.equals( next.value )) && next != end )
{
prev = next;
}
returnprev;
}
@OverrideprotectedEntry<K, V> start()
{
returntable[0];
}
@OverrideprotectedEntry<K, V> end()
{
returntable[0];
}
}
privateabstractclassCyclicIterable<E> extendsAbstractIterable<E>
{
@OverrideprotectedEntry<K, V> findPrev(Entry<K, V> prev)
{
Entry<K, V> next;
while ((next = prev.next).key == null && next != end )
{
prev = next;
}
returnprev;
}
@OverrideprotectedEntry<K, V> start()
{
returntable[0];
}
@OverrideprotectedEntry<K, V> end()
{
returntable[0];
}
}
privateclassEntryIterableextendsCyclicIterable<Entry<K, V>>
{
@OverridepublicEntry<K, V> next()
{
returnnextEntry();
}
}
privateclassValueIterableextendsCyclicIterable<V>
{
@OverridepublicVnext()
{
returnnextEntry().value;
}
}
privateclassKeyIterableextendsCyclicIterable<K>
{
@OverridepublicKnext()
{
returnnextEntry().key;
}
}
}
Special syntax:
To highlight a line (yellow background), prefix it with '@@'
To indicate that a line should be removed (red background), prefix it with '-'
To indicate that a line should be added (green background), prefix it with '+'
To post multiple snippets, seperate them by '~~~~'