All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.carrotsearch.hppcrt.maps.FloatObjectOpenHashMap Maven / Gradle / Ivy

Go to download

High Performance Primitive Collections Realtime (fork of HPPC of Carrotsearch) Fundamental data structures (maps, sets, lists, stacks, queues, heaps, sorts) generated for combinations of object and primitive types to conserve JVM memory and speed up execution. The Realtime fork intend of extending collections while tweaking and optimizations to remove any dynamic allocations at runtime, and low variance execution times.

There is a newer version: 0.7.5
Show newest version
package com.carrotsearch.hppcrt.maps;

import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.hash.*;

  
  
  
  
// If RH is defined, RobinHood Hashing is in effect :
  

/**
 * A hash map of float to VType, implemented using open
 * addressing with linear probing for collision resolution.
 * 
 * 

* The internal buffers of this implementation ({@link #keys}, {@link #values}), * 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 supports null values.

* * @author This code is inspired by the collaboration and implementation in the fastutil project. * * */ @javax.annotation.Generated(date = "2015-02-27T19:21:15+0100", value = "HPPC-RT generated from: FloatObjectOpenHashMap.java") public class FloatObjectOpenHashMap implements FloatObjectMap, 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 VType defaultValue = (null); /** * Hash-indexed array holding all keys. *

* Direct map iteration: iterate {keys[i], values[i]} for i in [0; keys.length[ where keys[i] != 0/null, then also * {0/null, {@link #allocatedDefaultKeyValue} } 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 VType[] values; /** *True if key = 0/null is in the map. */ public boolean allocatedDefaultKey = false; /** * if allocatedDefaultKey = true, contains the associated V to the key = 0/null */ public VType allocatedDefaultKeyValue; /** * 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 FloatObjectOpenHashMap() { this(FloatObjectOpenHashMap.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 FloatObjectOpenHashMap(final int initialCapacity) { this(initialCapacity, FloatObjectOpenHashMap.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 FloatObjectOpenHashMap(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) + FloatObjectOpenHashMap.MIN_CAPACITY; //align on next power of two internalCapacity = HashContainerUtils.roundCapacity(internalCapacity); this.keys = (new float[internalCapacity]); this.values = (Internals.newArray(internalCapacity)); //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 FloatObjectOpenHashMap(final FloatObjectAssociativeContainer container) { this(container.size()); putAll(container); } /** * {@inheritDoc} */ @Override public VType put(float key, VType value) { if (key == (0f)) { if (this.allocatedDefaultKey) { final VType previousValue = this.allocatedDefaultKeyValue; this.allocatedDefaultKeyValue = value; return previousValue; } this.allocatedDefaultKeyValue = value; this.allocatedDefaultKey = true; return this.defaultValue; } final int mask = this.keys.length - 1; final float[] keys = this.keys; final VType[] values = this.values; //copied straight from fastutil "fast-path" int slot; float curr; //1.1 The rehashed key slot is occupied... if ((curr = keys[slot = (PhiMix.hash(Float.floatToIntBits(key))) & mask]) != (0f)) { //1.2 the occupied place is indeed key, so only updates the value and nothing else. if ((Float.floatToIntBits(curr) == Float.floatToIntBits(key))) { final VType oldValue = this.values[slot]; values[slot] = value; return oldValue; } //1.3 key is colliding, manage below : } else if (this.assigned < this.resizeAt) { //1.4 key is not colliding, without resize, so insert, return defaultValue. keys[slot] = key; values[slot] = value; this.assigned++; return this.defaultValue; } //2. Slow path, find a place somewhere down there... while ((keys[slot] != (0f))) { if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot]))) { final VType 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 FloatObjectAssociativeContainer container) { return putAll((Iterable>) container); } /** * {@inheritDoc} */ @Override public int putAll(final Iterable> iterable) { final int count = this.size(); for (final FloatObjectCursor c : iterable) { put(c.key, c.value); } return this.size() - count; } /** * {@inheritDoc} */ @Override public boolean putIfAbsent(final float key, final VType value) { if (!containsKey(key)) { put(key, value); return true; } return false; } /** * Expand the internal storage buffers (capacity) and rehash. */ private void expandAndPut(final float pendingKey, final VType 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 VType[] 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++; oldKeys[freeSlot] = pendingKey; oldValues[freeSlot] = pendingValue; //for inserts final int mask = this.keys.length - 1; float key = (0f); VType value = (null); int slot = -1; final float[] keys = this.keys; final VType[] 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 = (PhiMix.hash(Float.floatToIntBits(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 VType[] values = (Internals.newArray(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 VType remove(final float key) { if (key == (0f)) { if (this.allocatedDefaultKey) { final VType previousValue = this.allocatedDefaultKeyValue; //help the GC this.allocatedDefaultKeyValue = (null); this.allocatedDefaultKey = false; return previousValue; } return this.defaultValue; } final int mask = this.keys.length - 1; final float[] keys = this.keys; final VType[] values = this.values; //copied straight from fastutil "fast-path" int slot; float curr; //1.1 The rehashed slot is free, nothing to remove, return default value if ((curr = keys[slot = (PhiMix.hash(Float.floatToIntBits(key))) & mask]) == (0f)) { return this.defaultValue; } //1.2) The rehashed entry is occupied by the key, remove it, return value if ((Float.floatToIntBits(curr) == Float.floatToIntBits(key))) { final VType value = values[slot]; this.assigned--; shiftConflictingKeys(slot); return value; } //2. Hash collision, search for the key along the path slot = (slot + 1) & mask; //2. Slow path here while ((keys[slot] != (0f)) ) { if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot]))) { final VType value = 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 VType[] values = this.values; while (true) { slotCurr = ((slotPrev = slotCurr) + 1) & mask; while ((keys[slotCurr] != (0f))) { slotOther = (PhiMix.hash(Float.floatToIntBits(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); /* */ values[slotPrev] = (null); /* */ } /** * {@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 VType get(final float key) { if (key == (0f)) { if (this.allocatedDefaultKey) { return this.allocatedDefaultKeyValue; } return this.defaultValue; } final int mask = this.keys.length - 1; final float[] keys = this.keys; final VType[] values = this.values; //copied straight from fastutil "fast-path" int slot; float curr; //1.1 The rehashed slot is free, nothing to get, return default value if ((curr = keys[slot = (PhiMix.hash(Float.floatToIntBits(key))) & mask]) == (0f)) { return this.defaultValue; } //1.2) The rehashed entry is occupied by the key, return value if ((Float.floatToIntBits(curr) == Float.floatToIntBits(key))) { return values[slot]; } //2. Hash collision, search for the key along the path slot = (slot + 1) & mask; while ((keys[slot] != (0f)) ) { if ((Float.floatToIntBits(key) == Float.floatToIntBits(keys[slot]))) { return 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[this.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 VType lget() { if (this.lastSlot == -2) { return this.allocatedDefaultKeyValue; } assert this.lastSlot >= 0 : "Call containsKey() first."; assert (this.keys[this.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 VType lset(final VType value) { if (this.lastSlot == -2) { final VType previous = this.allocatedDefaultKeyValue; this.allocatedDefaultKeyValue = value; return previous; } assert this.lastSlot >= 0 : "Call containsKey() first."; assert (this.keys[this.lastSlot] != (0f)) : "Last call to exists did not have any associated value."; final VType 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; final float[] keys = this.keys; //copied straight from fastutil "fast-path" int slot; float curr; //1.1 The rehashed slot is free, return false if ((curr = keys[slot = (PhiMix.hash(Float.floatToIntBits(key))) & mask]) == (0f)) { this.lastSlot = -1; return false; } //1.2) The rehashed entry is occupied by the key, return true if ((Float.floatToIntBits(curr) == Float.floatToIntBits(key))) { this.lastSlot = slot; return true; } //2. Hash collision, search for the key along the path slot = (slot + 1) & mask; 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; this.allocatedDefaultKey = false; //help the GC this.allocatedDefaultKeyValue = (null); //Faster than Arrays.fill(keys, null); // Help the GC. FloatArrays.blankArray(this.keys, 0, this.keys.length); //Faster than Arrays.fill(values, null); // Help the GC. ObjectArrays. blankArray(this.values, 0, this.values.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 += 0 + Internals.rehash(this.allocatedDefaultKeyValue); } final float[] keys = this.keys; final VType[] values = this.values; for (int i = keys.length; --i >= 0;) { if ((keys[i] != (0f))) { h += (PhiMix.hash(Float.floatToIntBits(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 FloatObjectOpenHashMap)) { return false; } /* */ @SuppressWarnings("unchecked") final/* */ FloatObjectMap other = (FloatObjectMap) obj; if (other.size() == this.size()) { final EntryIterator it = this.iterator(); while (it.hasNext()) { final FloatObjectCursor c = it.next(); if (other.containsKey(c.key)) { final VType v = other.get(c.key); if ((c.value == null ? v == null : c.value.equals(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 FloatObjectCursor cursor; public EntryIterator() { this.cursor = new FloatObjectCursor(); 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 FloatObjectCursor fetch() { if (this.cursor.index == FloatObjectOpenHashMap.this.keys.length + 1) { if (FloatObjectOpenHashMap.this.allocatedDefaultKey) { this.cursor.index = FloatObjectOpenHashMap.this.keys.length; this.cursor.key = (0f); this.cursor.value = FloatObjectOpenHashMap.this.allocatedDefaultKeyValue; return this.cursor; } //no value associated with the default key, continue iteration... this.cursor.index = FloatObjectOpenHashMap.this.keys.length; } int i = this.cursor.index - 1; while (i >= 0 && !(FloatObjectOpenHashMap.this.keys[i] != (0f))) { i--; } if (i == -1) { return done(); } this.cursor.index = i; this.cursor.key = FloatObjectOpenHashMap.this.keys[i]; this.cursor.value = FloatObjectOpenHashMap.this.values[i]; return this.cursor; } } /** * internal pool of EntryIterator */ protected final IteratorPool, EntryIterator> entryIteratorPool = new IteratorPool, EntryIterator>( new ObjectFactory() { @Override public EntryIterator create() { return new EntryIterator(); } @Override public void initialize(final EntryIterator obj) { obj.cursor.index = FloatObjectOpenHashMap.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.allocatedDefaultKeyValue); } final float[] keys = this.keys; final VType[] 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.allocatedDefaultKeyValue)) { return predicate; } } final float[] keys = this.keys; final VType[] 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 FloatObjectOpenHashMap owner = FloatObjectOpenHashMap.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 = FloatObjectOpenHashMap.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 == FloatObjectOpenHashMap.this.keys.length + 1) { if (FloatObjectOpenHashMap.this.allocatedDefaultKey) { this.cursor.index = FloatObjectOpenHashMap.this.keys.length; this.cursor.value = (0f); return this.cursor; } //no value associated with the default key, continue iteration... this.cursor.index = FloatObjectOpenHashMap.this.keys.length; } int i = this.cursor.index - 1; while (i >= 0 && !(FloatObjectOpenHashMap.this.keys[i] != (0f))) { i--; } if (i == -1) { return done(); } this.cursor.index = i; this.cursor.value = FloatObjectOpenHashMap.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 AbstractObjectCollection { private final FloatObjectOpenHashMap owner = FloatObjectOpenHashMap.this; /** * {@inheritDoc} */ @Override public int size() { return this.owner.size(); } /** * {@inheritDoc} */ @Override public int capacity() { return this.owner.capacity(); } @Override public boolean contains(final VType value) { if (this.owner.allocatedDefaultKey && (value == null ? this.owner.allocatedDefaultKeyValue == null : value.equals(this.owner.allocatedDefaultKeyValue))) { 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 VType[] values = this.owner.values; for (int slot = 0; slot < keys.length; slot++) { if ((keys[slot] != (0f)) && (value == null ? values[slot] == null : value.equals(values[slot]))) { return true; } } return false; } @Override public > T forEach(final T procedure) { if (this.owner.allocatedDefaultKey) { procedure.apply(this.owner.allocatedDefaultKeyValue); } final float[] keys = this.owner.keys; final VType[] 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.allocatedDefaultKeyValue)) { return predicate; } } final float[] keys = this.owner.keys; final VType[] 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 VType e) { final int before = this.owner.size(); if (this.owner.allocatedDefaultKey) { if ((e == null ? this.owner.allocatedDefaultKeyValue == null : e.equals(this.owner.allocatedDefaultKeyValue))) { this.owner.allocatedDefaultKey = false; } } final float[] keys = this.owner.keys; final VType[] values = this.owner.values; for (int slot = 0; slot < keys.length;) { if ((keys[slot] != (0f))) { if ((e == null ? values[slot] == null : e.equals(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 ObjectPredicate predicate) { final int before = this.owner.size(); if (this.owner.allocatedDefaultKey) { if (predicate.apply(this.owner.allocatedDefaultKeyValue)) { this.owner.allocatedDefaultKey = false; } } final float[] keys = this.owner.keys; final VType[] 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, ValuesIterator> valuesIteratorPool = new IteratorPool, ValuesIterator>( new ObjectFactory() { @Override public ValuesIterator create() { return new ValuesIterator(); } @Override public void initialize(final ValuesIterator obj) { obj.cursor.index = FloatObjectOpenHashMap.this.keys.length + 1; } @Override public void reset(final ValuesIterator obj) { // nothing } }); @Override public VType[] toArray(final VType[] target) { int count = 0; if (this.owner.allocatedDefaultKey) { target[count++] = this.owner.allocatedDefaultKeyValue; } final float[] keys = this.owner.keys; final VType[] 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 ObjectCursor cursor; public ValuesIterator() { this.cursor = new ObjectCursor(); 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 ObjectCursor fetch() { if (this.cursor.index == FloatObjectOpenHashMap.this.values.length + 1) { if (FloatObjectOpenHashMap.this.allocatedDefaultKey) { this.cursor.index = FloatObjectOpenHashMap.this.values.length; this.cursor.value = FloatObjectOpenHashMap.this.allocatedDefaultKeyValue; return this.cursor; } //no value associated with the default key, continue iteration... this.cursor.index = FloatObjectOpenHashMap.this.keys.length; } int i = this.cursor.index - 1; while (i >= 0 && !(FloatObjectOpenHashMap.this.keys[i] != (0f))) { i--; } if (i == -1) { return done(); } this.cursor.index = i; this.cursor.value = FloatObjectOpenHashMap.this.values[i]; return this.cursor; } } /** * Clone this object. * * The returned clone will use the same HashingStrategy strategy. * It also realizes a trim-to- this.size() in the process. * */ @Override public FloatObjectOpenHashMap clone() { final FloatObjectOpenHashMap cloned = new FloatObjectOpenHashMap(this.size(), this.loadFactor); cloned.putAll(this); cloned.allocatedDefaultKeyValue = this.allocatedDefaultKeyValue; cloned.allocatedDefaultKey = this.allocatedDefaultKey; 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 FloatObjectCursor 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 FloatObjectOpenHashMap from(final float[] keys, final VType[] values) { if (keys.length != values.length) { throw new IllegalArgumentException("Arrays of keys and values must have an identical length."); } final FloatObjectOpenHashMap map = new FloatObjectOpenHashMap(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 FloatObjectOpenHashMap from(final FloatObjectAssociativeContainer container) { return new FloatObjectOpenHashMap(container); } /** * Create a new hash map without providing the full generic signature (constructor * shortcut). */ public static FloatObjectOpenHashMap newInstance() { return new FloatObjectOpenHashMap(); } /** * Create a new hash map with initial capacity and load factor control. (constructor * shortcut). */ public static FloatObjectOpenHashMap newInstance(final int initialCapacity, final float loadFactor) { return new FloatObjectOpenHashMap(initialCapacity, loadFactor); } /** * Returns the "default value" value used * in containers methods returning "default value" * @return */ public VType getDefaultValue() { return this.defaultValue; } /** * Set the "default value" value to be used * in containers methods returning "default value" * @return */ public void setDefaultValue(final VType defaultValue) { this.defaultValue = defaultValue; } //Test for existence in template }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy