2
0
Эх сурвалжийг харах

[java] Add `no_map_cache` checks on WeakMap, and reimplement its iterators as classes

Cauê Waneck 8 жил өмнө
parent
commit
76f77ae9e4

+ 106 - 50
std/java/_std/haxe/ds/WeakMap.hx

@@ -50,8 +50,10 @@ import java.lang.ref.ReferenceQueue;
 	private var nOccupied:Int;
 	private var upperBound:Int;
 
+#if !no_map_cache
 	private var cachedEntry:Entry<K,V>;
 	private var cachedIndex:Int;
+#end
 
 #if DEBUG_HASHTBL
 	private var totalProbes:Int;
@@ -62,7 +64,9 @@ import java.lang.ref.ReferenceQueue;
 
 	public function new() : Void
 	{
+#if !no_map_cache
 		cachedIndex = -1;
+#end
 		queue = new ReferenceQueue();
 	}
 
@@ -89,11 +93,13 @@ import java.lang.ref.ReferenceQueue;
 
 				if (entries[i] == x)
 				{
+#if !no_map_cache
 					if (cachedIndex == i)
 					{
 						cachedIndex = -1;
 						cachedEntry = null;
 					}
+#end
 					entries[i] = null;
 					hashes[i] = FLAG_DEL;
 					--size;
@@ -169,8 +175,10 @@ import java.lang.ref.ReferenceQueue;
 			entries[x] = entry;
 		}
 
+#if !no_map_cache
 		cachedIndex = x;
 		cachedEntry = entry;
+#end
 	}
 
 	@:final private function lookup( key : K ) : Int
@@ -231,8 +239,10 @@ import java.lang.ref.ReferenceQueue;
 		if (j != 0)
 		{ //rehashing is required
 			//resetting cache
+#if !no_map_cache
 			cachedEntry = null;
 			cachedIndex = -1;
+#end
 
 			j = -1;
 			var nBuckets = nBuckets, entries = entries, hashes = hashes;
@@ -294,17 +304,21 @@ import java.lang.ref.ReferenceQueue;
 	{
 		cleanupRefs();
 		var idx = -1;
+#if !no_map_cache
 		if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 ))
 		{
 			return cachedEntry.value;
 		}
+#end
 
 		idx = lookup(key);
 		if (idx != -1)
 		{
 			var entry = entries[idx];
+#if !no_map_cache
 			cachedEntry = entry;
 			cachedIndex = idx;
+#end
 
 			return entry.value;
 		}
@@ -316,17 +330,21 @@ import java.lang.ref.ReferenceQueue;
 	{
 		cleanupRefs();
 		var idx = -1;
+#if !no_map_cache
 		if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 ))
 		{
 			return cachedEntry.value;
 		}
+#end
 
 		idx = lookup(key);
 		if (idx != -1)
 		{
 			var entry = entries[idx];
+#if !no_map_cache
 			cachedEntry = entry;
 			cachedIndex = idx;
+#end
 
 			return entry.value;
 		}
@@ -338,17 +356,21 @@ import java.lang.ref.ReferenceQueue;
 	{
 		cleanupRefs();
 		var idx = -1;
+#if !no_map_cache
 		if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 ))
 		{
 			return true;
 		}
+#end
 
 		idx = lookup(key);
 		if (idx != -1)
 		{
 			var entry = entries[idx];
+#if !no_map_cache
 			cachedEntry = entry;
 			cachedIndex = idx;
+#end
 
 			return true;
 		}
@@ -360,7 +382,9 @@ import java.lang.ref.ReferenceQueue;
 	{
 		cleanupRefs();
 		var idx = -1;
+#if !no_map_cache
 		if ( !(cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) )
+#end
 		{
 			idx = lookup(key);
 		}
@@ -369,11 +393,13 @@ import java.lang.ref.ReferenceQueue;
 		{
 			return false;
 		} else {
+#if !no_map_cache
 			if (cachedEntry != null && cachedEntry.keyEquals(key))
 			{
 				cachedIndex = -1;
 				cachedEntry = null;
 			}
+#end
 
 			hashes[idx] = FLAG_DEL;
 			entries[idx] = null;
@@ -387,66 +413,20 @@ import java.lang.ref.ReferenceQueue;
 		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<K>
+	public inline function keys() : Iterator<K>
 	{
 		cleanupRefs();
-		var i = 0;
-		var len = nBuckets;
-		var lastKey = null; //keep a strong reference to the key while iterating, so it can't be collected while iterating
-		return {
-			hasNext: function() {
-				for (j in i...len)
-				{
-					if (!isEither(hashes[j]))
-					{
-						var entry = entries[j];
-						var last = entry.get();
-						if (last != null)
-						{
-							lastKey = last;
-							cachedIndex = i;
-							cachedEntry = entry;
-							i = j;
-							return true;
-						}
-					}
-				}
-				return false;
-			},
-			next: function() {
-				i = i + 1;
-				return lastKey;
-			}
-		};
+		return new WeakMapKeyIterator(this);
 	}
 
 	/**
 		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<V>
+	public inline function iterator() : Iterator<V>
 	{
 		cleanupRefs();
-		var i = 0;
-		var len = nBuckets;
-		return {
-			hasNext: function() {
-				for (j in i...len)
-				{
-					if (!isEither(hashes[j]))
-					{
-						i = j;
-						return true;
-					}
-				}
-				return false;
-			},
-			next: function() {
-				var ret = entries[i].value;
-				i = i + 1;
-				return ret;
-			}
-		};
+		return new WeakMapValueIterator(this);
 	}
 
 
@@ -555,4 +535,80 @@ private class Entry<K,V> extends WeakReference<K>
 	}
 }
 
+@:access(haxe.ds.WeakMap)
+@:final
+private class WeakMapKeyIterator<T:{},V> {
+	var m:WeakMap<T,V>;
+	var i:Int;
+	var len:Int;
+	var lastKey:T;
+
+	public function new(m:WeakMap<T,V>) {
+		this.i = 0;
+		this.m = m;
+		this.len = m.nBuckets;
+	}
+
+	public function hasNext():Bool {
+		for (j in i...len)
+		{
+			if (!WeakMap.isEither(m.hashes[j]))
+			{
+				var entry = m.entries[j],
+				    last = entry.get();
+				if (last != null)
+				{
+#if !no_map_cache
+					m.cachedIndex = i;
+					m.cachedEntry = entry;
+#end
+					lastKey = last; // keep a strong reference to the key while iterating, so it doesn't get collected
+					i = j;
+					return true;
+				}
+			}
+		}
+		lastKey = null;
+		return false;
+	}
+
+	public function next() : T {
+		i = i + 1;
+		return lastKey;
+	}
+}
+
+@:access(haxe.ds.WeakMap)
+@:final
+private class WeakMapValueIterator<K:{},T> {
+	var m:WeakMap<K,T>;
+	var i:Int;
+	var len:Int;
+
+	public function new(m:WeakMap<K,T>)
+	{
+		this.i = 0;
+		this.m = m;
+		this.len = m.nBuckets;
+	}
+
+	public function hasNext() : Bool {
+		for (j in i...len)
+		{
+			if (!WeakMap.isEither(m.hashes[j]) && m.entries[j].get() != null)
+			{
+				i = j;
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public inline function next():T {
+		var ret = m.entries[i];
+		i = i + 1;
+		return ret.value;
+	}
+}
+
 private typedef HashType = Int;