Przeglądaj źródła

Merge pull request #3778 from SmerkyG/intmap_iterator

Non-allocating iterators for flash IntMap
Nicolas Cannasse 9 lat temu
rodzic
commit
29a0f2413e

+ 1 - 1
extra/release-checklist.txt

@@ -30,4 +30,4 @@
 
 - Regenerate and upload API documentation (check --title and -D version values).
 - Update http://haxe.org/file/CHANGES.txt
-- Post announcement post to haxelang.
+- Post announcement post to haxelang.

+ 74 - 0
std/flash/_std/haxe/ds/IntMap.hx

@@ -47,6 +47,10 @@ package haxe.ds;
 		return true;
 	}
 
+	#if as3
+
+	// unoptimized version
+	
 	public function keys() : Iterator<Int> {
 		return untyped (__keys__(h)).iterator();
 	}
@@ -60,6 +64,18 @@ package haxe.ds;
 		};
 	}
 
+	#else
+
+	public inline function keys() : Iterator<Int> {
+		return new IntMapKeysIterator(h);
+	}
+
+	public inline function iterator() : Iterator<T> {
+		return new IntMapValuesIterator<T>(h);
+	}
+
+	#end
+	
 	public function toString() : String {
 		var s = new StringBuf();
 		s.add("{");
@@ -74,5 +90,63 @@ package haxe.ds;
 		s.add("}");
 		return s.toString();
 	}
+}
+
+#if !as3
+
+// this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation
+
+@:allow(haxe.ds.IntMap)
+private class IntMapKeysIterator {
+	var h:flash.utils.Dictionary;
+	var index : Int;
+	var nextIndex : Int;
+
+	inline function new(h:flash.utils.Dictionary):Void {
+		this.h = h;
+		this.index = 0;
+		hasNext();
+	}
+
+	public inline function hasNext():Bool {
+		var h = h, index = index; // tmp vars required for __has_next
+		var n = untyped __has_next__(h, index);
+		this.nextIndex = index; // store next index
+		return n;
+	}
+
+	public inline function next():Int {
+		var r : Int = untyped __forin__(h, nextIndex);
+		index = nextIndex;
+		return r;
+	}
+
+}
+
+@:allow(haxe.ds.IntMap)
+private class IntMapValuesIterator<T> {
+	var h:flash.utils.Dictionary;
+	var index : Int;
+	var nextIndex : Int;
+
+	inline function new(h:flash.utils.Dictionary):Void {
+		this.h = h;
+		this.index = 0;
+		hasNext();
+	}
+
+	public inline function hasNext():Bool {
+		var h = h, index = index; // tmp vars required for __has_next
+		var n = untyped __has_next__(h, index);
+		this.nextIndex = index; // store next index
+		return n;
+	}
+
+	public inline function next():T {
+		var r = untyped __foreach__(h, nextIndex);
+		index = nextIndex;
+		return r;
+	}
 
 }
+#end

+ 75 - 0
std/flash/_std/haxe/ds/UnsafeStringMap.hx

@@ -52,6 +52,10 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String,T> {
 		return true;
 	}
 
+	#if as3
+
+	// unoptimized version
+	
 	public function keys() : Iterator<String> {
 		return untyped (__keys__(h)).iterator();
 	}
@@ -65,6 +69,18 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String,T> {
 		};
 	}
 
+	#else
+
+	public inline function keys() : Iterator<String> {
+		return new UnsafeStringMapKeysIterator(h);
+	}
+
+	public inline function iterator() : Iterator<T> {
+		return new UnsafeStringMapValuesIterator<T>(h);
+	}
+
+	#end
+
 	public function toString() : String {
 		var s = new StringBuf();
 		s.add("{");
@@ -81,3 +97,62 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String,T> {
 	}
 
 }
+
+#if !as3
+
+// this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation
+
+@:allow(haxe.ds.UnsafeStringMap)
+private class UnsafeStringMapKeysIterator {
+	var h:flash.utils.Dictionary;
+	var index : Int;
+	var nextIndex : Int;
+
+	inline function new(h:flash.utils.Dictionary):Void {
+		this.h = h;
+		this.index = 0;
+		hasNext();
+	}
+
+	public inline function hasNext():Bool {
+		var h = h, index = index; // tmp vars required for __has_next
+		var n = untyped __has_next__(h, index);
+		this.nextIndex = index; // store next index
+		return n;
+	}
+
+	public inline function next():String {
+		var r : String = untyped __forin__(h, nextIndex);
+		index = nextIndex;
+		return r;
+	}
+
+}
+
+@:allow(haxe.ds.UnsafeStringMap)
+private class UnsafeStringMapValuesIterator<T> {
+	var h:flash.utils.Dictionary;
+	var index : Int;
+	var nextIndex : Int;
+
+	inline function new(h:flash.utils.Dictionary):Void {
+		this.h = h;
+		this.index = 0;
+		hasNext();
+	}
+
+	public inline function hasNext():Bool {
+		var h = h, index = index; // tmp vars required for __has_next
+		var n = untyped __has_next__(h, index);
+		this.nextIndex = index; // store next index
+		return n;
+	}
+
+	public inline function next():T {
+		var r = untyped __foreach__(h, nextIndex);
+		index = nextIndex;
+		return r;
+	}
+
+}
+#end

+ 30 - 0
tests/unit/issues/Issue3762.hx

@@ -0,0 +1,30 @@
+package unit.issues;
+import unit.Test;
+import haxe.ds.IntMap;
+
+class Issue3762 extends Test
+{
+	function test()
+	{
+		// test fast iterators against normal keys
+		var d = new IntMap<Int>();
+		var keys = [1, 2, 3];
+		for (i in 0...keys.length) {
+			var k = keys[i];
+			d.set(k, i);
+		}
+		var keyCount:Int = 0;
+		for (k in d.keys()) {
+			f( keys.indexOf(k) == -1 ); // key missing from keys iterator
+			keyCount++;
+		}
+		f( keyCount != keys.length ); // keys missing
+		var keyCount:Int = 0;
+		for (v in d) {
+			f(v < 0 || v >= keys.length); // bad value iterated
+			keyCount++;
+		}
+		f(keyCount != keys.length); // values missing
+
+	}
+}