Browse Source

[std] add array access and key value iteration support to haxe.ds.HashMap (#9056)

* [std] add array access and key value iteration support to haxe.ds.HashMap

see #9055

* Add a test
Jens Fischer 5 years ago
parent
commit
c3b0b714d6

+ 11 - 2
std/haxe/ds/HashMap.hx

@@ -22,6 +22,8 @@
 
 
 package haxe.ds;
 package haxe.ds;
 
 
+import haxe.iterators.HashMapKeyValueIterator;
+
 /**
 /**
 	HashMap allows mapping of hashable objects to arbitrary values.
 	HashMap allows mapping of hashable objects to arbitrary values.
 
 
@@ -40,7 +42,7 @@ abstract HashMap<K:{function hashCode():Int;}, V>(HashMapData<K, V>) {
 	/**
 	/**
 		See `Map.set`
 		See `Map.set`
 	**/
 	**/
-	public inline function set(k:K, v:V) {
+	@:arrayAccess public inline function set(k:K, v:V) {
 		this.keys.set(k.hashCode(), k);
 		this.keys.set(k.hashCode(), k);
 		this.values.set(k.hashCode(), v);
 		this.values.set(k.hashCode(), v);
 	}
 	}
@@ -48,7 +50,7 @@ abstract HashMap<K:{function hashCode():Int;}, V>(HashMapData<K, V>) {
 	/**
 	/**
 		See `Map.get`
 		See `Map.get`
 	**/
 	**/
-	public inline function get(k:K) {
+	@:arrayAccess public inline function get(k:K) {
 		return this.values.get(k.hashCode());
 		return this.values.get(k.hashCode());
 	}
 	}
 
 
@@ -91,6 +93,13 @@ abstract HashMap<K:{function hashCode():Int;}, V>(HashMapData<K, V>) {
 		return this.values.iterator();
 		return this.values.iterator();
 	}
 	}
 
 
+	/**
+		See `Map.keyValueIterator`
+	**/
+	public inline function keyValueIterator():HashMapKeyValueIterator<K, V> {
+		return new HashMapKeyValueIterator(cast this);
+	}
+
 	/**
 	/**
 		See `Map.clear`
 		See `Map.clear`
 	**/
 	**/

+ 28 - 0
std/haxe/iterators/HashMapKeyValueIterator.hx

@@ -0,0 +1,28 @@
+package haxe.iterators;
+
+import haxe.ds.HashMap;
+
+class HashMapKeyValueIterator<K:{function hashCode():Int;}, V> {
+	final map:HashMap<K, V>;
+	final keys:Iterator<K>;
+
+	public inline function new(map:HashMap<K, V>) {
+		this.map = map;
+		this.keys = map.keys();
+	}
+
+	/**
+		See `Iterator.hasNext`
+	**/
+	public inline function hasNext():Bool {
+		return keys.hasNext();
+	}
+
+	/**
+		See `Iterator.next`
+	**/
+	public inline function next():{key:K, value:V} {
+		var key = keys.next();
+		return {value: map.get(key), key: key};
+	}
+}

+ 46 - 0
tests/unit/src/unit/TestHashMap.hx

@@ -0,0 +1,46 @@
+package unit;
+
+import haxe.ds.HashMap;
+
+class TestHashMap extends Test {
+	function test() {
+		var grid = new HashMap<Point, String>();
+		grid[new Point(0, 0)] = "a";
+		grid[new Point(0, 1)] = "b";
+		grid[new Point(1, 0)] = "c";
+		grid[new Point(1, 1)] = "d";
+
+		eq("c", grid[new Point(1, 0)]);
+
+		var asserts = 0;
+		for (p => s in grid) {
+			t(p.equals(switch s {
+				case "a": new Point(0, 0);
+				case "b": new Point(0, 1);
+				case "c": new Point(1, 0);
+				case "d": new Point(1, 1);
+				case v: throw 'unknown value $v';
+			}));
+			asserts++;
+		}
+		eq(4, asserts);
+	}
+}
+
+private class Point {
+	public final x:Int;
+	public final y:Int;
+
+	public function new(x, y) {
+		this.x = x;
+		this.y = y;
+	}
+
+	public function equals(point:Point):Bool {
+		return x == point.x && y == point.y;
+	}
+
+	public function hashCode():Int {
+		return x + 10000 * y;
+	}
+}

+ 1 - 0
tests/unit/src/unit/TestMain.hx

@@ -72,6 +72,7 @@ class TestMain {
 			new TestSyntaxModule(),
 			new TestSyntaxModule(),
 			new TestNull(),
 			new TestNull(),
 			new TestNumericCasts(),
 			new TestNumericCasts(),
+			new TestHashMap(),
 			#if (!no_http && (!azure || !(php && Windows)))
 			#if (!no_http && (!azure || !(php && Windows)))
 			new TestHttp(),
 			new TestHttp(),
 			#end
 			#end