/**
*
*/
package net.varkhan.base.containers.map;
import net.varkhan.base.containers.Index;
import net.varkhan.base.containers.Indexable;
import net.varkhan.base.containers.Iterable;
import net.varkhan.base.containers.Iterator;
import net.varkhan.base.containers.type.*;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* @author varkhan
* @date May 28, 2009
* @time 9:43:13 PM
*/
public class BlockOpenHashIndexedLong2FloatMap implements IndexedLong2FloatMap, Serializable, Cloneable {
public static final long serialVersionUID=1L;
/**
* The list block size 2-logarithm
*/
protected final int blockshift;
/**
* The list block size ({@code 1 << blockshift})
*/
protected final int blocksize;
/**
* The list block mask ({@code blocksize - 1})
*/
protected final int blockmask;
/**
* The array of keys
*/
protected long[][] keys;
/**
* The array of values
*/
protected float[][] vals;
/**
* The array of occupancy flags
*/
protected byte[][] flgs;
/**
* The array of indexes
*/
protected long[][] idxs;
/**
* The acceptable load factor
*/
protected final float lfact;
/**
* The growth factor of the table
*/
protected final float gfact;
/**
* The total number of entries in the table
*/
protected long capa;
/**
* The mixing (secondary hashing) factor
*/
protected long mixr;
/**
* Number of entries in the map
*/
protected long size;
/**
* The maximum used index in the map, plus 1
*/
protected long head;
/**
* Number of free entries in the table (may be less than the {@link #capa} - {@link #size} because of deleted entries)
*/
protected long free;
/**
* Threshold after which we rehash. It must be the table size times {@link #lfact}
*/
protected long fill;
/**
* The default value to return on absent keys
*/
protected long defKey=0;
/**
* The default value to return on absent keys
*/
protected float defVal=0;
/**
* The hash strategy of this map
*/
protected LongHashingStrategy strategy;
/**
* Creates a new hash map.
*
* @param size the expected number of elements in the map
* @param blockshift the base-2 logarithm of the block size (such that the block size is {@code 1<<blockshift})
* @param loadfact the load factor (between 0 exclusive and 1 inclusive)
* @param growfact the growth factor (strictly greater than 1)
* @param strategy the hashing strategy
*/
public BlockOpenHashIndexedLong2FloatMap(long size, int blockshift, float loadfact, float growfact, final LongHashingStrategy strategy) {
// if(loadfact<=0 || loadfact>1) throw new IllegalArgumentException("Load factor must be between 0 exclusive and 1 inclusive");
// if(growfact<=1) throw new IllegalArgumentException("Growth factor must be strictly greater than 1");
// if(size<0) throw new IllegalArgumentException("Hash table size must be nonnegative");
if(blockshift<=3) blockshift=3;
if(loadfact>=1) loadfact=.75f;
if(growfact<=1) growfact=1.5f;
if(size<0) size=0;
this.blockshift=blockshift;
this.blocksize=(1<<blockshift);
this.blockmask=(1<<blockshift)-1;
this.strategy=strategy;
this.lfact=loadfact;
this.gfact=growfact;
this.capa=getCapa(size);
this.mixr=getMixr(this.capa, size);
this.fill=(long) (capa*loadfact);
this.free=this.capa;
this.size=0;
this.head=0;
int bnum=(int) (this.capa>>>this.blockshift)+1;
this.idxs=new long[bnum][];
this.flgs=new byte[bnum][];
this.keys=new long[bnum][];
this.vals=new float[bnum][];
}
/**
* Creates a new hash map.
*
* @param size the expected number of elements in the map
*/
public BlockOpenHashIndexedLong2FloatMap(long size) {
this(size, 10, .75f, 1.5f, LongHashingStrategy.DefaultHashingStrategy);
}
/**
* Creates a new hash map.
*/
public BlockOpenHashIndexedLong2FloatMap() {
this(11, 10, .75f, 1.5f, LongHashingStrategy.DefaultHashingStrategy);
}
/**********************************************************************************
** Global information accessors
**/
public long size() { return size; }
public boolean isEmpty() { return size==0; }
public long head() { return head; }
public void clear() {
if(free==capa) return;
free=capa;
size=0;
head=0;
for(int i=0;i<idxs.length;i++) idxs[i]=null;
for(int i=0;i<flgs.length;i++) flgs[i]=null;
for(int i=0;i<keys.length;i++) keys[i]=null;
for(int i=0;i<vals.length;i++) vals[i]=null;
}
public long getDefaultKey() { return defKey; }
public void setDefaultKey(long def) { defKey=def; }
public float getDefaultValue() { return defVal; }
public void setDefaultValue(float def) { defVal=def; }
/**********************************************************************************
** Map elements accessors
**/
private long _getIndex(long pos) {
int iblockpos=(int) (pos>>>this.blockshift);
int iblockoff=(int) (pos&this.blockmask);
long[] iblock=this.idxs[iblockpos];
// No block == EMPTY slots
return (iblock==null) ? 0 : iblock[iblockoff];
}
private void _setIndex(long pos, long index) {
int iblockpos=(int) (pos>>>this.blockshift);
int iblockoff=(int) (pos&this.blockmask);
long[] iblock=this.idxs[iblockpos];
if(iblock==null) this.idxs[iblockpos]=iblock=new long[this.blocksize];
iblock[iblockoff]=index;
}
private boolean _hasKey(long index) {
int fblockpos=(int) (index>>>this.blockshift);
int fblockoff=(int) (index&this.blockmask);
byte[] fblock=this.flgs[fblockpos];
return (fblock[fblockoff>>3]&(1<<(fblockoff&7)))!=0;
}
private long _getKey(long index) {
int kblockpos=(int) (index>>>this.blockshift);
int kblockoff=(int) (index&this.blockmask);
long[] kblock=this.keys[kblockpos];
// No block ??
return (kblock==null) ? defKey : kblock[kblockoff];
}
private float _getVal(long index) {
int kblockpos=(int) (index>>>this.blockshift);
int kblockoff=(int) (index&this.blockmask);
float[] vblock=this.vals[kblockpos];
// No block ??
return (vblock==null) ? defVal : vblock[kblockoff];
}
private void _setVal(long index, float v) {
int kblockpos=(int) (index>>>this.blockshift);
int kblockoff=(int) (index&this.blockmask);
float[] vblock=this.vals[kblockpos];
if(vblock==null) this.vals[kblockpos]=vblock=new float[this.blocksize];
vblock[kblockoff]=v;
}
private void _setEntry(long index, long k, float v) {
int kblockpos=(int) (index>>>this.blockshift);
int kblockoff=(int) (index&this.blockmask);
long[] kblock=this.keys[kblockpos];
float[] vblock=this.vals[kblockpos];
byte[] fblock=this.flgs[kblockpos];
if(kblock==null) this.keys[kblockpos]=kblock=new long[this.blocksize];
if(vblock==null) this.vals[kblockpos]=vblock=new float[this.blocksize];
if(fblock==null) this.flgs[kblockpos]=fblock=new byte[this.blocksize>>3];
kblock[kblockoff]=k;
vblock[kblockoff]=v;
fblock[kblockoff>>3]|=0x1<<(kblockoff&7);
}
private void _delEntry(long index) {
int kblockpos=(int) (index>>>this.blockshift);
int kblockoff=(int) (index&this.blockmask);
byte[] fblock=this.flgs[kblockpos];
if(fblock!=null) fblock[kblockoff>>3]&=~(0x1<<(kblockoff&7));
}
public boolean has(long index) {
if(index<0||index>=this.head) return false;
return _hasKey(index);
}
public long index(final Long key) {
if(key==null) return -1;
return index(key.longValue());
}
public long index(final long key) {
final long capa=this.capa;
final long mixr=this.mixr;
final long hash=this.strategy.hash(key);
// Get a positive integer for the hash
final long ph=hash&0x7FFFFFFFFFFFFFFFL;
// The slot position, starting at the primary hash
long slot=ph%capa;
// The signed lookup index in the key table
long sidx=_getIndex(slot);
// The key table value
long kval;
if(sidx<0||(sidx>0&&!(this.strategy.hash((kval=_getKey(sidx-1)))==hash&&this.strategy.equal(key, kval)))) {
// The scan increment
final long scan=(ph%mixr)+1;
do {
slot+=scan;
if(slot>=capa||slot<0) slot-=capa;
sidx=_getIndex(slot);
// There's always an EMPTY slot
}
while(sidx<0||(sidx>0&&!(this.strategy.hash((kval=_getKey(sidx-1)))==hash&&this.strategy.equal(key, kval))));
}
return sidx>0 ? sidx-1 : -1; // If OCCUPIED, necessarily, key_match(key, hash, kval).
}
public IndexedLong2FloatMap.Entry get(long index) {
if(index<0||index>=this.head) return null;
if(!_hasKey(index)) return null;
return new Entry(index, _getKey(index));
}
public Long getKey(long index) {
if(index<0||index>=this.head) return null;
if(!_hasKey(index)) return null;
return _getKey(index);
}
public long getLongKey(long index) {
if(index<0||index>=this.head) return defKey;
if(!_hasKey(index)) return defKey;
return _getKey(index);
}
public Float getValue(long index) {
if(index<0||index>=this.head) return null;
if(!_hasKey(index)) return null;
return _getVal(index);
}
public float getFloatValue(long index) {
if(index<0||index>=this.head) return defVal;
if(!_hasKey(index)) return defVal;
return _getVal(index);
}
public void setValue(long index, Float value) {
if(index<0||index>=this.head) return;
if(!_hasKey(index)) return;
if(value==null) _setVal(index, defVal);
else _setVal(index, value.floatValue());
}
public void setFloatValue(long index, float value) {
if(index<0||index>=this.head) return;
if(!_hasKey(index)) return;
_setVal(index, value);
}
public long add(IndexedMap.Entry<Long,Float> item) {
if(item==null) return -1;
return add(item.getKey(), item.getValue());
}
public long add(IndexedLong2ObjMap.Entry<Float> item) {
if(item==null) return -1;
if(item.getValue()==null) return add(item.getLongKey(), defVal);
else return add(item.getLongKey(), item.getValue().floatValue());
}
public long add(IndexedObj2FloatMap.Entry<Long> item) {
if(item==null||item.getKey()==null) return -1;
return add(item.getKey().longValue(), item.getFloatValue());
}
public long add(IndexedLong2FloatMap.Entry item) {
if(item==null) return -1;
return add(item.getLongKey(), item.getFloatValue());
}
public long add(final Long key, final Float val) {
if(key==null) return -1;
if(val==null) return add(key.longValue(), defVal);
return add(key.longValue(), val.floatValue());
}
public long add(final Long key, final float val) {
if(key==null) return -1;
return add(key.longValue(), val);
}
public long add(final long key, final Float val) {
if(val==null) return add(key, defVal);
return add(key, val.floatValue());
}
public long add(final long key, final float val) {
final long capa=this.capa;
final long mixr=this.mixr;
final long hash=this.strategy.hash(key);
// Get a positive integer for the hash
final long ph=hash&0x7FFFFFFFFFFFFFFFL;
// The slot position, starting at the primary hash
long slot=ph%capa;
// The signed lookup index in the key table
long sidx=_getIndex(slot);
// The key table value
long kval;
if(sidx>0&&!(hash==this.strategy.hash((kval=_getKey(sidx-1)))&&this.strategy.equal(key, kval))) {
// The scan increment
final long scan=(ph%mixr)+1;
do {
slot+=scan;
if(slot>=capa||slot<0) slot-=capa;
sidx=_getIndex(slot);
// There's always an EMPTY slot
} while(sidx>0&&!(hash==this.strategy.hash((kval=_getKey(sidx-1)))&&this.strategy.equal(key, kval)));
}
final long pos=slot; // Remember first available slot for later.
// Key found
if(sidx>0) {
sidx--;
_setVal(sidx, val);
return sidx; // If OCCUPIED, necessarily, key_match(key, hash, kval).
}
// If this slot is REMOVED, keep looking for the key until we find it or get to an empty slot
else if(sidx<0) {
long pidx=sidx;
// We are on a REMOVED spot, so we have to continue scanning
// The scan increment
final long scan=(ph%mixr)+1;
do {
slot+=scan;
if(slot>=capa||slot<0) slot-=capa;
pidx=_getIndex(slot);
// There's always an EMPTY slot
}
while(pidx<0||(pidx>0&&!(hash==this.strategy.hash((kval=_getKey(pidx-1)))&&this.strategy.equal(key, kval))));
if(pidx>0) return pidx-1; // If OCCUPIED, necessarily, key_match(key, hash, kval).
sidx=-sidx;
}
// If this slot is EMPTY, allocate an index and reserve a slot
else {
sidx=++this.head;
this.free--;
}
// Mark slot as OCCUPIED
_setIndex(pos, sidx--);
_setEntry(sidx, key, val);
if(++this.size>=this.fill)
rehash(getCapa((long) (this.size*this.gfact))); // Too many elements for the capacity, rehash at an increased capa
if(this.free==0)
rehash(capa); // Too many deletions, rehash at the same capa for cleanup
return sidx;
}
public void del(long index) {
if(index<0||index>=this.head) return;
if(!_hasKey(index)) return;
// We need to look up the key, to provide a starting point for the slot list
long key=_getKey(index);
final long capa=this.capa;
final long mixr=this.mixr;
final long hash=this.strategy.hash(key);
// Get a positive integer for the hash
final long ph=hash&0x7FFFFFFFFFFFFFFFL;
// The slot position, starting at the primary hash
long slot=ph%capa;
// The signed lookup index in the key table
long sidx=_getIndex(slot);
// The actual lookup index in the key table
long pidx=+index+1;
long nidx=-index-1;
// The key table value
// Object kval;
if(sidx!=0&&sidx!=pidx&&sidx!=nidx) {
// if ( sidx<0 || (sidx>0 && ! (hash == this.strategy.hash((Key)(kval=getKey(sidx-1))) && this.strategy.equal(key, (Key)kval))) ) {
// The scan increment
final long scan=(ph%mixr)+1;
do {
slot+=scan;
if(slot>=capa||slot<0) slot-=capa;
sidx=_getIndex(slot);
} while(sidx!=0&&sidx!=pidx&&sidx!=nidx);
// } while( sidx<0 || (sidx>0 && ! (hash == this.strategy.hash((Key)(kval=getKey(sidx-1))) && this.strategy.equal(key, (Key)kval))) );
// At this point, we have either an EMPTY slot, or an OCCUPIED or DELETED slot with the right index
}
// If EMPTY or DELETED, nothing to be done
if(sidx<=0) return;
// At this point we necessarily have an OCCUPIED slot, and sidx == index+1
_setIndex(slot, -(sidx--));
_delEntry(sidx);
this.size--;
}
/**
* Cleans-up the data in this map to make it more efficient.
* <p/>
* This method is generally useful to improve the map insertion and lookup
* speed after many element deletions, or when it will not be modified anymore.
*
* @return {@literal true} if the operation succeeded
*
* @see #trim(long)
* @see #pack()
*/
public boolean rehash() {
try { rehash(this.capa); }
catch(OutOfMemoryError cantDoIt) { return false; }
return true;
}
/**
* Reorganizes the data in this map to make it more compact.
* <p/>
* This method is generally useful to minimize the map's memory footprint
* after many element deletions, or when it will not be modified anymore.
*
* @return {@literal true} if the operation succeeded
*
* @see #trim(long)
* @see #rehash()
*/
public boolean pack() {
try { rehash(getCapa(this.size)); }
catch(OutOfMemoryError cantDoIt) { return false; }
return true;
}
/**
* Trims the map table to a given expected number of elements.
* <p/>
* This method is generally useful when reusing a map after clearing it,
* to avoid keeping in memory tables that are significantly smaller than
* required by the number of elements expected in the map.
*
* @param size the expected number of elements in the map
*
* @return {@literal true} if the operation succeeded
*
* @see #rehash()
* @see #pack()
*/
public boolean trim(long size) {
try { rehash(getCapa(size)); }
catch(OutOfMemoryError cantDoIt) { return false; }
return true;
}
/**
* Rehashes the map.
*
* @param capa the new table capacity
*/
protected void rehash(final long capa) {
long mixr=getMixr(capa, this.size);
long fill=(long) (capa*this.lfact);
long pos=0, s=this.size;
final long[][] idxs=new long[(int) (capa>>>this.blockshift)+1][];
long head=0;
while(s-->0) {
long idx;
while((idx=_getIndex(pos))<=0) pos++;
long key=_getKey(idx-1);
final long ph=this.strategy.hash(key)&0x7FFFFFFFFFFFFFFFL;
// The slot position, starting at the primary hash
long slot=ph%capa;
int iblockpos=(int) (slot>>>this.blockshift);
int iblockoff=(int) (slot&this.blockmask);
long[] iblock=idxs[iblockpos];
if(iblock!=null&&iblock[iblockoff]!=0) {
long scan=(ph%mixr)+1;
do {
slot+=scan;
if(slot>=capa||slot<0) slot-=capa;
iblockpos=(int) (slot>>>this.blockshift);
iblockoff=(int) (slot&this.blockmask);
iblock=idxs[iblockpos];
} while(iblock!=null&&iblock[iblockoff]!=0);
}
// idx is actually the index + 1
if(iblock==null) {
idxs[iblockpos]=iblock=new long[this.blocksize];
}
iblock[iblockoff]=idx;
if(head<idx) head=idx;
pos++;
}
// Increase the size of the keys if needed
if(head<capa&&this.capa<capa) {
int bnum=(int) (capa>>>this.blockshift)+1;
if(bnum>this.keys.length) {
final long[][] keys=new long[bnum][];
System.arraycopy(this.keys, 0, keys, 0, this.keys.length);
this.keys=keys;
final float[][] vals=new float[bnum][];
System.arraycopy(this.vals, 0, vals, 0, this.vals.length);
this.vals=vals;
final byte[][] flgs=new byte[bnum][];
System.arraycopy(this.flgs, 0, flgs, 0, this.flgs.length);
this.flgs=flgs;
}
}
// Decrease the size of the keys if possible
else if(head<=capa&&capa<this.capa) {
int bnum=(int) (((head<capa) ? capa : head)>>>this.blockshift)+1;
if(bnum<this.keys.length) {
final long[][] keys=new long[bnum][];
System.arraycopy(this.keys, 0, keys, 0, bnum);
this.keys=keys;
final float[][] vals=new float[bnum][];
System.arraycopy(this.vals, 0, vals, 0, bnum);
this.vals=vals;
final byte[][] flgs=new byte[bnum][];
System.arraycopy(this.flgs, 0, flgs, 0, bnum);
this.flgs=flgs;
}
}
this.capa=capa;
this.mixr=mixr;
this.free=this.capa-this.size;
this.fill=fill;
this.head=head;
this.idxs=idxs;
}
protected long getCapa(long size) {
if(size<this.size) size=this.size;
long capa=(long) (size/this.lfact)+1;
int min=0;
int max=PRIMES.length-1;
while(min<=max) {
int mid=(min+max)>>1;
long val=PRIMES[mid];
if(val<capa) min=mid+1;
else if(val>capa) max=mid-1;
else return val;
}
if(min>=PRIMES.length) return PRIMES[PRIMES.length-1];
return PRIMES[min];
}
protected long getMixr(long capa, long size) {
return capa-2;
}
protected static final long PRIMES[]={ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 13, 13, 13, 13, 13, 13, 13, 13, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 31, 31, 31, 31, 31, 31, 31, 43, 43, 43, 43, 43,
43, 43, 43, 61, 61, 61, 61, 61, 73, 73, 73, 73, 73, 73, 73, 103, 103, 109,
109, 109, 109, 109, 139, 139, 151, 151, 151, 151, 181, 181, 193, 199, 199,
199, 229, 241, 241, 241, 271, 283, 283, 313, 313, 313, 349, 349, 349, 349,
421, 433, 463, 463, 463, 523, 523, 571, 601, 619, 661, 661, 661, 661, 661,
823, 859, 883, 883, 883, 1021, 1063, 1093, 1153, 1153, 1231, 1321, 1321,
1429, 1489, 1489, 1621, 1699, 1789, 1873, 1951, 2029, 2131, 2143, 2311,
2383, 2383, 2593, 2731, 2803, 3001, 3121, 3259, 3391, 3583, 3673, 3919,
4093, 4273, 4423, 4651, 4801, 5023, 5281, 5521, 5743, 5881, 6301, 6571,
6871, 7129, 7489, 7759, 8089, 8539, 8863, 9283, 9721, 10141, 10531, 11071,
11551, 12073, 12613, 13009, 13759, 14323, 14869, 15649, 16363, 17029,
17839, 18541, 19471, 20233, 21193, 22159, 23059, 24181, 25171, 26263,
27541, 28753, 30013, 31321, 32719, 34213, 35731, 37309, 38923, 40639,
42463, 44281, 46309, 48313, 50461, 52711, 55051, 57529, 60091, 62299,
65521, 68281, 71413, 74611, 77713, 81373, 84979, 88663, 92671, 96739,
100801, 105529, 109849, 115021, 120079, 125509, 131011, 136861, 142873,
149251, 155863, 162751, 169891, 177433, 185071, 193381, 202129, 211063,
220021, 229981, 240349, 250969, 262111, 273643, 285841, 298411, 311713,
325543, 339841, 355009, 370663, 386989, 404269, 422113, 440809, 460081,
480463, 501829, 524221, 547399, 571603, 596929, 623353, 651019, 679909,
709741, 741343, 774133, 808441, 844201, 881539, 920743, 961531, 1004119,
1048573, 1094923, 1143283, 1193911, 1246963, 1302181, 1359733, 1420039,
1482853, 1548541, 1616899, 1688413, 1763431, 1841293, 1922773, 2008081,
2097133, 2189989, 2286883, 2388163, 2493853, 2604013, 2719669, 2840041,
2965603, 3097123, 3234241, 3377191, 3526933, 3682363, 3845983, 4016041,
4193803, 4379719, 4573873, 4776223, 4987891, 5208523, 5439223, 5680153,
5931313, 6194191, 6468463, 6754879, 7053331, 7366069, 7692343, 8032639,
8388451, 8759953, 9147661, 9552733, 9975193, 10417291, 10878619, 11360203,
11863153, 12387841, 12936529, 13509343, 14107801, 14732413, 15384673,
16065559, 16777141, 17519893, 18295633, 19105483, 19951231, 20834689,
21757291, 22720591, 23726449, 24776953, 25873963, 27018853, 28215619,
29464579, 30769093, 32131711, 33554011, 35039911, 36591211, 38211163,
39903121, 41669479, 43514521, 45441199, 47452879, 49553941, 51747991,
54039079, 56431513, 58930021, 61539091, 64263571, 67108669, 70079959,
73182409, 76422793, 79806229, 83339383, 87029053, 90881083, 94906249,
99108043, 103495879, 108077731, 112863013, 117860053, 123078019, 128526943,
134217439, 140159911, 146365159, 152845393, 159612601, 166679173,
174058849, 181765093, 189812341, 198216103, 206991601, 216156043,
225726379, 235720159, 246156271, 257054491, 268435009, 280319203,
292730833, 305691181, 319225021, 333358513, 348117151, 363529759,
379624279, 396432481, 413983771, 432312511, 451452613, 471440161,
492312523, 514109251, 536870839, 560640001, 585461743, 611382451,
638450569, 666717199, 696235363, 727060069, 759249643, 792864871,
827967631, 864625033, 902905501, 942880663, 984625531, 1028218189,
1073741719, 1121280091, 1170923713, 1222764841, 1276901371, 1333434301,
1392470281, 1454120779, 1518500173, 1585729993, 1655935399, 1729249999,
1805811253, 1885761133, 1969251079, 2056437379, 2147482951 };
/**********************************************************************************
** Map elements iterators
**/
/**
* The base Entry object for this map
*/
private class Entry implements IndexedLong2FloatMap.Entry {
private final long idx;
private final long key;
public Entry(long idx, long key) {
this.idx=idx;
this.key=key;
}
public long index() { return idx; }
public Long getKey() { return key; }
public long getLongKey() { return key; }
public Float getValue() { return _getVal(idx); }
public float getFloatValue() { return _getVal(idx); }
public Float setValue(Float val) {
if(val==null) return null;
float old=_getVal(idx);
_setVal(idx, val.floatValue());
return old;
}
public float setFloatValue(float val) {
float old=_getVal(idx);
_setVal(idx, val);
return old;
}
}
/**
* Returns an {@link Index} over the indexes in the map.
*
* @return an {@code Index} enumerating all indexes in the map
*/
public Index indexes() {
return new Index() {
long curr=-1;
/** The position of the next entry to be returned. */
long next=-1;
/** The position of the last entry that has been returned. */
long last=-1;
/** A downward counter measuring how many entries have been returned. */
long c=BlockOpenHashIndexedLong2FloatMap.this.size;
public long current() {
long idx;
if(curr==-1||(idx=_getIndex(curr))<=0) throw new IllegalStateException();
return idx-1;
}
public boolean hasNext() {
if(c==0) return false;
if(next==-1) {
next=curr+1;
while(next<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(next)<=0) next++;
}
return next<BlockOpenHashIndexedLong2FloatMap.this.capa;
}
public long next() {
last=curr;
if(!hasNext()) throw new NoSuchElementException();
curr=next;
next=-1;
c--;
return _getIndex(curr)-1;
}
public boolean hasPrevious() {
if(c==BlockOpenHashIndexedLong2FloatMap.this.size) return false;
if(last==-1) {
last=curr-1;
while(last>=0&&_getIndex(last)<=0) last--;
}
return last>=0;
}
public long previous() {
next=curr;
if(!hasPrevious()) throw new NoSuchElementException();
curr=last;
last=-1;
c++;
return _getIndex(curr)-1;
}
};
}
/**
* Iterates over all indexes in the map.
*
* @return an iterable over all the indexes that designate elements in the map
*/
public java.lang.Iterable<Long> iterateIndexes() {
return new java.lang.Iterable<Long>() {
public java.util.Iterator<Long> iterator() {
return new java.util.Iterator<Long>() {
/** The position of the next entry to be returned. */
long pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
/** A downward counter measuring how many entries have been returned. */
long c=size;
{
if(c!=0) while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0) pos++;
}
public boolean hasNext() {
return c!=0&&pos<BlockOpenHashIndexedLong2FloatMap.this.capa;
}
public Long next() {
if(!hasNext()) throw new NoSuchElementException();
long idx=_getIndex(last=pos)-1;
if(--c!=0) do pos++; while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0);
return idx;
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public Iterator<IndexedLong2FloatMap.Entry> iterator() {
return new Iterator<IndexedLong2FloatMap.Entry>() {
/** The position of the next entry to be returned. */
long pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
/** A downward counter measuring how many entries have been returned. */
long c=size;
{
if(c!=0) while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0) pos++;
}
public boolean hasNext() {
return c!=0&&pos<BlockOpenHashIndexedLong2FloatMap.this.capa;
}
public IndexedLong2FloatMap.Entry next() {
if(!hasNext()) throw new NoSuchElementException();
long idx=_getIndex(last=pos)-1;
if(--c!=0) do pos++; while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0);
return new Entry(idx, _getKey(idx));
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
public <Par> long visit(Visitor<IndexedMap.Entry<Long,Float>,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(new Entry(idx, _getKey(idx)), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedVisitor<IndexedMap.Entry<Long,Float>,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, new Entry(idx, _getKey(idx)), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedMapVisitor<Long,Float,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, _getKey(idx), _getVal(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public Iterable<IndexedLong2FloatMap.Entry> iterate(final long[] indexes) {
return new Iterable<IndexedLong2FloatMap.Entry>() {
public Iterator<IndexedLong2FloatMap.Entry> iterator() {
return new Iterator<IndexedLong2FloatMap.Entry>() {
/** The position of the next index */
int pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() {
return pos<indexes.length;
}
public IndexedLong2FloatMap.Entry next() {
if(pos>=indexes.length) throw new NoSuchElementException();
long idx=_getIndex(last=indexes[pos++])-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return new Entry(idx, _getKey(idx));
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public Iterable<IndexedLong2FloatMap.Entry> iterate(final java.lang.Iterable<Long> indexes) {
return new Iterable<IndexedLong2FloatMap.Entry>() {
public Iterator<IndexedLong2FloatMap.Entry> iterator() {
return new Iterator<IndexedLong2FloatMap.Entry>() {
/** An iterator over indexes */
final java.util.Iterator<Long> iter=indexes.iterator();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public IndexedLong2FloatMap.Entry next() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return new Entry(idx, _getKey(idx));
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public Iterable<IndexedLong2FloatMap.Entry> iterate(final Indexable indexes) {
return new Iterable<IndexedLong2FloatMap.Entry>() {
public Iterator<IndexedLong2FloatMap.Entry> iterator() {
return new Iterator<IndexedLong2FloatMap.Entry>() {
/** An iterator over indexes */
final Index iter=indexes.indexes();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public IndexedLong2FloatMap.Entry next() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return new Entry(idx, _getKey(idx));
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public IndexedLongContainer keys() {
return new IndexedLongContainer() {
public long size() { return BlockOpenHashIndexedLong2FloatMap.this.size(); }
public boolean isEmpty() { return BlockOpenHashIndexedLong2FloatMap.this.isEmpty(); }
public long head() { return BlockOpenHashIndexedLong2FloatMap.this.head(); }
public long getDefaultValue() { return BlockOpenHashIndexedLong2FloatMap.this.getDefaultKey(); }
public boolean has(long index) { return BlockOpenHashIndexedLong2FloatMap.this.has(index); }
public Long get(long index) { return BlockOpenHashIndexedLong2FloatMap.this.getKey(index); }
public long getLong(long index) { return BlockOpenHashIndexedLong2FloatMap.this.getLongKey(index); }
public Index indexes() { return BlockOpenHashIndexedLong2FloatMap.this.indexes(); }
public java.lang.Iterable<Long> iterateIndexes() { return BlockOpenHashIndexedLong2FloatMap.this.iterateIndexes(); }
public LongIterator iterator() {
return new LongIterator() {
/** The position of the next entry to be returned. */
long pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
/** A downward counter measuring how many entries have been returned. */
long c=size;
{
if(c!=0) while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0) pos++;
}
public boolean hasNext() {
return c!=0&&pos<BlockOpenHashIndexedLong2FloatMap.this.capa;
}
public Long next() { return nextValue(); }
public long nextValue() {
if(!hasNext()) throw new NoSuchElementException();
long idx=_getIndex(last=pos)-1;
if(--c!=0) do pos++; while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0);
return _getKey(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
public <Par> long visit(Visitor<Long,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(_getKey(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(LongVisitor<Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(_getKey(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedVisitor<Long,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, _getKey(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedLongVisitor<Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, _getKey(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public LongIterable iterate(final long[] indexes) {
return new LongIterable() {
public LongIterator iterator() {
return new LongIterator() {
/** The position of the next index */
int pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() {
return pos<indexes.length;
}
public Long next() { return nextValue(); }
public long nextValue() {
if(pos>=indexes.length) throw new NoSuchElementException();
long idx=_getIndex(last=indexes[pos++])-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getKey(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public LongIterable iterate(final java.lang.Iterable<Long> indexes) {
return new LongIterable() {
public LongIterator iterator() {
return new LongIterator() {
/** An iterator over indexes */
final java.util.Iterator<Long> iter=indexes.iterator();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public Long next() { return nextValue(); }
public long nextValue() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getKey(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public LongIterable iterate(final Indexable indexes) {
return new LongIterable() {
public LongIterator iterator() {
return new LongIterator() {
/** An iterator over indexes */
final Index iter=indexes.indexes();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public Long next() { return nextValue(); }
public long nextValue() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getKey(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
};
}
public IndexedFloatContainer values() {
return new IndexedFloatContainer() {
public long size() { return BlockOpenHashIndexedLong2FloatMap.this.size(); }
public boolean isEmpty() { return BlockOpenHashIndexedLong2FloatMap.this.isEmpty(); }
public long head() { return BlockOpenHashIndexedLong2FloatMap.this.head(); }
public float getDefaultValue() { return BlockOpenHashIndexedLong2FloatMap.this.getDefaultValue(); }
public boolean has(long index) { return BlockOpenHashIndexedLong2FloatMap.this.has(index); }
public Float get(long index) { return BlockOpenHashIndexedLong2FloatMap.this.getValue(index); }
public float getFloat(long index) { return BlockOpenHashIndexedLong2FloatMap.this.getFloatValue(index); }
public Index indexes() { return BlockOpenHashIndexedLong2FloatMap.this.indexes(); }
public java.lang.Iterable<Long> iterateIndexes() { return BlockOpenHashIndexedLong2FloatMap.this.iterateIndexes(); }
public FloatIterable.FloatIterator iterator() {
return new FloatIterable.FloatIterator() {
/** The position of the next entry to be returned. */
long pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
/** A downward counter measuring how many entries have been returned. */
long c=size;
{
if(c!=0) while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0) pos++;
}
public boolean hasNext() {
return c!=0&&pos<BlockOpenHashIndexedLong2FloatMap.this.capa;
}
public Float next() { return nextValue(); }
public float nextValue() {
if(!hasNext()) throw new NoSuchElementException();
long idx=_getIndex(last=pos)-1;
if(--c!=0) do pos++; while(pos<BlockOpenHashIndexedLong2FloatMap.this.capa&&_getIndex(pos)<=0);
return _getVal(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
public <Par> long visit(Visitor<Float,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(_getVal(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(FloatVisitor<Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(_getVal(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedVisitor<Float,Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, _getVal(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public <Par> long visit(IndexedFloatVisitor<Par> vis, Par par) {
long c=0;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long r=vis.invoke(idx, _getVal(idx), par);
if(r<0) return c;
c+=r;
pos++;
}
return c;
}
public FloatIterable iterate(final long[] indexes) {
return new FloatIterable() {
public FloatIterator iterator() {
return new FloatIterator() {
/** The position of the next index */
int pos=0;
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() {
return pos<indexes.length;
}
public Float next() { return nextValue(); }
public float nextValue() {
if(pos>=indexes.length) throw new NoSuchElementException();
long idx=_getIndex(last=indexes[pos++])-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getVal(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public FloatIterable iterate(final java.lang.Iterable<Long> indexes) {
return new FloatIterable() {
public FloatIterator iterator() {
return new FloatIterator() {
/** An iterator over indexes */
final java.util.Iterator<Long> iter=indexes.iterator();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public Float next() { return nextValue(); }
public float nextValue() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getVal(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
public FloatIterable iterate(final Indexable indexes) {
return new FloatIterable() {
public FloatIterator iterator() {
return new FloatIterator() {
/** An iterator over indexes */
final Index iter=indexes.indexes();
/** The position of the last entry that has been returned. */
long last=-1;
public boolean hasNext() { return iter.hasNext(); }
public Float next() { return nextValue(); }
public float nextValue() {
long idx=_getIndex(last=iter.next())-1;
if(!_hasKey(idx)) throw new NoSuchElementException();
return _getVal(idx);
}
public void remove() {
long idx;
if(last==-1||(idx=_getIndex(last))<=0) throw new IllegalStateException();
_setIndex(last, -idx);
_delEntry(last);
size--;
}
};
}
};
}
};
}
/**********************************************************************************
** Override methods
**/
/**
* Returns a clone of this map.
*
* @return an identical, yet independent copy of this map
*/
public BlockOpenHashIndexedLong2FloatMap clone() {
BlockOpenHashIndexedLong2FloatMap c;
try {
c=(BlockOpenHashIndexedLong2FloatMap) super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.keys=keys.clone();
c.idxs=idxs.clone();
c.vals=vals.clone();
c.strategy=strategy;
return c;
}
/**
* Returns a hash code for this map.
*
* @return a hash code for this map
*/
public int hashCode() {
long h=0;
long i=0, j=size;
while(j--!=0) {
long idx;
while((idx=_getIndex(i))<=0) i++;
long k=_getKey(idx-1);
h+=strategy.hash(k);
i++;
}
return (int) h;
}
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
if(o instanceof IndexedLong2FloatMap) {
IndexedLong2FloatMap that=(IndexedLong2FloatMap) o;
if(this.size!=that.size()) return false;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
if(!that.has(idx)) return false;
long k=_getKey(idx);
float v=_getVal(idx);
long l = that.getLongKey(idx);
float w = that.getValue(idx);
if(k!=l) return false;
if(Float.floatToRawIntBits(v)!=Float.floatToRawIntBits(w)) return false;
pos++;
}
return true;
}
return false;
}
public String toString() {
StringBuilder buf=new StringBuilder();
buf.append('{');
boolean first = true;
int pos=0;
while(pos<capa) {
long idx=_getIndex(pos);
if(idx<=0) {
pos++;
continue;
}
idx--;
long k=_getKey(idx);
float v=_getVal(idx);
if(first) first=false;
else buf.append(',');
buf.append(' ').append(idx).append('@').append(k).append(':').append(v);
pos++;
}
buf.append(' ').append('}');
return buf.toString();
}
// public String toDebugString() {
// StringBuilder buf=new StringBuilder();
// buf.append(this.getClass().getSimpleName()).append(" [").append(size).append('/').append(free).append('/').append(capa).append("] {\n");
// for(int i=0;i<capa;i++) {
// long idx=_getIndex(i);
// buf.append('\t');
// if(idx<0) {
// idx=-idx-1;
// buf.append('X').append(' ').append(idx).append('\t').append((_hasKey(idx) ? '+' : '-')).append(' ').append(_getKey(idx));
// buf.append("\t").append(getValue(idx));
// }
// else if(idx>0) {
// idx=idx-1;
// buf.append('=').append(' ').append(idx).append('\t').append((_hasKey(idx) ? '+' : '-')).append(' ').append(_getKey(idx));
// buf.append("\t").append(getValue(idx));
// }
// else {
// buf.append('-');
// }
// buf.append('\n');
// }
// return buf.toString();
// }
}