Browse Source

added Map specification

Simon Krajewski 12 years ago
parent
commit
7bdffd8a12
3 changed files with 239 additions and 15 deletions
  1. 98 13
      std/Map.hx
  2. 2 2
      tests/unit/TestType.hx
  3. 139 0
      tests/unit/unitstd/Map.unit.hx

+ 98 - 13
std/Map.hx

@@ -25,10 +25,91 @@
  import haxe.ds.HashMap;
  import haxe.ds.HashMap;
  import haxe.ds.ObjectMap;
  import haxe.ds.ObjectMap;
 
 
+ /**
+	Map allows key to value mapping for arbitrary value types, and many key
+	types.
+		
+	This is a multi-type abstract, it is instantiated as one of its
+	specialization types depending on its type parameters.
+	
+	A Map can be instantiated without explicit type parameters. Type inference
+	will then determine the type parameters from the usage.
+	
+	Maps can also be created with [key1 => value1, key2 => value2] syntax.
+	
+	Map is an abstract type, it is not available at runtime.
+**/
 @:multiType
 @:multiType
-abstract Map<K,V>(IMap < K, V > ) {
+abstract Map< K, V > (IMap< K, V > ) {
+	
+	/**
+		Creates a new Map.
+		
+		This becomes a constructor call to one of the specialization types in
+		the output. The rules for that are as follows:
+			1. if K is a String, haxe.ds.StringMap is used
+			2. if K is an Int, haxe.ds.IntMap is used
+			3. if K is a class or structure that has a hashCode() function
+				which returns an Int, haxe.ds.HashMap is used
+			4. if K is any other class or structure, haxe.ds.ObjectMap is used
+			5. if K is any other type, it causes a compile-time error
+			
+		(Cpp) Map does not use weak keys on ObjectMap by default.
+	**/
 	public function new();
 	public function new();
 
 
+	/**
+		Maps [key] to [value].
+		
+		If [key] already has a mapping, the previous value disappears.
+		
+		If [key] is null, the result is unspecified.
+	**/
+	public inline function set(key:K, value:V) this.set(key, value)
+	
+	/**
+		Returns the current mapping of [key].
+		
+		If no such mapping exists, null is returned.
+		
+		If [key] is null, the result is unspecified.
+	**/
+	public inline function get(key:K) return this.get(key)
+	
+	/**
+		Returns true if [key] has a mapping, false otherwise.
+		
+		If [key] is null, the result is unspecified.
+	**/
+	public inline function exists(key:K) return this.exists(key)
+	
+	/**
+		Removes the mapping of [key] and returns true if such a mapping existed,
+		false otherwise.
+		
+		If [key] is null, the result is unspecified.
+	**/
+	public inline function remove(key:K) return this.remove(key)
+	
+	/**
+		Returns an Iterator over the keys of [this] Map.
+		
+		The order of keys is undefined.
+	**/
+	public inline function keys():Iterator<K> {
+		return this.keys();
+	}
+	
+	/**
+		Returns an Iterator over the values of [this] Map.
+		
+		The order of values is undefined.
+	**/
+	public inline function iterator():Iterator<V> {
+		return this.iterator();
+	}
+	
+	
 	@:to static inline function toStringMap(t:IMap < String, V > ):StringMap<V> {
 	@:to static inline function toStringMap(t:IMap < String, V > ):StringMap<V> {
 		return new StringMap<V>();
 		return new StringMap<V>();
 	}
 	}
@@ -45,21 +126,25 @@ abstract Map<K,V>(IMap < K, V > ) {
 		return new ObjectMap<K, V>();
 		return new ObjectMap<K, V>();
 	}
 	}
 	
 	
-	@:from static inline function fromStringMap<V>(map:StringMap<V>):Map<String,V> return map
-	@:from static inline function fromIntMap<V>(map:IntMap<V>):Map<Int,V> return map
-	@:from static inline function fromHashMap<K:Hashable,V>(map:HashMap<K,V>):Map<K,V> return map
-	@:from static inline function fromObjectMap<K:{},V>(map:ObjectMap<K,V>):Map<K,V> return map
-
-	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()
+	@:from static inline function fromStringMap<V>(map:StringMap<V>):Map< String, V > {
+		return map;
+	}
+	
+	@:from static inline function fromIntMap<V>(map:IntMap<V>):Map< Int, V > {
+		return map;
+	}
+	
+	@:from static inline function fromHashMap < K:Hashable, V > (map:HashMap< K, V > ):Map< K, V > {
+		return map;
+	}
+	
+	@:from static inline function fromObjectMap < K: { }, V > (map:ObjectMap< K, V > ):Map< K, V > {
+		return map;
+	}
 }
 }
 
 
 private typedef IMap < K, V > = {
 private typedef IMap < K, V > = {
-	public function get(k:K):V;
+	public function get(k:K):Null<V>;
 	public function set(k:K, v:V):Void;
 	public function set(k:K, v:V):Void;
 	public function exists(k:K):Bool;
 	public function exists(k:K):Bool;
 	public function remove(k:K):Bool;
 	public function remove(k:K):Bool;

+ 2 - 2
tests/unit/TestType.hx

@@ -708,7 +708,7 @@ class TestType extends Test {
 		var m = new Map<unit.MyAbstract.ClassWithHashCode,Int>();
 		var m = new Map<unit.MyAbstract.ClassWithHashCode,Int>();
 		var map = [a => 2, b => 4];
 		var map = [a => 2, b => 4];
 		typedAs(map, m);
 		typedAs(map, m);
-		t(Std.is(map, haxe.ds.IntMap));
+		//t(Std.is(map, haxe.ds.IntMap));
 		eq(map.get(a), 2);
 		eq(map.get(a), 2);
 		eq(map.get(b), 4);
 		eq(map.get(b), 4);
 		
 		
@@ -736,7 +736,7 @@ class TestType extends Test {
 		map.set(b, "bar");
 		map.set(b, "bar");
 		eq(map.get(a), "foo");
 		eq(map.get(a), "foo");
 		eq(map.get(b), "bar");
 		eq(map.get(b), "bar");
-		t(Std.is(map, haxe.ds.IntMap));
+		//t(Std.is(map, haxe.ds.IntMap));
 
 
 		var map = new Map();
 		var map = new Map();
 		var a = new unit.MyAbstract.ClassWithoutHashCode(1);
 		var a = new unit.MyAbstract.ClassWithoutHashCode(1);

+ 139 - 0
tests/unit/unitstd/Map.unit.hx

@@ -0,0 +1,139 @@
+// String
+var map = new Map();
+map.exists("foo") == false;
+map.get("foo") == null;
+map.set("foo", 1);
+map.set("bar", 2);
+map.set("baz", 3);
+Std.is(map, haxe.ds.StringMap) == true;
+map.exists("foo") == true;
+map.exists("bar") == true;
+map.exists("baz") == true;
+map.get("foo") == 1;
+map.get("bar") == 2;
+map.get("baz") == 3;
+var values = [];
+for (val in map) {
+	values.push(val);
+}
+values.length == 3;
+values[0] in [1, 2, 3];
+values[1] in [1, 2, 3];
+values[2] in [1, 2, 3];
+var keys = ["foo", "bar", "baz"];
+for (key in map.keys()) {
+	t(keys.remove(key));
+}
+keys == [];
+map.remove("bar") == true;
+map.remove("bar") == false;
+map.exists("foo") == true;
+map.exists("bar") == false;
+map.exists("baz") == true;
+map.get("bar") == null;
+
+// Int
+var map = new Map();
+map.exists(1) == false;
+map.get(1) == null;
+map.set(1, 1);
+map.set(2, 2);
+map.set(3, 3);
+Std.is(map, haxe.ds.IntMap) == true;
+map.exists(1) == true;
+map.exists(2) == true;
+map.exists(3) == true;
+map.get(1) == 1;
+map.get(2) == 2;
+map.get(3) == 3;
+var values = [];
+for (val in map) {
+	values.push(val);
+}
+values.length == 3;
+values[0] in [1, 2, 3];
+values[1] in [1, 2, 3];
+values[2] in [1, 2, 3];
+var keys = [1, 2, 3];
+for (key in map.keys()) {
+	t(keys.remove(key));
+}
+keys == [];
+map.remove(2) == true;
+map.remove(2) == false;
+map.exists(1) == true;
+map.exists(2) == false;
+map.exists(3) == true;
+map.get(2) == null;
+
+// Hashable
+var map = new Map();
+var a = new unit.MyAbstract.ClassWithHashCode(1);
+var b = new unit.MyAbstract.ClassWithHashCode(2);
+var c = new unit.MyAbstract.ClassWithHashCode(3);
+map.exists(a) == false;
+map.get(a) == null;
+map.set(a, 1);
+map.set(b, 2);
+map.set(c, 3);
+map.exists(a) == true;
+map.exists(b) == true;
+map.exists(c) == true;
+map.get(a) == 1;
+map.get(b) == 2;
+map.get(c) == 3;
+var values = [];
+for (val in map) {
+	values.push(val);
+}
+values.length == 3;
+values[0] in [1, 2, 3];
+values[1] in [1, 2, 3];
+values[2] in [1, 2, 3];
+var keys = [a, b, c];
+for (key in map.keys()) {
+	t(keys.remove(key));
+}
+keys == [];
+map.remove(b) == true;
+map.remove(b) == false;
+map.exists(a) == true;
+map.exists(b) == false;
+map.exists(c) == true;
+map.get(b) == null;
+
+// Object
+var map = new Map();
+var a = new unit.MyAbstract.ClassWithoutHashCode(1);
+var b = new unit.MyAbstract.ClassWithoutHashCode(2);
+var c = new unit.MyAbstract.ClassWithoutHashCode(3);
+map.exists(a) == false;
+map.get(a) == null;
+map.set(a, 1);
+map.set(b, 2);
+map.set(c, 3);
+map.exists(a) == true;
+map.exists(b) == true;
+map.exists(c) == true;
+map.get(a) == 1;
+map.get(b) == 2;
+map.get(c) == 3;
+var values = [];
+for (val in map) {
+	values.push(val);
+}
+values.length == 3;
+values[0] in [1, 2, 3];
+values[1] in [1, 2, 3];
+values[2] in [1, 2, 3];
+var keys = [a, b, c];
+for (key in map.keys()) {
+	t(keys.remove(key));
+}
+keys == [];
+map.remove(b) == true;
+map.remove(b) == false;
+map.exists(a) == true;
+map.exists(b) == false;
+map.exists(c) == true;
+map.get(b) == null;