📄 fastmap.java
字号:
keyHash );
}
final Entry/*<K,V>*/entry = getEntry( key,
keyHash );
if ( entry == null ) {
addEntry( keyHash,
key,
value );
return null;
}
final Object/*V*/prevValue = entry._value;
entry._value = value;
return prevValue;
}
private synchronized Object/*V*/putShared(final Object/*K*/key,
final Object/*V*/value,
final int keyHash) {
final Entry/*<K,V>*/entry = getEntry( key,
keyHash );
if ( entry == null ) {
addEntry( keyHash,
key,
value );
return null;
}
final Object/*V*/prevValue = entry._value;
entry._value = value;
return prevValue;
}
/**
* Copies all of the mappings from the specified map to this map.
*
* @param map the mappings to be stored in this map.
* @throws NullPointerException the specified map is <code>null</code>,
* or the specified map contains <code>null</code> keys.
*/
public final void putAll(final Map/*<? extends K, ? extends V>*/map) {
if ( map instanceof FastMap ) { // Optimization.
final FastMap/*<? extends K, ? extends V>*/fm = (FastMap/*<? extends K, ? extends V>*/) map;
for ( Entry/*<? extends K, ? extends V>*/e = fm._head, end = fm._tail; (e = e._next) != end; ) {
put( e._key,
e._value );
}
} else {
for ( final Iterator i = map.entrySet().iterator(); i.hasNext(); ) {
final Map.Entry/*<? extends K, ? extends V>*/e = (Map.Entry/*<? extends K, ? extends V>*/) i.next();
put( e.getKey(),
e.getValue() );
}
}
}
/**
* Removes the entry for the specified key if present. The entry
* is recycled if the map is not marked as {@link #isShared shared};
* otherwise the entry is candidate for garbage collection.
*
* <p> Note: Shared maps in ImmortalMemory (e.g. static) should not remove
* their entries as it could cause a memory leak (ImmortalMemory
* is never garbage collected), instead they should set their
* entry values to <code>null</code>.</p>
*
* @param key the key whose mapping is to be removed from the map.
* @return previous value associated with specified key, or
* <code>null</code> if there was no mapping for key. A
* <code>null</code> return can also indicate that the map
* previously associated <code>null</code> with the specified key.
* @throws NullPointerException if the key is <code>null</code>.
*/
public final Object/*V*/remove(final Object key) {
if ( this._isShared ) {
return removeShared( key );
}
final Entry/*<K,V>*/entry = getEntry( key );
if ( entry != null ) {
final Object/*V*/prevValue = entry._value;
removeEntry( entry );
return prevValue;
}
return null;
}
private synchronized Object/*V*/removeShared(final Object key) {
final Entry/*<K,V>*/entry = getEntry( key );
if ( entry != null ) {
this._size--;
entry.detach();
return entry._value;
}
return null;
}
/**
* <p> Sets the shared status of this map (whether the map is thread-safe
* or not). Shared maps are typically used for lookup table (e.g. static
* instances in ImmortalMemory). They support concurrent access
* (e.g. iterations) without synchronization, the maps updates
* themselves are synchronized internally.</p>
* <p> Unlike <code>ConcurrentHashMap</code> access to a shared map never
* blocks. Retrieval reflects the map state not older than the last
* time the accessing thread has been synchronized (for multi-processors
* systems synchronizing ensures that the CPU internal cache is not
* stale).</p>
*
* @param isShared <code>true</code> if this map is shared and thread-safe;
* <code>false</code> otherwise.
* @return <code>this</code>
*/
public FastMap/*<K,V>*/setShared(final boolean isShared) {
this._isShared = isShared;
return this;
}
/**
* Indicates if this map supports concurrent operations without
* synchronization (default unshared).
*
* @return <code>true</code> if this map is thread-safe; <code>false</code>
* otherwise.
*/
public boolean isShared() {
return this._isShared;
}
/**
* Sets the key comparator for this fast map.
*
* @param keyComparator the key comparator.
* @return <code>this</code>
*/
public FastMap/*<K,V>*/setKeyComparator(final FastComparator keyComparator) {
this._keyComparator = keyComparator;
this._keyComp = (keyComparator instanceof FastComparator.Default) ? (FastComparator.REHASH_SYSTEM_HASHCODE ? FastComparator.REHASH : null) : (keyComparator instanceof FastComparator.Direct) ? null : keyComparator;
return this;
}
/**
* Returns the key comparator for this fast map.
*
* @return the key comparator.
*/
public FastComparator getKeyComparator() {
return this._keyComparator;
}
/**
* Sets the value comparator for this map.
*
* @param valueComparator the value comparator.
* @return <code>this</code>
*/
public FastMap/*<K,V>*/setValueComparator(final FastComparator valueComparator) {
this._values.setValueComparator( valueComparator );
return this;
}
/**
* Returns the value comparator for this fast map.
*
* @return the value comparator.
*/
public FastComparator getValueComparator() {
return this._values.getValueComparator();
}
/**
* Removes all map's entries. The entries are removed and recycled;
* unless this map is {@link #isShared shared} in which case the entries
* are candidate for garbage collection.
*
* <p> Note: Shared maps in ImmortalMemory (e.g. static) should not remove
* their entries as it could cause a memory leak (ImmortalMemory
* is never garbage collected), instead they should set their
* entry values to <code>null</code>.</p>
*/
public final void clear() {
if ( this._isShared ) {
clearShared();
return;
}
// Clears all keys, values and buckets linked lists.
for ( Entry/*<K,V>*/e = this._head, end = this._tail; (e = e._next) != end; ) {
e._key = null;
e._value = null;
final Entry/*<K,V>*/[][] table = e._table;
table[(e._keyHash >> FastMap.R0) & (table.length - 1)][e._keyHash & FastMap.M0] = null;
}
this._tail = this._head._next;
this._size = 0;
// Discards old entries.
this._oldEntries = null;
}
private synchronized void clearShared() {
for ( Entry/*<K,V>*/e = this._head, end = this._tail; (e = e._next) != end; ) {
final Entry/*<K,V>*/[][] table = e._table;
table[(e._keyHash >> FastMap.R0) & (table.length - 1)][e._keyHash & FastMap.M0] = null;
}
this._head._next = this._tail; // Does not modify current linked list.
this._tail._previous = this._head; //
this._oldEntries = null;
this._size = 0;
}
/**
* Compares the specified object with this map for equality.
* Returns <code>true</code> if the given object is also a map and the two
* maps represent the same mappings (regardless of collection iteration
* order).
*
* @param obj the object to be compared for equality with this map.
* @return <code>true</code> if the specified object is equal to this map;
* <code>false</code> otherwise.
*/
public boolean equals(final Object obj) {
if ( obj == this ) {
return true;
} else if ( obj instanceof Map ) {
final Map/*<?,?>*/that = (Map) obj;
if ( this.size() == that.size() ) {
final Set thatEntrySet = that.entrySet();
for ( Entry e = this._head, end = this._tail; (e = e._next) != end; ) {
if ( !thatEntrySet.contains( e ) ) {
return false;
}
}
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Returns the hash code value for this map.
*
* @return the hash code value for this map.
*/
public int hashCode() {
int code = 0;
for ( Entry e = this._head, end = this._tail; (e = e._next) != end; ) {
code += e.hashCode();
}
return code;
}
/**
* Returns the textual representation of this map.
*
* @return the textual representation of the entry set.
*/
public String toString() {
return this._entrySet.toString();
}
/**
* Prints the current statistics on this map.
* This method may help identify poorly defined hash functions.
* An average collision of less than <code>50%</code> is typically
* acceptable.
*
* @param out the stream to use for output (e.g. <code>System.out</code>)
*/
public void printStatistics(final PrintStream out) {
int maxOccupancy = 0;
int totalCollisions = 0;
int size = 0;
for ( int i = 0; i < this._entries.length; i++ ) {
for ( int j = 0; j < this._entries[i].length; j++ ) {
Entry entry = this._entries[i][j];
int occupancy = 0;
while ( entry != null ) {
occupancy++;
if ( occupancy > maxOccupancy ) {
maxOccupancy = occupancy;
}
if ( occupancy > 1 ) {
totalCollisions++;
}
entry = entry._beside;
size++;
}
}
}
final StringBuffer percentCollisions = new StringBuffer();
if ( size != 0 ) {
percentCollisions.append( (100 * totalCollisions) / size );
percentCollisions.append( '%' );
} else {
percentCollisions.append( "N/A" );
}
synchronized ( out ) {
out.print( "SIZE: " + size );
out.print( ", TABLE LENGTH: " + this._entries.length * this._entries[0].length );
out.print( ", AVG COLLISIONS: " + percentCollisions );
out.print( ", MAX SLOT OCCUPANCY: " + maxOccupancy );
out.print( ", KEY COMPARATOR: " + ((this._keyComp == null) ? FastComparator.DIRECT : this._keyComp) );
out.print( ", SHARED: " + this._isShared );
out.println();
if ( this._oldEntries != null ) {
out.print( " + " );
this._oldEntries.printStatistics( out );
}
}
}
/**
* Returns a {@link FastCollection} view of the values contained in this
* map. The collection is backed by the map, so changes to the
* map are reflected in the collection, and vice-versa. The collection
* supports element removal, which removes the corresponding mapping from
* this map, via the <code>Iterator.remove</code>,
* <code>Collection.remove</code>, <code>removeAll</code>,
* <code>retainAll</code> and <code>clear</code> operations.
* It does not support the <code>add</code> or <code>addAll</code>
* operations.
*
* @return a collection view of the values contained in this map
* (instance of {@link FastCollection}).
*/
public final Collection/*<V>*/values() {
return this._values;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -