com.carrotsearch.hppcrt.maps.FloatFloatOpenHashMap Maven / Gradle / Ivy
Show all versions of hppcrt Show documentation
package com.carrotsearch.hppcrt.maps;
import java.util.*;
import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.strategies.FloatHashingStrategy;
// If RH is defined, RobinHood Hashing is in effect
//If SA is defined, no allocated array is used but instead default sentinel values
/**
* A hash map of float
to float
, implemented using open
* addressing with linear probing for collision resolution.
*
*
* The internal buffers of this implementation ({@link #keys}, {@link #values},
* etc...) are always allocated to the nearest size that is a power of two. When
* the capacity exceeds the given load factor, the buffer size is doubled.
*
*
* See {@link ObjectObjectOpenHashMap} class for API similarities and differences against Java
* Collections.
*
*
*
*
Important note. The implementation uses power-of-two tables and linear
* probing, which may cause poor performance (many collisions) if hash values are
* not properly distributed.
* This implementation uses rehashing
* using {@link MurmurHash3}.
*
*
*
* @author This code is inspired by the collaboration and implementation in the fastutil project.
*
*
*/
@javax.annotation.Generated(date = "2014-10-25T20:54:09+0200", value = "HPPC-RT generated from: FloatFloatOpenHashMap.java")
public class FloatFloatOpenHashMap
implements FloatFloatMap, Cloneable
{
/**
* Minimum capacity for the map.
*/
public final static int MIN_CAPACITY = HashContainerUtils.MIN_CAPACITY;
/**
* Default capacity.
*/
public final static int DEFAULT_CAPACITY = HashContainerUtils.DEFAULT_CAPACITY;
/**
* Default load factor.
*/
public final static float DEFAULT_LOAD_FACTOR = HashContainerUtils.DEFAULT_LOAD_FACTOR;
protected float defaultValue = (0f);
/**
* Hash-indexed array holding all keys.
*
* Direct map iteration: iterate {keys[i], values[i]} for i in [0; keys.length[ where keys[i] != 0, then also
* {0, {@link #defaultKeyValue} } is in the map if {@link #allocatedDefaultKey} = true.
*
*
* Direct iteration warning:
* If the iteration goal is to fill another hash container, please iterate {@link #keys} in reverse to prevent performance losses.
* @see #values
*/
public float[] keys;
/**
* Hash-indexed array holding all values associated to the keys
* stored in {@link #keys}.
*
* @see #keys
*/
public float[] values;
/**
*True if key = 0 is in the map.
*/
public boolean allocatedDefaultKey = false;
/**
* if allocatedDefaultKey = true, contains the associated V to the key = 0
*/
public float defaultKeyValue;
/**
* Cached number of assigned slots in {@link #keys}.
*/
protected int assigned;
/**
* The load factor for this map (fraction of allocated slots
* before the buffers must be rehashed or reallocated).
*/
protected final float loadFactor;
/**
* Resize buffers when {@link #keys} hits this value.
*/
protected int resizeAt;
/**
* The most recent slot accessed in {@link #containsKey} (required for
* {@link #lget}).
*
* @see #containsKey
* @see #lget
*/
protected int lastSlot;
/**
* Creates a hash map with the default capacity of {@value #DEFAULT_CAPACITY},
* load factor of {@value #DEFAULT_LOAD_FACTOR}.
*
*
See class notes about hash distribution importance.
*/
public FloatFloatOpenHashMap()
{
this(FloatFloatOpenHashMap.DEFAULT_CAPACITY);
}
/**
* Creates a hash map with the given initial capacity, default load factor of
* {@value #DEFAULT_LOAD_FACTOR}.
*
* See class notes about hash distribution importance.
*
* @param initialCapacity Initial capacity (greater than zero and automatically
* rounded to the next power of two).
*/
public FloatFloatOpenHashMap(final int initialCapacity)
{
this(initialCapacity, FloatFloatOpenHashMap.DEFAULT_LOAD_FACTOR);
}
/**
* Creates a hash map with the given initial capacity,
* load factor.
*
* See class notes about hash distribution importance.
*
* @param initialCapacity Initial capacity (greater than zero and automatically
* rounded to the next power of two).
*
* @param loadFactor The load factor (greater than zero and smaller than 1).
*/
public FloatFloatOpenHashMap(final int initialCapacity, final float loadFactor)
{
assert loadFactor > 0 && loadFactor <= 1 : "Load factor must be between (0, 1].";
this.loadFactor = loadFactor;
//take into account of the load factor to garantee no reallocations before reaching initialCapacity.
int internalCapacity = (int) (initialCapacity / loadFactor) + FloatFloatOpenHashMap.MIN_CAPACITY;
//align on next power of two
internalCapacity = HashContainerUtils.roundCapacity(internalCapacity);
this.keys = new float [internalCapacity];
this.values = new float [internalCapacity];
//fill with "not allocated" value
//Take advantage of the rounding so that the resize occur a bit later than expected.
//allocate so that there is at least one slot that remains allocated = false
//this is compulsory to guarantee proper stop in searching loops
this.resizeAt = Math.max(3, (int) (internalCapacity * loadFactor)) - 2;
}
/**
* Create a hash map from all key-value pairs of another container.
*/
public FloatFloatOpenHashMap(final FloatFloatAssociativeContainer container)
{
this(container.size());
putAll(container);
}
/**
* {@inheritDoc}
*/
@Override
public float put(float key, float value)
{
if (((key) == (0f))) {
if (this.allocatedDefaultKey) {
float previousValue = this.defaultKeyValue;
this.defaultKeyValue = value;
return previousValue;
}
this.defaultKeyValue = value;
this.allocatedDefaultKey = true;
return this.defaultValue;
}
final int mask = this.keys.length - 1;
int slot = Internals.rehash(key) & mask;
final float[] keys = this.keys;
final float[] values = this.values;
while ((! ((keys[ slot]) == (0f))))
{
if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot])))
{
final float oldValue = values[slot];
values[slot] = value;
return oldValue;
}
slot = (slot + 1) & mask;
}
// Check if we need to grow. If so, reallocate new data, fill in the last element
// and rehash.
if (this.assigned == this.resizeAt)
{
expandAndPut(key, value, slot);
}
else
{
this.assigned++;
keys[slot] = key;
values[slot] = value;
}
return this.defaultValue;
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final FloatFloatAssociativeContainer container)
{
return putAll((Iterable extends FloatFloatCursor>) container);
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final Iterable extends FloatFloatCursor> iterable)
{
final int count = this.size();
for (final FloatFloatCursor c : iterable)
{
put(c.key, c.value);
}
return this.size() - count;
}
/**
* {@inheritDoc}
*/
@Override
public boolean putIfAbsent(final float key, final float value)
{
if (!containsKey(key))
{
put(key, value);
return true;
}
return false;
}
/**
* Trove-inspired API method. An equivalent
* of the following code:
*
* if (containsKey(key))
* {
* float v = (float) (lget() + additionValue);
* lset(v);
* return v;
* }
* else
* {
* put(key, putValue);
* return putValue;
* }
*
*
* @param key The key of the value to adjust.
* @param putValue The value to put if key
does not exist.
* @param additionValue The value to add to the existing value if key
exists.
* @return Returns the current value associated with key
(after changes).
*/
@Override
public float putOrAdd(float key, float putValue, float additionValue)
{
if (((key) == (0f))) {
if (this.allocatedDefaultKey) {
this.defaultKeyValue += additionValue;
return this.defaultKeyValue;
}
this.defaultKeyValue = putValue;
this.allocatedDefaultKey = true;
return putValue;
}
final int mask = keys.length - 1;
int slot = Internals.rehash(key) & mask;
final float[] keys = this.keys;
final float[] values = this.values;
float value = putValue;
while ((! ((keys[ slot]) == (0f))))
{
if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot])))
{
values[slot] += additionValue;
return values[slot];
}
slot = (slot + 1) & mask;
}
if (assigned == resizeAt) {
expandAndPut(key, value, slot);
} else {
assigned++;
keys[slot] = key;
values[slot] = value;
}
return putValue;
}
/**
* An equivalent of calling
*
* if (containsKey(key))
* {
* float v = (float) (lget() + additionValue);
* lset(v);
* return v;
* }
* else
* {
* put(key, additionValue);
* return additionValue;
* }
*
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if key
exists.
* @return Returns the current value associated with key
(after changes).
*/
@Override
public float addTo(float key, float additionValue)
{
return putOrAdd(key, additionValue, additionValue);
}
/**
* Expand the internal storage buffers (capacity) and rehash.
*/
private void expandAndPut(final float pendingKey, final float pendingValue, final int freeSlot)
{
assert this.assigned == this.resizeAt;
//default sentinel value is never in the keys[] array, so never trigger reallocs
assert !((pendingKey) == (0f));
// Try to allocate new buffers first. If we OOM, it'll be now without
// leaving the data structure in an inconsistent state.
final float[] oldKeys = this.keys;
final float[] oldValues = this.values;
allocateBuffers(HashContainerUtils.nextCapacity(this.keys.length));
// We have succeeded at allocating new data so insert the pending key/value at
// the free slot in the old arrays before rehashing.
this.lastSlot = -1;
this.assigned++;
//We don't care of the oldAllocated value, so long it means "allocated = true", since the whole set is rebuilt from scratch.
oldKeys[freeSlot] = pendingKey;
oldValues[freeSlot] = pendingValue;
//for inserts
final int mask = this.keys.length - 1;
float key = (0f);
float value = (0f);
int slot = -1;
final float[] keys = this.keys;
final float[] values = this.values;
//iterate all the old arrays to add in the newly allocated buffers
//It is important to iterate backwards to minimize the conflict chain length !
for (int i = oldKeys.length; --i >= 0;)
{
if ((! ((oldKeys[ i]) == (0f))))
{
key = oldKeys[i];
value = oldValues[i];
slot = Internals.rehash(key) & mask;
while ((! ((keys[ slot]) == (0f))))
{
slot = (slot + 1) & mask;
} //end while
keys[slot] = key;
values[slot] = value;
}
}
}
/**
* Allocate internal buffers for a given capacity.
*
* @param capacity New capacity (must be a power of two).
*/
private void allocateBuffers(final int capacity)
{
final float[] keys = new float [capacity];
final float[] values = new float [capacity];
this.keys = keys;
this.values = values;
//allocate so that there is at least one slot that remains allocated = false
//this is compulsory to guarantee proper stop in searching loops
this.resizeAt = Math.max(3, (int) (capacity * this.loadFactor)) - 2;
}
/**
* {@inheritDoc}
*/
@Override
public float remove(final float key)
{
if (((key) == (0f))) {
if (this.allocatedDefaultKey) {
float previousValue = this.defaultKeyValue;
this.allocatedDefaultKey = false;
return previousValue;
}
return this.defaultValue;
}
final int mask = this.keys.length - 1;
int slot = Internals.rehash(key) & mask;
final float[] keys = this.keys;
while ((! ((keys[ slot]) == (0f)))
)
{
if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot])))
{
final float value = this.values[slot];
this.assigned--;
shiftConflictingKeys(slot);
return value;
}
slot = (slot + 1) & mask;
} //end while true
return this.defaultValue;
}
/**
* Shift all the slot-conflicting keys allocated to (and including) slot
.
*/
protected void shiftConflictingKeys(int slotCurr)
{
// Copied nearly verbatim from fastutil's impl.
final int mask = this.keys.length - 1;
int slotPrev, slotOther;
final float[] keys = this.keys;
final float[] values = this.values;
while (true)
{
slotCurr = ((slotPrev = slotCurr) + 1) & mask;
while ((! ((keys[ slotCurr]) == (0f))))
{
slotOther = Internals.rehash(keys[slotCurr]) & mask;
if (slotPrev <= slotCurr)
{
// we're on the right of the original slot.
if (slotPrev >= slotOther || slotOther > slotCurr)
{
break;
}
}
else
{
// we've wrapped around.
if (slotPrev >= slotOther && slotOther > slotCurr)
{
break;
}
}
slotCurr = (slotCurr + 1) & mask;
}
if (!(! ((keys[ slotCurr]) == (0f))))
{
break;
}
// Shift key/value/allocated triplet.
keys[slotPrev] = keys[slotCurr];
values[slotPrev] = values[slotCurr];
}
//means not allocated
/* */
keys[slotPrev] = (0f);
/* */
/* */
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final FloatContainer container)
{
final int before = this.size();
for (final FloatCursor cursor : container)
{
remove(cursor.value);
}
return before - this.size();
}
/**
* {@inheritDoc}
* Important!
* If the predicate actually injects the removed keys in another hash container, you may experience performance losses.
*/
@Override
public int removeAll(final FloatPredicate predicate)
{
final int before = this.size();
if (this.allocatedDefaultKey) {
if (predicate.apply((0f)))
{
this.allocatedDefaultKey = false;
}
}
final float[] keys = this.keys;
for (int i = 0; i < keys.length;)
{
if ((! ((keys[ i]) == (0f))))
{
if (predicate.apply(keys[i]))
{
this.assigned--;
shiftConflictingKeys(i);
// Repeat the check for the same i.
continue;
}
}
i++;
}
return before - this.size();
}
/**
* {@inheritDoc}
*
*
Use the following snippet of code to check for key existence
* first and then retrieve the value if it exists.
*
* if (map.containsKey(key))
* value = map.lget();
*
*/
@Override
public float get(final float key)
{
if (((key) == (0f))) {
if (this.allocatedDefaultKey) {
return this.defaultKeyValue;
}
return this.defaultValue;
}
final int mask = this.keys.length - 1;
int slot = Internals.rehash(key) & mask;
final float[] keys = this.keys;
while ((! ((keys[ slot]) == (0f)))
)
{
if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot])))
{
return this.values[slot];
}
slot = (slot + 1) & mask;
} //end while true
return this.defaultValue;
}
/**
* Returns the last key stored in this has map for the corresponding
* most recent call to {@link #containsKey}.
* Precondition : {@link #containsKey} must have been called previously !
* Use the following snippet of code to check for key existence
* first and then retrieve the key value if it exists.
*
* if (map.containsKey(key))
* value = map.lkey();
*
*
* This is equivalent to calling:
*
* if (map.containsKey(key))
* key = map.keys[map.lslot()];
*
*/
public float lkey()
{
if (this.lastSlot == -2) {
return (0f);
}
assert this.lastSlot >= 0 : "Call containsKey() first.";
assert ! ((this.keys[lastSlot]) == (0f)) : "Last call to exists did not have any associated value.";
return this.keys[this.lastSlot];
}
/**
* Returns the last value saved in a call to {@link #containsKey}.
* Precondition : {@link #containsKey} must have been called previously !
* @see #containsKey
*/
public float lget()
{
if (this.lastSlot == -2) {
return this.defaultKeyValue;
}
assert this.lastSlot >= 0 : "Call containsKey() first.";
assert !((this.keys[lastSlot]) == (0f)) : "Last call to exists did not have any associated value.";
return this.values[this.lastSlot];
}
/**
* Sets the value corresponding to the key saved in the last
* call to {@link #containsKey}, if and only if the key exists
* in the map already.
* Precondition : {@link #containsKey} must have been called previously !
* @see #containsKey
* @return Returns the previous value stored under the given key.
*/
public float lset(final float value)
{
if (this.lastSlot == -2) {
float previous = this.defaultKeyValue;
this.defaultKeyValue = value;
return previous;
}
assert this.lastSlot >= 0 : "Call containsKey() first.";
assert ! ((this.keys[lastSlot]) == (0f)) : "Last call to exists did not have any associated value.";
final float previous = this.values[this.lastSlot];
this.values[this.lastSlot] = value;
return previous;
}
/**
* @return Returns the slot of the last key looked up in a call to {@link #containsKey} if
* it returned true
* * or else -2 if {@link #containsKey} were successful on key = 0
* * @see #containsKey
*/
public int lslot()
{
assert this.lastSlot >= 0 || this.lastSlot == -2 : "Call containsKey() first.";
return this.lastSlot;
}
/**
* {@inheritDoc}
*
* Saves the associated value for fast access using {@link #lget}
* or {@link #lset}.
*
* if (map.containsKey(key))
* value = map.lget();
*
* or, to modify the value at the given key without looking up
* its slot twice:
*
* if (map.containsKey(key))
* map.lset(map.lget() + 1);
*
* */
@Override
public boolean containsKey(final float key)
{
if (((key) == (0f))) {
if (this.allocatedDefaultKey) {
this.lastSlot = -2;
} else {
this.lastSlot = -1;
}
return this.allocatedDefaultKey;
}
final int mask = this.keys.length - 1;
int slot = Internals.rehash(key) & mask;
final float[] keys = this.keys;
while ((! ((keys[ slot]) == (0f)))
)
{
if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot])))
{
this.lastSlot = slot;
return true;
}
slot = (slot + 1) & mask;
} //end while true
//unsuccessful search
this.lastSlot = -1;
return false;
}
/**
* {@inheritDoc}
*
* Does not release internal buffers.
*/
@Override
public void clear()
{
this.assigned = 0;
this.lastSlot = -1;
// States are always cleared.
this.allocatedDefaultKey = false;
//Faster than Arrays.fill(keys, null); // Help the GC.
FloatArrays.blankArray(this.keys, 0, this.keys.length);
}
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.assigned + (this.allocatedDefaultKey?1:0) ;
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
return this.resizeAt - 1;
}
/**
* {@inheritDoc}
*
* Note that an empty container may still contain many deleted keys (that occupy buffer
* space). Adding even a single element to such a container may cause rehashing.
*/
@Override
public boolean isEmpty()
{
return size() == 0;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
int h = 0;
if (this.allocatedDefaultKey) {
h += Internals.rehash((0f)) + Internals.rehash(this.defaultKeyValue);
}
final float[] keys = this.keys;
final float[] values = this.values;
for (int i = keys.length; --i >= 0;)
{
if ((! ((keys[ i]) == (0f))))
{
//This hash is an intrinsic property of the container contents,
//consequently is independent from the HashStrategy, so do not use it !
h += Internals.rehash(keys[i]) + Internals.rehash(values[i]);
}
}
return h;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(final Object obj)
{
if (obj != null)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof FloatFloatOpenHashMap))
{
return false;
}
/* */
FloatFloatMap other = (FloatFloatMap) obj;
if (other.size() == this.size())
{
final EntryIterator it = this.iterator();
while (it.hasNext())
{
final FloatFloatCursor c = it.next();
if (other.containsKey(c.key))
{
final float v = other.get(c.key);
if ((Float.floatToIntBits(c.value) == Float.floatToIntBits(v)))
{
continue;
}
}
//recycle
it.release();
return false;
}
return true;
}
}
return false;
}
/**
* An iterator implementation for {@link #iterator}.
*/
public final class EntryIterator extends AbstractIterator
{
public final FloatFloatCursor cursor;
public EntryIterator()
{
this.cursor = new FloatFloatCursor();
this.cursor.index = -2;
}
/**
* Iterate backwards w.r.t the buffer, to
* minimize collision chains when filling another hash container (ex. with putAll())
*/
@Override
protected FloatFloatCursor fetch()
{
if (this.cursor.index == FloatFloatOpenHashMap.this.keys.length + 1) {
if (FloatFloatOpenHashMap.this.allocatedDefaultKey) {
this.cursor.index = FloatFloatOpenHashMap.this.keys.length;
this.cursor.key = (0f);
this.cursor.value = FloatFloatOpenHashMap.this.defaultKeyValue;
return this.cursor;
} else {
//no value associated with the default key, continue iteration...
this.cursor.index = FloatFloatOpenHashMap.this.keys.length;
}
}
int i = this.cursor.index - 1;
while (i >= 0 &&
!(! ((FloatFloatOpenHashMap.this.keys[ i]) == (0f))))
{
i--;
}
if (i == -1)
{
return done();
}
this.cursor.index = i;
this.cursor.key = FloatFloatOpenHashMap.this.keys[i];
this.cursor.value = FloatFloatOpenHashMap.this.values[i];
return this.cursor;
}
}
/**
* internal pool of EntryIterator
*/
protected final IteratorPool entryIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public EntryIterator create()
{
return new EntryIterator();
}
@Override
public void initialize(final EntryIterator obj)
{
obj.cursor.index = FloatFloatOpenHashMap.this.keys.length +1 ;
}
@Override
public void reset(final EntryIterator obj) {
// nothing
}
});
/**
* {@inheritDoc}
* @return
*/
@Override
public EntryIterator iterator()
{
//return new EntryIterator();
return this.entryIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T procedure)
{
if (this.allocatedDefaultKey) {
procedure.apply((0f), this.defaultKeyValue);
}
final float[] keys = this.keys;
final float[] values = this.values;
//Iterate in reverse for side-stepping the longest conflict chain
//in another hash, in case apply() is actually used to fill another hash container.
for (int i = keys.length - 1; i >= 0; i--)
{
if ((! ((keys[ i]) == (0f))))
{
procedure.apply(keys[i], values[i]);
}
}
return procedure;
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T predicate)
{
if (this.allocatedDefaultKey) {
if(! predicate.apply((0f), this.defaultKeyValue)) {
return predicate;
}
}
final float[] keys = this.keys;
final float[] values = this.values;
//Iterate in reverse for side-stepping the longest conflict chain
//in another hash, in case apply() is actually used to fill another hash container.
for (int i = keys.length - 1; i >= 0; i--)
{
if ((! ((keys[ i]) == (0f))))
{
if (!predicate.apply(keys[i], values[i]))
{
break;
}
}
} //end for
return predicate;
}
/**
* @return a new KeysContainer view of the keys of this associated container.
* This view then reflects all changes from the map.
*/
@Override
public KeysContainer keys()
{
return new KeysContainer();
}
/**
* A view of the keys inside this hash map.
*/
public final class KeysContainer
extends AbstractFloatCollection implements FloatLookupContainer
{
private final FloatFloatOpenHashMap owner =
FloatFloatOpenHashMap.this;
@Override
public boolean contains(final float e)
{
return containsKey(e);
}
@Override
public T forEach(final T procedure)
{
if (this.owner.allocatedDefaultKey) {
procedure.apply((0f));
}
final float[] keys = this.owner.keys;
//Iterate in reverse for side-stepping the longest conflict chain
//in another hash, in case apply() is actually used to fill another hash container.
for (int i = keys.length - 1; i >= 0; i--)
{
if ((! ((keys[ i]) == (0f))))
{
procedure.apply(keys[i]);
}
}
return procedure;
}
@Override
public T forEach(final T predicate)
{
if (this.owner.allocatedDefaultKey) {
if(! predicate.apply((0f))) {
return predicate;
}
}
final float[] keys = this.owner.keys;
//Iterate in reverse for side-stepping the longest conflict chain
//in another hash, in case apply() is actually used to fill another hash container.
for (int i = keys.length - 1; i >= 0; i--)
{
if ((! ((keys[ i]) == (0f))))
{
if (!predicate.apply(keys[i]))
{
break;
}
}
}
return predicate;
}
/**
* {@inheritDoc}
*/
@Override
public KeysIterator iterator()
{
//return new KeysIterator();
return this.keyIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.owner.size();
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
return this.owner.capacity();
}
@Override
public void clear()
{
this.owner.clear();
}
@Override
public int removeAll(final FloatPredicate predicate)
{
return this.owner.removeAll(predicate);
}
@Override
public int removeAllOccurrences(final float e)
{
final boolean hasKey = this.owner.containsKey(e);
int result = 0;
if (hasKey)
{
this.owner.remove(e);
result = 1;
}
return result;
}
/**
* internal pool of KeysIterator
*/
protected final IteratorPool keyIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public KeysIterator create()
{
return new KeysIterator();
}
@Override
public void initialize(final KeysIterator obj)
{
obj.cursor.index = FloatFloatOpenHashMap.this.keys.length +1 ;
}
@Override
public void reset(final KeysIterator obj) {
// nothing
}
});
@Override
public float[] toArray(final float[] target)
{
int count = 0;
if (this.owner.allocatedDefaultKey) {
target[count++] = (0f);
}
final float[] keys = this.owner.keys;
for (int i = 0; i < keys.length; i++)
{
if ((! ((keys[ i]) == (0f))))
{
target[count++] = keys[i];
}
}
assert count == this.owner.size();
return target;
}
};
/**
* An iterator over the set of keys.
*/
public final class KeysIterator extends AbstractIterator
{
public final FloatCursor cursor;
public KeysIterator()
{
this.cursor = new FloatCursor();
this.cursor.index = -2;
}
/**
* Iterate backwards w.r.t the buffer, to
* minimize collision chains when filling another hash container (ex. with putAll())
*/
@Override
protected FloatCursor fetch()
{
if (this.cursor.index == FloatFloatOpenHashMap.this.keys.length + 1) {
if (FloatFloatOpenHashMap.this.allocatedDefaultKey) {
this.cursor.index = FloatFloatOpenHashMap.this.keys.length;
this.cursor.value = (0f);
return this.cursor;
} else {
//no value associated with the default key, continue iteration...
this.cursor.index = FloatFloatOpenHashMap.this.keys.length;
}
}
int i = this.cursor.index - 1;
while (i >= 0 && !(! ((FloatFloatOpenHashMap.this.keys[ i]) == (0f))))
{
i--;
}
if (i == -1)
{
return done();
}
this.cursor.index = i;
this.cursor.value = FloatFloatOpenHashMap.this.keys[i];
return this.cursor;
}
}
/**
* @return a new ValuesContainer, view of the values of this map.
* This view then reflects all changes from the map.
*/
@Override
public ValuesContainer values()
{
return new ValuesContainer();
}
/**
* A view over the set of values of this map.
*/
public final class ValuesContainer extends AbstractFloatCollection
{
private final FloatFloatOpenHashMap owner =
FloatFloatOpenHashMap.this;
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.owner.size();
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
return this.owner.capacity();
}
@Override
public boolean contains(final float value)
{
if (this.owner.allocatedDefaultKey && (Float.floatToIntBits(value) == Float.floatToIntBits(this.owner.defaultKeyValue))) {
return true;
}
// This is a linear scan over the values, but it's in the contract, so be it.
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int slot = 0; slot < keys.length; slot++)
{
if ((! ((keys[ slot]) == (0f)))
&& (Float.floatToIntBits(value) == Float.floatToIntBits(values[slot])))
{
return true;
}
}
return false;
}
@Override
public T forEach(final T procedure)
{
if (this.owner.allocatedDefaultKey) {
procedure.apply(this.owner.defaultKeyValue);
}
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int slot = 0; slot < keys.length; slot++)
{
if ((! ((keys[ slot]) == (0f)))) {
procedure.apply(values[slot]);
}
}
return procedure;
}
@Override
public T forEach(final T predicate)
{
if (this.owner.allocatedDefaultKey) {
if (!predicate.apply(this.owner.defaultKeyValue))
{
return predicate;
}
}
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int slot = 0; slot < keys.length; slot++)
{
if ((! ((keys[ slot]) == (0f))))
{
if (!predicate.apply(values[slot]))
{
break;
}
}
}
return predicate;
}
@Override
public ValuesIterator iterator()
{
// return new ValuesIterator();
return this.valuesIteratorPool.borrow();
}
/**
* {@inheritDoc}
* Indeed removes all the (key,value) pairs matching
* (key ? , e) with the same e, from the map.
*/
@Override
public int removeAllOccurrences(final float e)
{
final int before = this.owner.size();
if (this.owner.allocatedDefaultKey) {
if((Float.floatToIntBits(e) == Float.floatToIntBits(this.owner.defaultKeyValue))) {
this.owner.allocatedDefaultKey = false;
}
}
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int slot = 0; slot < keys.length;)
{
if ((! ((keys[ slot]) == (0f))))
{
if ((Float.floatToIntBits(e) == Float.floatToIntBits(values[slot])))
{
this.owner.assigned--;
shiftConflictingKeys(slot);
// Repeat the check for the same i.
continue;
}
}
slot++;
}
return before - this.owner.size();
}
/**
* {@inheritDoc}
* Indeed removes all the (key,value) pairs matching
* the predicate for the values, from the map.
*/
@Override
public int removeAll(final FloatPredicate predicate)
{
final int before = this.owner.size();
if (this.owner.allocatedDefaultKey) {
if(predicate.apply(this.owner.defaultKeyValue)) {
this.owner.allocatedDefaultKey = false;
}
}
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int slot = 0; slot < keys.length;)
{
if ((! ((keys[ slot]) == (0f))))
{
if (predicate.apply(values[slot]))
{
this.owner.assigned--;
shiftConflictingKeys(slot);
// Repeat the check for the same i.
continue;
}
}
slot++;
}
return before - this.owner.size();
}
/**
* {@inheritDoc}
* Alias for clear() the whole map.
*/
@Override
public void clear()
{
this.owner.clear();
}
/**
* internal pool of ValuesIterator
*/
protected final IteratorPool valuesIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public ValuesIterator create()
{
return new ValuesIterator();
}
@Override
public void initialize(final ValuesIterator obj)
{
obj.cursor.index = FloatFloatOpenHashMap.this.keys.length +1 ;
}
@Override
public void reset(final ValuesIterator obj) {
// nothing
}
});
@Override
public float[] toArray(final float[] target)
{
int count = 0;
if (this.owner.allocatedDefaultKey) {
target[count++] = this.owner.defaultKeyValue;
}
final float[] keys = this.owner.keys;
final float[] values = this.owner.values;
for (int i = 0; i < values.length; i++)
{
if ((! ((keys[ i]) == (0f))))
{
target[count++] = values[i];
}
}
assert count == this.owner.size();
return target;
}
}
/**
* An iterator over the set of values.
*/
public final class ValuesIterator extends AbstractIterator
{
public final FloatCursor cursor;
public ValuesIterator()
{
this.cursor = new FloatCursor();
this.cursor.index = -2;
}
/**
* Iterate backwards w.r.t the buffer, to
* minimize collision chains when filling another hash container (ex. with putAll())
*/
@Override
protected FloatCursor fetch()
{
if (this.cursor.index == FloatFloatOpenHashMap.this.values.length + 1) {
if (FloatFloatOpenHashMap.this.allocatedDefaultKey) {
this.cursor.index = FloatFloatOpenHashMap.this.values.length;
this.cursor.value = FloatFloatOpenHashMap.this.defaultKeyValue;
return this.cursor;
} else {
//no value associated with the default key, continue iteration...
this.cursor.index = FloatFloatOpenHashMap.this.keys.length;
}
}
int i = this.cursor.index - 1;
while (i >= 0 &&
!(! ((FloatFloatOpenHashMap.this.keys[ i]) == (0f))))
{
i--;
}
if (i == -1)
{
return done();
}
this.cursor.index = i;
this.cursor.value = FloatFloatOpenHashMap.this.values[i];
return this.cursor;
}
}
/**
* Clone this object.
* */
@Override
public FloatFloatOpenHashMap clone()
{
final FloatFloatOpenHashMap cloned = new FloatFloatOpenHashMap(this.size(), this.loadFactor);
cloned.putAll(this);
cloned.defaultValue = this.defaultValue;
return cloned;
}
/**
* Convert the contents of this map to a human-friendly string.
*/
@Override
public String toString()
{
final StringBuilder buffer = new StringBuilder();
buffer.append("[");
boolean first = true;
for (final FloatFloatCursor cursor : this)
{
if (!first)
{
buffer.append(", ");
}
buffer.append(cursor.key);
buffer.append("=>");
buffer.append(cursor.value);
first = false;
}
buffer.append("]");
return buffer.toString();
}
/**
* Creates a hash map from two index-aligned arrays of key-value pairs.
*/
public static FloatFloatOpenHashMap from(final float[] keys, final float[] values)
{
if (keys.length != values.length)
{
throw new IllegalArgumentException("Arrays of keys and values must have an identical length.");
}
final FloatFloatOpenHashMap map = new FloatFloatOpenHashMap(keys.length);
for (int i = 0; i < keys.length; i++)
{
map.put(keys[i], values[i]);
}
return map;
}
/**
* Create a hash map from another associative container.
*/
public static FloatFloatOpenHashMap from(final FloatFloatAssociativeContainer container)
{
return new FloatFloatOpenHashMap(container);
}
/**
* Create a new hash map without providing the full generic signature (constructor
* shortcut).
*/
public static FloatFloatOpenHashMap newInstance()
{
return new FloatFloatOpenHashMap();
}
/**
* Create a new hash map with initial capacity and load factor control. (constructor
* shortcut).
*/
public static FloatFloatOpenHashMap newInstance(final int initialCapacity, final float loadFactor)
{
return new FloatFloatOpenHashMap(initialCapacity, loadFactor);
}
/**
* Returns the "default value" value used
* in containers methods returning "default value"
* @return
*/
public float getDefaultValue()
{
return this.defaultValue;
}
/**
* Set the "default value" value to be used
* in containers methods returning "default value"
* @return
*/
public void setDefaultValue(final float defaultValue)
{
this.defaultValue = defaultValue;
}
//Test for existence with default value sentinels
}