Pārlūkot izejas kodu

Add copy() to IMap (#6331)

* Add copy() to IMap

* optimize map.copy() on php

* optimize BalancedTree.copy()

* Implement map.copy() on eval
(I have no idea what I am doing)

* refactor a bit?
Kevin Leung 8 gadi atpakaļ
vecāks
revīzija
353d877afb
49 mainītis faili ar 355 papildinājumiem un 4 dzēšanām
  1. 6 0
      src/macro/eval/evalEncode.ml
  2. 8 4
      src/macro/eval/evalStdLib.ml
  3. 9 0
      std/Map.hx
  4. 6 0
      std/cpp/_std/haxe/ds/IntMap.hx
  5. 6 0
      std/cpp/_std/haxe/ds/ObjectMap.hx
  6. 6 0
      std/cpp/_std/haxe/ds/StringMap.hx
  7. 7 0
      std/cpp/_std/haxe/ds/WeakMap.hx
  8. 6 0
      std/cs/_std/haxe/ds/IntMap.hx
  9. 6 0
      std/cs/_std/haxe/ds/ObjectMap.hx
  10. 6 0
      std/cs/_std/haxe/ds/StringMap.hx
  11. 6 0
      std/flash/_std/haxe/ds/IntMap.hx
  12. 6 0
      std/flash/_std/haxe/ds/ObjectMap.hx
  13. 6 0
      std/flash/_std/haxe/ds/StringMap.hx
  14. 6 0
      std/flash/_std/haxe/ds/UnsafeStringMap.hx
  15. 6 0
      std/flash/_std/haxe/ds/WeakMap.hx
  16. 1 0
      std/haxe/Constraints.hx
  17. 6 0
      std/haxe/ds/BalancedTree.hx
  18. 10 0
      std/haxe/ds/HashMap.hx
  19. 5 0
      std/haxe/ds/IntMap.hx
  20. 5 0
      std/haxe/ds/ObjectMap.hx
  21. 5 0
      std/haxe/ds/StringMap.hx
  22. 7 0
      std/haxe/ds/WeakMap.hx
  23. 6 0
      std/hl/_std/haxe/ds/IntMap.hx
  24. 6 0
      std/hl/_std/haxe/ds/ObjectMap.hx
  25. 6 0
      std/hl/_std/haxe/ds/StringMap.hx
  26. 6 0
      std/java/_std/haxe/ds/IntMap.hx
  27. 7 0
      std/java/_std/haxe/ds/ObjectMap.hx
  28. 6 0
      std/java/_std/haxe/ds/StringMap.hx
  29. 7 0
      std/java/_std/haxe/ds/WeakMap.hx
  30. 6 0
      std/js/_std/haxe/ds/IntMap.hx
  31. 6 0
      std/js/_std/haxe/ds/ObjectMap.hx
  32. 6 0
      std/js/_std/haxe/ds/StringMap.hx
  33. 6 0
      std/lua/_std/haxe/ds/IntMap.hx
  34. 6 0
      std/lua/_std/haxe/ds/ObjectMap.hx
  35. 6 0
      std/lua/_std/haxe/ds/StringMap.hx
  36. 6 0
      std/neko/_std/haxe/ds/IntMap.hx
  37. 6 0
      std/neko/_std/haxe/ds/ObjectMap.hx
  38. 6 0
      std/neko/_std/haxe/ds/StringMap.hx
  39. 6 0
      std/php/_std/haxe/ds/IntMap.hx
  40. 7 0
      std/php/_std/haxe/ds/ObjectMap.hx
  41. 6 0
      std/php/_std/haxe/ds/StringMap.hx
  42. 6 0
      std/php7/_std/haxe/ds/IntMap.hx
  43. 7 0
      std/php7/_std/haxe/ds/ObjectMap.hx
  44. 6 0
      std/php7/_std/haxe/ds/StringMap.hx
  45. 6 0
      std/python/_std/haxe/ds/IntMap.hx
  46. 6 0
      std/python/_std/haxe/ds/ObjectMap.hx
  47. 6 0
      std/python/_std/haxe/ds/StringMap.hx
  48. 56 0
      tests/unit/src/unitstd/Map.unit.hx
  49. 10 0
      tests/unit/src/unitstd/haxe/ds/BalancedTree.unit.hx

+ 6 - 0
src/macro/eval/evalEncode.ml

@@ -126,8 +126,14 @@ let encode_rope s =
 let encode_bytes s =
 let encode_bytes s =
 	encode_instance key_haxe_io_Bytes ~kind:(IBytes s)
 	encode_instance key_haxe_io_Bytes ~kind:(IBytes s)
 
 
+let encode_int_map_direct h =
+	encode_instance key_haxe_ds_IntMap ~kind:(IIntMap h)
+	
 let encode_string_map_direct h =
 let encode_string_map_direct h =
 	encode_instance key_haxe_ds_StringMap ~kind:(IStringMap h)
 	encode_instance key_haxe_ds_StringMap ~kind:(IStringMap h)
+	
+let encode_object_map_direct h =
+	encode_instance key_haxe_ds_ObjectMap ~kind:(IObjectMap (Obj.magic h))
 
 
 let encode_string_map convert m =
 let encode_string_map convert m =
 	let h = StringHashtbl.create 0 in
 	let h = StringHashtbl.create 0 in

+ 8 - 4
src/macro/eval/evalStdLib.ml

@@ -1358,7 +1358,7 @@ let encode_list_iterator l =
 	]
 	]
 
 
 module StdMap (Hashtbl : Hashtbl.S) = struct
 module StdMap (Hashtbl : Hashtbl.S) = struct
-	let map_fields enc dec str this = [
+	let map_fields enc dec str enc_inst this = [
 		"get",vifun1 (fun vthis vkey -> try Hashtbl.find (this vthis) (dec vkey) with Not_found -> vnull);
 		"get",vifun1 (fun vthis vkey -> try Hashtbl.find (this vthis) (dec vkey) with Not_found -> vnull);
 		"set",vifun2 (fun vthis vkey vvalue -> Hashtbl.replace (this vthis) (dec vkey) vvalue; vnull);
 		"set",vifun2 (fun vthis vkey vvalue -> Hashtbl.replace (this vthis) (dec vkey) vvalue; vnull);
 		"exists",vifun1 (fun vthis vkey -> vbool (Hashtbl.mem (this vthis) (dec vkey)));
 		"exists",vifun1 (fun vthis vkey -> vbool (Hashtbl.mem (this vthis) (dec vkey)));
@@ -1376,6 +1376,10 @@ module StdMap (Hashtbl : Hashtbl.S) = struct
 			let keys = Hashtbl.fold (fun _ v acc -> v :: acc) (this vthis) [] in
 			let keys = Hashtbl.fold (fun _ v acc -> v :: acc) (this vthis) [] in
 			encode_list_iterator keys
 			encode_list_iterator keys
 		);
 		);
+		"copy",vifun0 (fun vthis ->
+			let copied = Hashtbl.copy (this vthis) in
+			enc_inst copied
+		);
 		"toString",vifun0 (fun vthis ->
 		"toString",vifun0 (fun vthis ->
 			let open Rope in
 			let open Rope in
 			let s = concat empty [
 			let s = concat empty [
@@ -2594,17 +2598,17 @@ let init_maps builtins =
 		| VInstance {ikind = IIntMap h} -> h
 		| VInstance {ikind = IIntMap h} -> h
 		| v -> unexpected_value v "int map"
 		| v -> unexpected_value v "int map"
 	in
 	in
-	init_fields builtins (["haxe";"ds"],"IntMap") [] (StdIntMap.map_fields vint decode_int (fun i -> Rope.of_string (string_of_int i)) this);
+	init_fields builtins (["haxe";"ds"],"IntMap") [] (StdIntMap.map_fields vint decode_int (fun i -> Rope.of_string (string_of_int i)) encode_int_map_direct this);
 	let this vthis = match vthis with
 	let this vthis = match vthis with
 		| VInstance {ikind = IStringMap h} -> h
 		| VInstance {ikind = IStringMap h} -> h
 		| v -> unexpected_value v "string map"
 		| v -> unexpected_value v "string map"
 	in
 	in
-	init_fields builtins (["haxe";"ds"],"StringMap") [] (StdStringMap.map_fields vstring_direct decode_rope_string (fun (r,_) -> r) this);
+	init_fields builtins (["haxe";"ds"],"StringMap") [] (StdStringMap.map_fields vstring_direct decode_rope_string (fun (r,_) -> r) encode_string_map_direct this);
 	let this vthis = match vthis with
 	let this vthis = match vthis with
 		| VInstance {ikind = IObjectMap h} -> Obj.magic h
 		| VInstance {ikind = IObjectMap h} -> Obj.magic h
 		| v -> unexpected_value v "object map"
 		| v -> unexpected_value v "object map"
 	in
 	in
-	init_fields builtins (["haxe";"ds"],"ObjectMap") [] (StdObjectMap.map_fields (fun v -> v) (fun v -> v) (fun s -> s_value 0 s) this)
+    init_fields builtins (["haxe";"ds"],"ObjectMap") [] (StdObjectMap.map_fields (fun v -> v) (fun v -> v) (fun s -> s_value 0 s) encode_object_map_direct this)
 
 
 let init_constructors builtins =
 let init_constructors builtins =
 	let add = Hashtbl.add builtins.constructor_builtins in
 	let add = Hashtbl.add builtins.constructor_builtins in

+ 9 - 0
std/Map.hx

@@ -122,6 +122,15 @@ abstract Map<K,V>(IMap<K,V> ) {
 		return this.iterator();
 		return this.iterator();
 	}
 	}
 
 
+	/**
+		Returns a shallow copy of `this` map.
+
+		The order of values is undefined.
+	**/
+	public inline function copy():Map<K,V> {
+		return cast this.copy();
+	}
+
 	/**
 	/**
 		Returns a String representation of `this` Map.
 		Returns a String representation of `this` Map.
 
 

+ 6 - 0
std/cpp/_std/haxe/ds/IntMap.hx

@@ -77,6 +77,12 @@ package haxe.ds;
 		var a:Array<Dynamic> = untyped __global__.__int_hash_values(h);
 		var a:Array<Dynamic> = untyped __global__.__int_hash_values(h);
 		return a.iterator();
 		return a.iterator();
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		return untyped __global__.__int_hash_to_string(h);
 		return untyped __global__.__int_hash_to_string(h);

+ 6 - 0
std/cpp/_std/haxe/ds/ObjectMap.hx

@@ -76,6 +76,12 @@ class ObjectMap<K:{},V> implements haxe.Constraints.IMap<K,V> {
 		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
 		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
 		return a.iterator();
 		return a.iterator();
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		return untyped __global__.__object_hash_to_string(h);
 		return untyped __global__.__object_hash_to_string(h);

+ 6 - 0
std/cpp/_std/haxe/ds/StringMap.hx

@@ -76,6 +76,12 @@ package haxe.ds;
 		var a:Array<Dynamic> = untyped __global__.__string_hash_values(h);
 		var a:Array<Dynamic> = untyped __global__.__string_hash_values(h);
 		return a.iterator();
 		return a.iterator();
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		return untyped __global__.__string_hash_to_string(h);
 		return untyped __global__.__string_hash_to_string(h);

+ 7 - 0
std/cpp/_std/haxe/ds/WeakMap.hx

@@ -74,6 +74,13 @@ class WeakMap<K:{},V> implements haxe.Constraints.IMap<K,V> {
 		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
 		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
 		return a.iterator();
 		return a.iterator();
 	}
 	}
+	
+	public function copy() : WeakMap<K,V> {
+		var copied = new WeakMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
+
 
 
 	public function toString() : String {
 	public function toString() : String {
 		return untyped __global__.__object_hash_to_string(h);
 		return untyped __global__.__object_hash_to_string(h);

+ 6 - 0
std/cs/_std/haxe/ds/IntMap.hx

@@ -362,6 +362,12 @@ import cs.NativeArray;
 	{
 	{
 		return new IntMapValueIterator(this);
 		return new IntMapValueIterator(this);
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap<T>();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 6 - 0
std/cs/_std/haxe/ds/ObjectMap.hx

@@ -392,6 +392,12 @@ import cs.NativeArray;
 	{
 	{
 		return new ObjectMapValueIterator(this);
 		return new ObjectMapValueIterator(this);
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap<K, V>();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 6 - 0
std/cs/_std/haxe/ds/StringMap.hx

@@ -388,6 +388,12 @@ import cs.NativeArray;
 		return new StringMapValueIterator(this);
 		return new StringMapValueIterator(this);
 	}
 	}
 
 
+	public function copy() : StringMap<T> {
+		var copied = new StringMap<T>();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
+
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.
 	**/
 	**/

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

@@ -76,6 +76,12 @@ package haxe.ds;
 
 
 	#end
 	#end
 	
 	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
+	
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();
 		s.add("{");
 		s.add("{");

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

@@ -69,6 +69,12 @@ class ObjectMap<K:{},V> extends flash.utils.Dictionary implements haxe.Constrain
 	}
 	}
 
 
 	#end
 	#end
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "";
 		var s = "";

+ 6 - 0
std/flash/_std/haxe/ds/StringMap.hx

@@ -111,6 +111,12 @@ package haxe.ds;
 	}
 	}
 
 
 	#end
 	#end
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

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

