|
@@ -1,5 +1,3 @@
|
|
|
-package;
|
|
|
-import java.NativeArray;
|
|
|
/*
|
|
|
* Copyright (c) 2005, The haXe Project Contributors
|
|
|
* All rights reserved.
|
|
@@ -24,37 +22,38 @@ import java.NativeArray;
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
* DAMAGE.
|
|
|
*/
|
|
|
+import java.NativeArray;
|
|
|
|
|
|
-/**
|
|
|
+/*
|
|
|
* This IntHash implementation is based on khash (https://github.com/attractivechaos/klib/blob/master/khash.h)
|
|
|
* Copyright goes to Attractive Chaos <[email protected]> and his contributors
|
|
|
- *
|
|
|
+ *
|
|
|
* Thanks also to Jonas Malaco Filho for his Haxe-written IntHash code inspired by Python tables.
|
|
|
* (https://jonasmalaco.com/fossil/test/jonas-haxe/artifact/887b53126e237d6c68951111d594033403889304)
|
|
|
*/
|
|
|
-
|
|
|
-@:core_api class IntHash<T>
|
|
|
+
|
|
|
+@:core_api class IntHash<T>
|
|
|
{
|
|
|
private static inline var HASH_UPPER = 0.7;
|
|
|
-
|
|
|
+
|
|
|
private var flags:NativeArray<Int>;
|
|
|
private var _keys:NativeArray<Int>;
|
|
|
private var vals:NativeArray<T>;
|
|
|
-
|
|
|
+
|
|
|
private var nBuckets:Int;
|
|
|
private var size:Int;
|
|
|
private var nOccupied:Int;
|
|
|
private var upperBound:Int;
|
|
|
-
|
|
|
+
|
|
|
private var cachedKey:Int;
|
|
|
private var cachedIndex:Int;
|
|
|
-
|
|
|
- public function new() : Void
|
|
|
+
|
|
|
+ public function new() : Void
|
|
|
{
|
|
|
cachedIndex = -1;
|
|
|
}
|
|
|
|
|
|
- public function set( key : Int, value : T ) : Void
|
|
|
+ public function set( key : Int, value : T ) : Void
|
|
|
{
|
|
|
var x:Int;
|
|
|
if (nOccupied >= upperBound)
|
|
@@ -64,14 +63,14 @@ import java.NativeArray;
|
|
|
else
|
|
|
resize(nBuckets + 1);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
var flags = flags, _keys = _keys;
|
|
|
{
|
|
|
var mask = nBuckets - 1;
|
|
|
var site = x = nBuckets;
|
|
|
var k = hash(key);
|
|
|
var i = k & mask;
|
|
|
-
|
|
|
+
|
|
|
//for speed up
|
|
|
if (flagIsEmpty(flags, i)) {
|
|
|
x = i;
|
|
@@ -91,8 +90,8 @@ import java.NativeArray;
|
|
|
x = i;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if (flagIsEmpty(flags, x))
|
|
|
+
|
|
|
+ if (flagIsEmpty(flags, x))
|
|
|
{
|
|
|
_keys[x] = key;
|
|
|
vals[x] = value;
|
|
@@ -109,13 +108,13 @@ import java.NativeArray;
|
|
|
vals[x] = value;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@:final private function lookup( key : Int ) : Int
|
|
|
{
|
|
|
if (nBuckets != 0)
|
|
|
{
|
|
|
var flags = flags, _keys = _keys;
|
|
|
-
|
|
|
+
|
|
|
var mask = nBuckets - 1, k = hash(key);
|
|
|
var i = k & mask;
|
|
|
var inc = getInc(k, mask); /* inc == 1 for linear probing */
|
|
@@ -128,30 +127,30 @@ import java.NativeArray;
|
|
|
}
|
|
|
return isEither(flags, i) ? -1 : i;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return -1;
|
|
|
}
|
|
|
-
|
|
|
- public function get( key : Int ) : Null<T>
|
|
|
+
|
|
|
+ public function get( key : Int ) : Null<T>
|
|
|
{
|
|
|
var idx = -1;
|
|
|
if (cachedKey == key && ( (idx = cachedIndex) != -1 ))
|
|
|
{
|
|
|
return vals[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
idx = lookup(key);
|
|
|
if (idx != -1)
|
|
|
{
|
|
|
cachedKey = key;
|
|
|
cachedIndex = idx;
|
|
|
-
|
|
|
+
|
|
|
return vals[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return null;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private function getDefault( key : Int, def : T ) : T
|
|
|
{
|
|
|
var idx = -1;
|
|
@@ -159,67 +158,67 @@ import java.NativeArray;
|
|
|
{
|
|
|
return vals[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
idx = lookup(key);
|
|
|
if (idx != -1)
|
|
|
{
|
|
|
cachedKey = key;
|
|
|
cachedIndex = idx;
|
|
|
-
|
|
|
+
|
|
|
return vals[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return def;
|
|
|
}
|
|
|
|
|
|
- public function exists( key : Int ) : Bool
|
|
|
+ public function exists( key : Int ) : Bool
|
|
|
{
|
|
|
var idx = -1;
|
|
|
if (cachedKey == key && ( (idx = cachedIndex) != -1 ))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
idx = lookup(key);
|
|
|
if (idx != -1)
|
|
|
{
|
|
|
cachedKey = key;
|
|
|
cachedIndex = idx;
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- public function remove( key : Int ) : Bool
|
|
|
+ public function remove( key : Int ) : Bool
|
|
|
{
|
|
|
var idx = -1;
|
|
|
if (! (cachedKey == key && ( (idx = cachedIndex) != -1 )))
|
|
|
{
|
|
|
idx = lookup(key);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (idx == -1)
|
|
|
{
|
|
|
return false;
|
|
|
} else {
|
|
|
if (cachedKey == key)
|
|
|
cachedIndex = -1;
|
|
|
-
|
|
|
+
|
|
|
if (!isEither(flags, idx))
|
|
|
{
|
|
|
setIsDelTrue(flags, idx);
|
|
|
--size;
|
|
|
-
|
|
|
+
|
|
|
vals[idx] = null;
|
|
|
_keys[idx] = 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@:final private function resize(newNBuckets:Int) : Void
|
|
|
{
|
|
|
//This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets.
|
|
@@ -242,7 +241,7 @@ import java.NativeArray;
|
|
|
if (_keys != null)
|
|
|
arrayCopy(_keys, 0, k, 0, nBuckets);
|
|
|
_keys = k;
|
|
|
-
|
|
|
+
|
|
|
var v = new NativeArray(newNBuckets);
|
|
|
if (vals != null)
|
|
|
arrayCopy(vals, 0, v, 0, nBuckets);
|
|
@@ -250,16 +249,16 @@ import java.NativeArray;
|
|
|
} //otherwise shrink
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if (j != 0)
|
|
|
+
|
|
|
+ if (j != 0)
|
|
|
{ //rehashing is required
|
|
|
//resetting cache
|
|
|
cachedKey = 0;
|
|
|
cachedIndex = -1;
|
|
|
-
|
|
|
+
|
|
|
j = -1;
|
|
|
var nBuckets = nBuckets, _keys = _keys, vals = vals, flags = flags;
|
|
|
-
|
|
|
+
|
|
|
var newMask = newNBuckets - 1;
|
|
|
while (++j < nBuckets)
|
|
|
{
|
|
@@ -267,7 +266,7 @@ import java.NativeArray;
|
|
|
{
|
|
|
var key = _keys[j];
|
|
|
var val = vals[j];
|
|
|
-
|
|
|
+
|
|
|
setIsDelTrue(flags, j);
|
|
|
while (true) /* kick-out process; sort of like in Cuckoo hashing */
|
|
|
{
|
|
@@ -277,7 +276,7 @@ import java.NativeArray;
|
|
|
while (!flagIsEmpty(newFlags, i))
|
|
|
i = (i + inc) & newMask;
|
|
|
setIsEmptyFalse(newFlags, i);
|
|
|
-
|
|
|
+
|
|
|
if (i < nBuckets && !isEither(flags, i)) /* kick out the existing element */
|
|
|
{
|
|
|
{
|
|
@@ -290,7 +289,7 @@ import java.NativeArray;
|
|
|
vals[i] = val;
|
|
|
val = tmp;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
setIsDelTrue(flags, i); /* mark it as deleted in the old hash table */
|
|
|
} else { /* write the element and jump out of the loop */
|
|
|
_keys[i] = key;
|
|
@@ -300,7 +299,7 @@ import java.NativeArray;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (nBuckets > newNBuckets) /* shrink the hash table */
|
|
|
{
|
|
|
{
|
|
@@ -314,7 +313,7 @@ import java.NativeArray;
|
|
|
this.vals = v;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
this.flags = newFlags;
|
|
|
this.nBuckets = newNBuckets;
|
|
|
this.nOccupied = size;
|
|
@@ -326,7 +325,7 @@ import java.NativeArray;
|
|
|
Returns an iterator of all keys in the hashtable.
|
|
|
Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration
|
|
|
**/
|
|
|
- public function keys() : Iterator<Int>
|
|
|
+ public function keys() : Iterator<Int>
|
|
|
{
|
|
|
var i = 0;
|
|
|
var len = nBuckets;
|
|
@@ -346,7 +345,7 @@ import java.NativeArray;
|
|
|
var ret = _keys[i];
|
|
|
cachedIndex = i;
|
|
|
cachedKey = ret;
|
|
|
-
|
|
|
+
|
|
|
i = i + 1;
|
|
|
return ret;
|
|
|
}
|
|
@@ -357,7 +356,7 @@ import java.NativeArray;
|
|
|
Returns an iterator of all values in the hashtable.
|
|
|
Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration
|
|
|
**/
|
|
|
- public function iterator() : Iterator<T>
|
|
|
+ public function iterator() : Iterator<T>
|
|
|
{
|
|
|
var i = 0;
|
|
|
var len = nBuckets;
|
|
@@ -399,46 +398,46 @@ import java.NativeArray;
|
|
|
s.add("}");
|
|
|
return s.toString();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private static inline function assert(x:Bool):Void
|
|
|
{
|
|
|
#if debug
|
|
|
if (!x) throw "assert failed";
|
|
|
#end
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private static inline function defaultK():Int return 0
|
|
|
-
|
|
|
+
|
|
|
private static inline function arrayCopy(sourceArray:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void
|
|
|
java.lang.System.arraycopy(sourceArray, sourceIndex, destinationArray, destinationIndex, length)
|
|
|
-
|
|
|
+
|
|
|
private static inline function getInc(k:Int, mask:Int):Int
|
|
|
return (((k) >> 3 ^ (k) << 3) | 1) & (mask)
|
|
|
-
|
|
|
- private static inline function hash(i:Int):Int
|
|
|
+
|
|
|
+ private static inline function hash(i:Int):Int
|
|
|
return i
|
|
|
-
|
|
|
+
|
|
|
private static inline function flagIsEmpty(flag:NativeArray<Int>, i:Int):Bool
|
|
|
return ( (flag[i >> 4] >>> ((i & 0xf) << 1)) & 2 ) != 0
|
|
|
-
|
|
|
+
|
|
|
private static inline function flagIsDel(flag:NativeArray<Int>, i:Int):Bool
|
|
|
return ((flag[i >> 4] >>> ((i & 0xf) << 1)) & 1) != 0
|
|
|
-
|
|
|
+
|
|
|
private static inline function isEither(flag:NativeArray<Int>, i:Int):Bool
|
|
|
return ((flag[i >> 4] >>> ((i & 0xf) << 1)) & 3) != 0
|
|
|
-
|
|
|
+
|
|
|
private static inline function setIsDelFalse(flag:NativeArray<Int>, i:Int):Void
|
|
|
flag[i >> 4] &= ~(1 << ((i & 0xf) << 1))
|
|
|
-
|
|
|
+
|
|
|
private static inline function setIsEmptyFalse(flag:NativeArray<Int>, i:Int):Void
|
|
|
flag[i >> 4] &= ~(2 << ((i & 0xf) << 1))
|
|
|
-
|
|
|
+
|
|
|
private static inline function setIsBothFalse(flag:NativeArray<Int>, i:Int):Void
|
|
|
flag[i >> 4] &= ~(3 << ((i & 0xf) << 1))
|
|
|
-
|
|
|
+
|
|
|
private static inline function setIsDelTrue(flag:NativeArray<Int>, i:Int):Void
|
|
|
flag[i >> 4] |= 1 << ((i & 0xf) << 1)
|
|
|
-
|
|
|
+
|
|
|
private static inline function roundUp(x:Int):Int
|
|
|
{
|
|
|
--x;
|
|
@@ -449,7 +448,7 @@ import java.NativeArray;
|
|
|
x |= (x) >>> 16;
|
|
|
return ++x;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private static inline function flagsSize(m:Int):Int
|
|
|
return ((m) < 16? 1 : (m) >> 4)
|
|
|
}
|