Browse Source

initial ObjectMap

Simon Krajewski 12 years ago
parent
commit
8adb29ffbb

+ 58 - 32
std/Map.hx

@@ -1,32 +1,58 @@
-@:multiType
-abstract Map(IMap < K, V > )<K,V> {
-	public function new();
-
-	@:to static inline function toHash(t:IMap < String, V > ):haxe.ds.StringMap<V> {
-		return new haxe.ds.StringMap<V>();
-	}
-
-	@:to static inline function toIntHash(t:IMap < Int, V > ):haxe.ds.IntMap<V> {
-		return new haxe.ds.IntMap<V>();
-	}
-
-	@:to static inline function toHashMap<K:{ function hashCode():Int; }>(t:IMap < K, V >):haxe.ds.HashMap<K,V> {
-		return new haxe.ds.HashMap<K, V>();
-	}
-
-	public inline function set(k:K, v:V) this.set(k, v)
-	public inline function get(k:K) return this.get(k)
-	public inline function exists(k:K) return this.exists(k)
-	public inline function remove(k:K) return this.remove(k)
-	public inline function keys() return this.keys()
-	public inline function iterator() return this.iterator()
-}
-
-private typedef IMap < K, V > = {
-	public function get(k:K):V;
-	public function set(k:K, v:V):Void;
-	public function exists(k:K):Bool;
-	public function remove(k:K):Bool;
-	public function keys():Iterator<K>;
-	public function iterator():Iterator<V>;
-}
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+@:multiType
+abstract Map(IMap < K, V > )<K,V> {
+	public function new();
+
+	@:to static inline function toHash(t:IMap < String, V > ):haxe.ds.StringMap<V> {
+		return new haxe.ds.StringMap<V>();
+	}
+
+	@:to static inline function toIntHash(t:IMap < Int, V > ):haxe.ds.IntMap<V> {
+		return new haxe.ds.IntMap<V>();
+	}
+
+	@:to static inline function toHashMap<K:{ function hashCode():Int; }>(t:IMap < K, V >):haxe.ds.HashMap<K,V> {
+		return new haxe.ds.HashMap<K, V>();
+	}
+	
+	@:to static inline function toObjectMap<K:{ }>(t:IMap < K, V >):haxe.ds.ObjectMap<K,V> {
+		return new haxe.ds.ObjectMap<K, V>();
+	}
+
+	public inline function set(k:K, v:V) this.set(k, v)
+	public inline function get(k:K) return this.get(k)
+	public inline function exists(k:K) return this.exists(k)
+	public inline function remove(k:K) return this.remove(k)
+	public inline function keys() return this.keys()
+	public inline function iterator() return this.iterator()
+}
+
+private typedef IMap < K, V > = {
+	public function get(k:K):V;
+	public function set(k:K, v:V):Void;
+	public function exists(k:K):Bool;
+	public function remove(k:K):Bool;
+	public function keys():Iterator<K>;
+	public function iterator():Iterator<V>;
+}

+ 32 - 0
std/flash/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,32 @@
+package haxe.ds;
+
+@:coreApi
+abstract ObjectMap(flash.utils.Dictionary)<K, V> {
+	public inline function new(weakKeys : Bool = false) {
+		this = new flash.utils.Dictionary(weakKeys);
+	}
+	
+	public inline function get( k : K ) : Null<V> {
+		return untyped this[k];
+	}
+
+	public inline function set( k : K, v : V ):Void {
+		untyped this[k] = v;
+	}
+
+	public inline function exists( k : K ) : Bool {
+		return untyped this[k] != null;
+	}
+
+	public inline function remove( k : K ):Bool {
+		return untyped __delete__(this,k);
+	}
+
+	public inline function keys() : Array<K> {
+		return untyped __keys__(this);
+	}
+
+	public function iterator() : Iterator<V> {
+		return untyped __keys__(this).iterator();
+	}
+}

