Browse Source

[js] let's see if `Object.create(null)` makes sense for StringMap nowadays (#8909)

* [js] let's see if `Object.create(null)` makes sense for StringMap nowadays

* [js] adjust optimization test
Dan Korostelev 6 years ago
parent
commit
653f3062de
2 changed files with 102 additions and 2 deletions
  1. 100 0
      std/js/_std/haxe/ds/StringMap.hx
  2. 2 2
      tests/optimization/src/TestJs.hx

+ 100 - 0
std/js/_std/haxe/ds/StringMap.hx

@@ -22,6 +22,105 @@
 
 
 package haxe.ds;
 package haxe.ds;
 
 
+import js.lib.Object;
+import haxe.Constraints.IMap;
+import haxe.DynamicAccess;
+
+#if (js_es >= 5)
+@:coreApi class StringMap<T> implements IMap<String, T> {
+	var h:Dynamic;
+
+	public inline function new() {
+		h = Object.create(null);
+	}
+
+	public inline function exists(key:String):Bool {
+		return Object.prototype.hasOwnProperty.call(h, key);
+	}
+
+	public inline function get(key:String):Null<T> {
+		return h[cast key];
+	}
+
+	public inline function set(key:String, value:T):Void {
+		h[cast key] = value;
+	}
+
+	public inline function remove(key:String):Bool {
+		return if (exists(key)) {
+			js.Syntax.delete(h, key); true;
+		} else {
+			false;
+		}
+	}
+
+	public inline function keys():Iterator<String> {
+		return keysIterator(h);
+	}
+
+	public inline function iterator():Iterator<T> {
+		return valueIterator(h);
+	}
+
+	public inline function keyValueIterator():KeyValueIterator<String, T> {
+		return kvIterator(h);
+	}
+
+	public inline function copy():StringMap<T> {
+		return createCopy(h);
+	}
+
+	public inline function clear():Void {
+		h = Object.create(null);
+	}
+
+	public inline function toString():String {
+		return stringify(h);
+	}
+
+	// impl
+
+	static function keysIterator(h:Dynamic):Iterator<String> {
+		var keys = Object.keys(h), len = keys.length, idx = 0;
+		return {
+			hasNext: () -> idx < len,
+			next: () -> keys[idx++]
+		};
+	}
+
+	static function valueIterator<T>(h:Dynamic):Iterator<T> {
+		var keys = Object.keys(h), len = keys.length, idx = 0;
+		return {
+			hasNext: () -> idx < len,
+			next: () -> h[cast keys[idx++]]
+		};
+	}
+
+	static function kvIterator<T>(h:Dynamic):KeyValueIterator<String, T> {
+		var keys = Object.keys(h), len = keys.length, idx = 0;
+		return {
+			hasNext: () -> idx < len,
+			next: () -> {var k = keys[idx++]; {key: k, value: h[cast k]}}
+		};
+	}
+
+	static function createCopy<T>(h:Dynamic):StringMap<T> {
+		var copy = new StringMap();
+		js.Syntax.code("for (var key in {0}) {1}[key] = {0}[key]", h, copy.h);
+		return copy;
+	}
+
+	@:analyzer(no_optimize)
+	static function stringify(h:Dynamic):String {
+		var s = "{", first = true;
+		js.Syntax.code("for (var key in {0}) {", h);
+		js.Syntax.code("\tif ({0}) {0} = false; else {1} += ',';", first, s);
+		js.Syntax.code("\t{0} += key + ' => ' + {1}({2}[key]);", s, Std.string, h);
+		js.Syntax.code("}");
+		return s + "}";
+	}
+}
+#else
 private class StringMapIterator<T> {
 private class StringMapIterator<T> {
 	var map:StringMap<T>;
 	var map:StringMap<T>;
 	var keys:Array<String>;
 	var keys:Array<String>;
@@ -168,3 +267,4 @@ private class StringMapIterator<T> {
 		untyped __js__("var __map_reserved = {};");
 		untyped __js__("var __map_reserved = {};");
 	}
 	}
 }
 }
+#end

+ 2 - 2
tests/optimization/src/TestJs.hx

@@ -249,8 +249,8 @@ class TestJs {
 	}
 	}
 
 
 	@:js('
 	@:js('
-		var map = new haxe_ds_StringMap();
-		if(__map_reserved["some"] != null) {map.setReserved("some",2);} else {map.h["some"] = 2;}
+		var map_h = Object.create(null);
+		map_h["some"] = 2;
 		TestJs.use(2);
 		TestJs.use(2);
 	')
 	')
 	static function testIssue4731() {
 	static function testIssue4731() {