@@ -80,6 +80,12 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String,T> {
 	}
 	}
 
 
 	#end
 	#end
+	
+	public function copy() : UnsafeStringMap<T> {
+		var copied = new UnsafeStringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/flash/_std/haxe/ds/WeakMap.hx

@@ -69,6 +69,12 @@ class WeakMap<K:{},V> extends flash.utils.Dictionary implements haxe.Constraints
 	}
 	}
 
 
 	#end
 	#end
+	
+	public function copy() : WeakMap<K,V> {
+		var copied = new WeakMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "";
 		var s = "";

+ 1 - 0
std/haxe/Constraints.hx

@@ -62,5 +62,6 @@ interface IMap<K,V> {
 	public function remove(k:K):Bool;
 	public function remove(k:K):Bool;
 	public function keys():Iterator<K>;
 	public function keys():Iterator<K>;
 	public function iterator():Iterator<V>;
 	public function iterator():Iterator<V>;
+	public function copy():IMap<K,V>;
 	public function toString():String;
 	public function toString():String;
 }
 }

+ 6 - 0
std/haxe/ds/BalancedTree.hx

@@ -128,6 +128,12 @@ class BalancedTree<K,V> implements haxe.Constraints.IMap<K,V> {
 		keysLoop(root, ret);
 		keysLoop(root, ret);
 		return ret.iterator();
 		return ret.iterator();
 	}
 	}