+ 100 - 0
std/flash8/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,100 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.ds;
+
+@:coreApi
+abstract ObjectMap({}) < K: { }, V > {
+	
+	static var count = 0;
+	
+	static inline function assignId(obj: { } ) {
+		return untyped obj.__id__ = ++count;
+	}
+	
+	static inline function getId(obj: { } ) {
+		return untyped obj.__id__;
+	}
+	
+	public function new() {
+		this = untyped __new__(_global["Object"]);
+		untyped this.__keys__ = untyped __new__(_global["Object"]);
+	}
+	
+	public function set(key:K, value:V) untyped {
+		var id = "$" + (key.__id__ != null ? key.__id__ : assignId(key));
+		this[id] = value;
+		this.__keys__[id] = key;
+	}
+	
+	public inline function get(key:K) {
+		return untyped this["$" +getId(key)];
+	}
+	
+	public inline function exists(key:K) {
+		return untyped this["hasOwnProperty"]("$" +getId(key));
+	}
+	
+	public function remove( key : K ) : Bool {
+		var key = "$" + getId(key);
+		if( untyped !this["hasOwnProperty"](key) ) return false;
+		untyped __delete__(this,key);
+		untyped __delete__(this.__keys__,key);
+		return true;
+	}
+	
+	public function keys() : Iterator<K> {
+		var a = [];
+		untyped {
+			var keys:Iterator<String> = __hkeys__(this.__keys__)["iterator"]();
+			for (key in keys) {
+				if( this.hasOwnProperty("$" +key) )
+					a.push(this.__keys__["$" +key]);
+			}
+		}
+		return a.iterator();
+	}
+	
+	public function iterator() : Iterator<V> {
+		return untyped {
+			ref : this,
+			it : __hkeys__(this.__keys__)["iterator"](),
+			hasNext : function() { return __this__.it[__unprotect__("hasNext")](); },
+			next : function() { var i = __this__.it[__unprotect__("next")](); return __this__.ref["$" +i]; }
+		};
+	}
+	
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys(this);
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(this,i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+}

+ 33 - 0
std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,33 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.ds;
+
+extern class ObjectMap < K: { }, V > {
+	public function new():Void;
+	public function set(key:K, value:V):Void;
+	public function get(key:K):V;
+	public function exists(key:K):Bool;
+	public function remove(key:K):Bool;
+	public function keys():Iterator<K>;
+	public function iterator():Iterator<V>;
+}

+ 99 - 0
std/js/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,99 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.ds;
+
+@:coreApi
+abstract ObjectMap({}) < K: { }, V > {
+	
+	static var count = 0;
+	
+	static inline function assignId(obj: { } ) {
+		return untyped obj.__id__ = ++count;
+	}
+	
+	static inline function getId(obj: { } ) {
+		return untyped obj.__id__;
+	}
+	
+	public inline function new() {
+		this = { };
+		untyped this.__keys__ = { };
+	}
+	
+	public function set(key:K, value:V) untyped {
+		var id = key.__id__ != null ? key.__id__ : assignId(key);
+		this[id] = value;
+		this.__keys__[id] = key;
+	}
+	
+	public inline function get(key:K) {
+		return untyped this[getId(key)];
+	}
+	
+	public inline function exists(key:K) {
+		return untyped this.hasOwnProperty(getId(key));
+	}
+	
+	public function remove( key : K ) : Bool {
+		var id = getId(key);
+		if ( untyped !this.hasOwnProperty(id) ) return false;
+		untyped  __js__("delete")(this[id]);
+		untyped  __js__("delete")(this.__keys__[id]);
+		return true;
+	}
+	
+	public function keys() : Iterator<K> {
+		var a = [];
+		untyped {
+			__js__("for( var key in this1.__keys__ ) {");
+				if( this.hasOwnProperty(key) )
+					a.push(this.__keys__[key]);
+			__js__("}");
+		}
+		return a.iterator();
+	}
+	
+	public function iterator() : Iterator<V> {
+		return untyped {
+			ref : this,
+			it : keys(this),
+			hasNext : function() { return __this__.it.hasNext(); },
+			next : function() { var i = __this__.it.next(); return __this__.ref[getId(i)]; }
+		};
+	}
+	
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys(this);
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(this,i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+}

+ 73 - 0
std/neko/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package haxe.ds;
+
+@:coreApi
+abstract ObjectMap({})<K,V> {
+
+	public function new() : Void {
+		this = untyped __dollar__hnew(0);
+	}
+
+	public inline function set( key : K, value : V ) : Void {
+		untyped __dollar__hset(this,key,value,null);
+	}
+
+	public function get( key : K ) : V {
+		return untyped __dollar__hget(this,key,null);
+	}
+
+	public inline function exists( key : K ) : Bool {
+		return untyped __dollar__hmem(this,key,null);
+	}
+
+	public inline function remove( key : K ) : Bool {
+		return untyped __dollar__hremove(this,key,null);
+	}
+
+	public function keys() : Iterator<K> {
+		var l = new List<K>();
+		untyped __dollar__hiter(this,function(k,_) { l.push(k); });
+		return l.iterator();
+	}
+
+	public function iterator() : Iterator<V> {
+		var l = new List<V>();
+		untyped __dollar__hiter(this,function(_,v) { l.push(v); });
+		return l.iterator();
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys(this);
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(this,i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+}

+ 71 - 0
std/php/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,71 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.ds;
+
+@:coreApi
+abstract ObjectMap(StringMap<V>) < K: { }, V > {
+	static function getId(key: { } ) {
+		return untyped __php__("spl_object_hash($key)");
+	}
+	
+	public function new() {
+		this = new StringMap<V>();
+	}
+	
+	public function set(key:K, value:V) untyped {
+		untyped this.set(getId(key), value);
+	}
+	
+	public function get(key:K) {
+		return this.get(getId(key));
+	}
+	
+	public function exists(key:K) {
+		return this.exists(getId(key));
+	}
+	
+	public function remove( key : K ) : Bool {
+		return this.remove(getId(key));
+	}
+	
+	public inline function keys() : Iterator<K> {
+		return untyped __call__("new _hx_array_iterator", __call__("array_keys", this.h));
+	}
+	
+	public inline function iterator() : Iterator<V> {
+		return untyped __call__("new _hx_array_iterator", __call__("array_values", this.h));
+	}
+	
+	public function toString() : String {
+		var s = "{";
+		var it = keys(this);
+		for( i in it ) {
+			s += i;
+			s += " => ";
+			s += Std.string(get(this,i));
+			if( it.hasNext() )
+				s += ", ";
+		}
+		return s + "}";
+	}
+}

+ 5 - 0
tests/unit/MyAbstract.hx

@@ -156,4 +156,9 @@ class ClassWithHashCode {
 	var i:Int;
 	public function new(i) { this.i = i; }
 	public function hashCode() return i
+}
+
+class ClassWithoutHashCode {
+	public var i:Int;
+	public function new(i) { this.i = i; }
 }

+ 10 - 0
tests/unit/TestType.hx

@@ -736,6 +736,16 @@ class TestType extends Test {
 		eq(map.get(b), "bar");
 		t(Std.is(map, haxe.ds.IntMap));
 
+		var map = new Map();
+		var a = new unit.MyAbstract.ClassWithoutHashCode(1);
+		var b = new unit.MyAbstract.ClassWithoutHashCode(2);
+		map.set(a, "foo");
+		map.set(b, "bar");
+		eq(map.get(a), "foo");
+		eq(map.get(b), "bar");
+		// this may be specialized
+		//t(Std.is(map, haxe.ds.ObjectMap));
+		
 		//var map = new unit.MyAbstract.MyMap();
 		//map.set(new haxe.Template("foo"), 99);
 		//t(Std.is(map, unit.MyAbstract.PseudoObjectHash));

+ 79 - 0
tests/unit/unitstd/haxe/ds/ObjectMap.unit.hx

@@ -0,0 +1,79 @@
+var k1 = new IntWrap(1);
+var k2 = new IntWrap(2);
+var k3 = new IntWrap(3);
+var o = new haxe.ds.ObjectMap();
+
+// non existent
+o.exists(k1) == false;
+o.exists(k2) == false;
+o.exists(k3) == false;
+o.get(k1) == null;
+o.get(k2) == null;
+o.get(k3) == null;
+
+// set + exists
+o.set(k1, "9");
+o.set(k2, "8");
+o.set(k3, "7");
+o.exists(k1) == true;
+o.exists(k2) == true;
+o.exists(k3) == true;
+
+// get
+o.get(k3) == "7";
+o.get(k2) == "8";
+o.get(k1) == "9";
+
+// keys
+var a = [];
+for (k in o.keys())
+	a.push(k);
+a.length == 3;
+a[0] in [k1, k2, k3];
+a[1] in [k1, k2, k3];
+a[2] in [k1, k2, k3];
+o.exists(k1) == true;
+o.exists(k2) == true;
+o.exists(k3) == true;
+o.get(k3) == "7";
+o.get(k2) == "8";
+o.get(k1) == "9";
+
+// iterator
+var a:Array<String> = [];
+for (k in o) {
+	a.push(k);
+}
+a.length == 3;
+a[0] in ["9", "8", "7"];
+a[1] in ["9", "8", "7"];
+a[2] in ["9", "8", "7"];
+o.exists(k1) == true;
+o.exists(k2) == true;
+o.exists(k3) == true;
+o.get(k3) == "7";
+o.get(k2) == "8";
+o.get(k1) == "9";
+
+// remove
+o.remove(k2) == true;
+o.exists(k1) == true;
+o.exists(k2) == false;
+o.exists(k3) == true;
+o.get(k1) == "9";
+o.get(k2) == null;
+o.get(k3) == "7";
+var a = [];
+for (k in o.keys())
+	a.push(k);
+a.length == 2;
+a[0] in [k1, k3];
+a[1] in [k1, k3];
+var a:Array<String> = [];
+for (k in o.iterator()) {
+	a.push(k);
+}
+a.length == 2;
+a[0] in ["9", "7"];
+a[1] in ["9", "7"];
+o.remove(k2) == false;