+	
+	public function copy():BalancedTree<K, V> {
+		var copied = new BalancedTree<K, V>();
+		copied.root = root;
+		return copied;
+	}
 
 
 	function setLoop(k:K, v:V, node:TreeNode<K,V>) {
 	function setLoop(k:K, v:V, node:TreeNode<K,V>) {
 		if (node == null) return new TreeNode<K,V>(null, k, v, null);
 		if (node == null) return new TreeNode<K,V>(null, k, v, null);

+ 10 - 0
std/haxe/ds/HashMap.hx

@@ -72,6 +72,16 @@ abstract HashMap<K:{ function hashCode():Int; }, V >(HashMapData<K,V>) {
 	public inline function keys() {
 	public inline function keys() {
 		return this.keys.iterator();
 		return this.keys.iterator();
 	}
 	}
+	
+	/**
+		See `Map.copy`
+	**/
+	public function copy() : HashMap<K, V> {
+		var copied = new HashMapData();
+		copied.keys = this.keys.copy();
+		copied.values = this.values.copy();
+		return cast copied;
+	}
 
 
 	/**
 	/**
 		See `Map.iterator`
 		See `Map.iterator`

+ 5 - 0
std/haxe/ds/IntMap.hx

@@ -65,6 +65,11 @@ extern class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 	**/
 	**/
 	public function iterator() : Iterator<T>;
 	public function iterator() : Iterator<T>;
 
 
+	/**
+		See `Map.copy`
+	**/
+	public function copy() : IntMap<T>;
+	
 	/**
 	/**
 		See `Map.toString`
 		See `Map.toString`
 	**/
 	**/

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

@@ -68,6 +68,11 @@ extern class ObjectMap < K: { }, V > implements haxe.Constraints.IMap<K,V> {
 		See `Map.iterator`
 		See `Map.iterator`
 	**/
 	**/
 	public function iterator():Iterator<V>;
 	public function iterator():Iterator<V>;
+	
+	/**
+		See `Map.copy`
+	**/
+	public function copy() : ObjectMap<K,V>;
 
 
 	/**
 	/**
 		See `Map.toString`
 		See `Map.toString`

+ 5 - 0
std/haxe/ds/StringMap.hx

@@ -66,6 +66,11 @@ extern class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 	**/
 	**/
 	public function iterator() : Iterator<T>;
 	public function iterator() : Iterator<T>;
 
 
+	/**
+		See `Map.copy`
+	**/
+	public function copy() : StringMap<T>;
+	
 	/**
 	/**
 		See `Map.toString`
 		See `Map.toString`
 	**/
 	**/

+ 7 - 0
std/haxe/ds/WeakMap.hx

@@ -80,6 +80,13 @@ class WeakMap<K: { },V> implements haxe.Constraints.IMap<K,V> {
 	public function iterator():Iterator<V> {
 	public function iterator():Iterator<V> {
 		return null;
 		return null;
 	}
 	}
+	
+	/**
+		See `Map.copy`
+	**/
+	public function copy() : WeakMap<K,V> {
+		return null;
+	}
 
 
 	/**
 	/**
 		See `Map.toString`
 		See `Map.toString`

+ 6 - 0
std/hl/_std/haxe/ds/IntMap.hx

@@ -54,6 +54,12 @@ class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return h.iterator();
 		return h.iterator();
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/hl/_std/haxe/ds/ObjectMap.hx

@@ -54,6 +54,12 @@ class ObjectMap<K:{},T> implements haxe.Constraints.IMap<K,T> {
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return h.iterator();
 		return h.iterator();
 	}
 	}
+	
+	public function copy() : ObjectMap<K,T> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/hl/_std/haxe/ds/StringMap.hx

@@ -79,6 +79,12 @@ class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return h.iterator();
 		return h.iterator();
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/java/_std/haxe/ds/IntMap.hx

@@ -385,6 +385,12 @@ import java.NativeArray;
 			}
 			}
 		};
 		};
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 7 - 0
std/java/_std/haxe/ds/ObjectMap.hx

@@ -409,6 +409,13 @@ import java.NativeArray;
 			}
 			}
 		};
 		};
 	}
 	}
+	
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 6 - 0
std/java/_std/haxe/ds/StringMap.hx

@@ -409,6 +409,12 @@ import java.NativeArray;
 			}
 			}
 		};
 		};
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 7 - 0
std/java/_std/haxe/ds/WeakMap.hx

@@ -447,6 +447,13 @@ import java.lang.ref.ReferenceQueue;
 			}
 			}
 		};
 		};
 	}
 	}
+	
+	
+	public function copy() : WeakMap<K,V> {
+		var copied = new WeakMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	/**
 	/**
 		Returns an displayable representation of the hashtable content.
 		Returns an displayable representation of the hashtable content.

+ 6 - 0
std/js/_std/haxe/ds/IntMap.hx

@@ -61,6 +61,12 @@ package haxe.ds;
 			next : function() { var i = __this__.it.next(); return __this__.ref[i]; }
 			next : function() { var i = __this__.it.next(); return __this__.ref[i]; }
 		};
 		};
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

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

@@ -82,6 +82,12 @@ class ObjectMap<K:{ }, V> implements haxe.Constraints.IMap<K,V> {
 			next : function() { var i = __this__.it.next(); return __this__.ref[getId(i)]; }
 			next : function() { var i = __this__.it.next(); return __this__.ref[getId(i)]; }
 		};
 		};
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

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

@@ -124,6 +124,12 @@ private class StringMapIterator<T> {
 	public inline function iterator() : Iterator<T> {
 	public inline function iterator() : Iterator<T> {
 		return new StringMapIterator(this, arrayKeys());
 		return new StringMapIterator(this, arrayKeys());
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/lua/_std/haxe/ds/IntMap.hx

@@ -66,6 +66,12 @@ class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 			next : function() return h[it.next()]
 			next : function() return h[it.next()]
 		};
 		};
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/lua/_std/haxe/ds/ObjectMap.hx

@@ -79,6 +79,12 @@ class ObjectMap<A,B> implements haxe.Constraints.IMap<A,B> {
 			next : function() return h[itr.next()]
 			next : function() return h[itr.next()]
 		};
 		};
 	}
 	}
+	
+	public function copy() : ObjectMap<A,B> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/lua/_std/haxe/ds/StringMap.hx

@@ -75,6 +75,12 @@ class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 			next : function() return untyped __lua__("{0}[{1}]", v, it.next())
 			next : function() return untyped __lua__("{0}[{1}]", v, it.next())
 		};
 		};
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/neko/_std/haxe/ds/IntMap.hx

@@ -56,6 +56,12 @@ package haxe.ds;
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		return l.iterator();
 		return l.iterator();
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

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

@@ -75,6 +75,12 @@ class ObjectMap<K:{},V> implements haxe.Constraints.IMap<K,V> {
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		return l.iterator();
 		return l.iterator();
 	}
 	}
+	
+	public function copy() : ObjectMap<K, V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/neko/_std/haxe/ds/StringMap.hx

@@ -56,6 +56,12 @@ package haxe.ds;
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		return l.iterator();
 		return l.iterator();
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/php/_std/haxe/ds/IntMap.hx

@@ -59,6 +59,12 @@ package haxe.ds;
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		copied.h = h;
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "{";
 		var s = "{";

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

@@ -73,6 +73,13 @@ class ObjectMap <K:{ }, V> implements haxe.Constraints.IMap<K,V> {
 	public inline function iterator() : Iterator<V> {
 	public inline function iterator() : Iterator<V> {
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		copied.h = h;
+		copied.hk = hk;
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "{";
 		var s = "{";

+ 6 - 0
std/php/_std/haxe/ds/StringMap.hx

@@ -59,6 +59,12 @@ package haxe.ds;
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 		return untyped __call__("new _hx_array_iterator", __call__("array_values", h));
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		copied.h = h;
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "{";
 		var s = "{";

+ 6 - 0
std/php7/_std/haxe/ds/IntMap.hx

@@ -84,6 +84,12 @@ import php.NativeIndexedArray;
 		return Global.array_values(data).iterator();
 		return Global.array_values(data).iterator();
 	}
 	}
 
 
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		copied.data = data;
+		return copied;
+	}
+
 	/**
 	/**
 		See `Map.toString`
 		See `Map.toString`
 	**/
 	**/

+ 7 - 0
std/php7/_std/haxe/ds/ObjectMap.hx

@@ -66,6 +66,13 @@ class ObjectMap <K:{ }, V> implements haxe.Constraints.IMap<K,V> {
 	public inline function iterator() : Iterator<V> {
 	public inline function iterator() : Iterator<V> {
 		return _values.iterator();
 		return _values.iterator();
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		copied._values = _values;
+		copied._keys = _keys;
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = "{";
 		var s = "{";

+ 6 - 0
std/php7/_std/haxe/ds/StringMap.hx

@@ -62,6 +62,12 @@ import haxe.Constraints;
 	public inline function iterator() : Iterator<T> {
 	public inline function iterator() : Iterator<T> {
 		return data.iterator();
 		return data.iterator();
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		copied.data = data;
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var parts = new NativeArray();
 		var parts = new NativeArray();

+ 6 - 0
std/python/_std/haxe/ds/IntMap.hx

@@ -57,6 +57,12 @@ class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return h.values().iter();
 		return h.values().iter();
 	}
 	}
+	
+	public function copy() : IntMap<T> {
+		var copied = new IntMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/python/_std/haxe/ds/ObjectMap.hx

@@ -58,6 +58,12 @@ class ObjectMap<K:{},V> implements haxe.Constraints.IMap<K, V> {
 	public function iterator() : Iterator<V> {
 	public function iterator() : Iterator<V> {
 		return h.values().iter();
 		return h.values().iter();
 	}
 	}
+	
+	public function copy() : ObjectMap<K,V> {
+		var copied = new ObjectMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 		var s = new StringBuf();
 		var s = new StringBuf();

+ 6 - 0
std/python/_std/haxe/ds/StringMap.hx

@@ -57,6 +57,12 @@ class StringMap<T> implements haxe.Constraints.IMap<String, T> {
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
 		return h.values().iter();
 		return h.values().iter();
 	}
 	}
+	
+	public function copy() : StringMap<T> {
+		var copied = new StringMap();
+		for(key in keys()) copied.set(key, get(key));
+		return copied;
+	}
 
 
 	public function toString() : String {
 	public function toString() : String {
 
 

+ 56 - 0
tests/unit/src/unitstd/Map.unit.hx

@@ -22,6 +22,20 @@ map3.exists("foo") == true;
 map3.get("foo") == 1;
 map3.get("foo") == 1;
 map4.exists("foo") == true;
 map4.exists("foo") == true;
 map4.get("foo") == 1;
 map4.get("foo") == 1;
+
+var copied = map.copy();
+copied != map;
+copied.exists("foo") == map.exists("foo");
+copied.exists("bar") == map.exists("bar");
+copied.exists("baz") == map.exists("baz");
+copied.get("foo") == map.get("foo");
+copied.get("bar") == map.get("bar");
+copied.get("baz") == map.get("baz");
+
+copied.set("foo", 4);
+copied.get("foo") == 4;
+map.get("foo") == 1;
+
 var values = [];
 var values = [];
 for (val in map) {
 for (val in map) {
 	values.push(val);
 	values.push(val);
@@ -56,6 +70,20 @@ map.exists(3) == true;
 map.get(1) == 1;
 map.get(1) == 1;
 map.get(2) == 2;
 map.get(2) == 2;
 map.get(3) == 3;
 map.get(3) == 3;
+
+var copied = map.copy();
+copied != map;
+copied.exists(1) == map.exists(1);
+copied.exists(2) == map.exists(2);
+copied.exists(3) == map.exists(3);
+copied.get(1) == map.get(1);
+copied.get(2) == map.get(2);
+copied.get(3) == map.get(3);
+
+copied.set(1, 4);
+copied.get(1) == 4;
+map.get(1) == 1;
+
 var values = [];
 var values = [];
 for (val in map) {
 for (val in map) {
 	values.push(val);
 	values.push(val);
@@ -92,6 +120,20 @@ map.exists(c) == true;
 map.get(a) == 1;
 map.get(a) == 1;
 map.get(b) == 2;
 map.get(b) == 2;
 map.get(c) == 3;
 map.get(c) == 3;
+
+var copied = map.copy();
+copied != map;
+copied.exists(a) == map.exists(a);
+copied.exists(b) == map.exists(b);
+copied.exists(c) == map.exists(c);
+copied.get(a) == map.get(a);
+copied.get(b) == map.get(b);
+copied.get(c) == map.get(c);
+
+copied.set(a, 4);
+copied.get(a) == 4;
+map.get(a) == 1;
+
 var values = [];
 var values = [];
 for (val in map) {
 for (val in map) {
 	values.push(val);
 	values.push(val);
@@ -128,6 +170,20 @@ map.exists(c) == true;
 map.get(a) == 1;
 map.get(a) == 1;
 map.get(b) == 2;
 map.get(b) == 2;
 map.get(c) == 3;
 map.get(c) == 3;
+
+var copied = map.copy();
+copied != map;
+copied.exists(a) == map.exists(a);
+copied.exists(b) == map.exists(b);
+copied.exists(c) == map.exists(c);
+copied.get(a) == map.get(a);
+copied.get(b) == map.get(b);
+copied.get(c) == map.get(c);
+
+copied.set(a, 4);
+copied.get(a) == 4;
+map.get(a) == 1;
+
 var values = [];
 var values = [];
 for (val in map) {
 for (val in map) {
 	values.push(val);
 	values.push(val);

+ 10 - 0
tests/unit/src/unitstd/haxe/ds/BalancedTree.unit.hx

@@ -31,6 +31,16 @@ for (k in test.keys()) {
 for (k in otherKeys) {
 for (k in otherKeys) {
 	eq(false, m.exists(k));
 	eq(false, m.exists(k));
 }
 }
+
+var copied = m.copy();
+copied != m;
+for(k in m.keys()) {
+	eq(test[k], copied.get(k));
+	copied.set(k, copied.get(k) + 1);
+	eq(test[k] + 1, copied.get(k));
+	eq(test[k], m.get(k));
+}
+
 var r = [for (key in m.keys()) key];
 var r = [for (key in m.keys()) key];
 arrEq(r, [1,6,8,11,13,15,17,22,25,27]);
 arrEq(r, [1,6,8,11,13,15,17,22,25,27]);
 var r = [for (val in m) val];
 var r = [for (val in m) val];