Browse Source

Add Array.resize method (#6869)

* Add Array.resize method

* Add Array.resize eval implementation

* [php] optimized Array.resize()

* [cs/java] don't grow array on resize unless necessary

* [hl] add Array.resize to ArrayBase

* fix flash
Ben Morris 7 years ago
parent
commit
6df5ca3b11

+ 1 - 1
src/generators/genswf9.ml

@@ -319,7 +319,7 @@ let property ctx p t =
 		(match p with
 		| "length" -> ident p, Some KInt, false (* UInt in the spec *)
 		| "map" | "filter" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
-		| "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" -> ident p , None, true
+		| "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" | "resize" -> ident p , None, true
 		| _ -> as3 p, None, false);
 	| TInst ({ cl_path = ["flash"],"Vector" },_) ->
 		(match p with

+ 10 - 1
src/macro/eval/evalArray.ml

@@ -193,4 +193,13 @@ let unshift a v =
 		Array.blit a.avalues 0 a.avalues 1 a.alength;
 	end;
 	Array.set a.avalues 0 v;
-	a.alength <- a.alength + 1
+	a.alength <- a.alength + 1
+
+let resize a l =
+	if a.alength < l then begin
+		set a (l - 1) vnull;
+		()
+	end else if a.alength > l then begin
+		splice a l (a.alength - l) a.alength;
+		()
+	end else ()

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

@@ -254,6 +254,13 @@ module StdArray = struct
 		EvalArray.unshift this v;
 		vnull
 	)
+
+	let resize = vifun1 (fun vthis len ->
+		let this = this vthis in
+		let len = decode_int len in
+		EvalArray.resize this len;
+		vnull
+	)
 end
 
 let outside_bounds () =
@@ -2732,6 +2739,7 @@ let init_standard_library builtins =
 		"pop",StdArray.pop;
 		"push",StdArray.push;
 		"remove",StdArray.remove;
+		"resize",StdArray.resize;
 		"reverse",StdArray.reverse;
 		"shift",StdArray.shift;
 		"slice",StdArray.slice;

+ 14 - 0
std/Array.hx

@@ -285,4 +285,18 @@ extern class Array<T> {
 		If `f` is null, the result is unspecified.
 	**/
 	function filter( f : T -> Bool ) : Array<T>;
+
+	/**
+		Set the length of the Array.
+
+		If `len` is shorter than the array's current size, the last
+		`length - len` elements will be removed. If `len` is longer, the Array
+		will be extended, with new elements set to a target-specific default
+		value:
+
+		- always null on dynamic targets
+		- 0, 0.0 or false for Int, Float and Bool respectively on static targets
+		- null for other types on static targets
+	**/
+	function resize( len : Int ) : Void;
 }

+ 2 - 0
std/cpp/VirtualArray.hx

@@ -25,6 +25,7 @@ package cpp;
    public function iterator() : Iterator<Dynamic>;
    public function map<S>( f : Dynamic -> S ) : VirtualArray;
    public function filter( f : Dynamic -> Bool ) : VirtualArray;
+   public function resize( len : Int ) : Void;
 }
 
 
@@ -72,5 +73,6 @@ abstract VirtualArray(NativeVirtualArray)
    @:extern inline public function iterator() : Iterator<Dynamic> return this.iterator();
    @:extern inline public function map<S>( f : Dynamic -> S ) : VirtualArray return this.map(f);
    @:extern inline public function filter( f : Dynamic -> Bool ) : VirtualArray return this.filter(f);
+   @:extern inline public function resize( len : Int ) : Void return this.resize(len);
 }
 

+ 16 - 0
std/cs/_std/Array.hx

@@ -428,6 +428,22 @@ import cs.NativeArray;
 		return new ArrayIterator<T>(this);
 	}
 
+	public function resize( len : Int ) : Void
+	{
+		if (length < len)
+		{
+			if (__a.length < len)
+			{
+				cs.system.Array.Resize(__a, len);
+			}
+			this.length = len;
+		}
+		else if (length > len)
+		{
+			spliceVoid(len, length - len);
+		}
+	}
+
 	private function __get(idx:Int):T
 	{
 		return if ((cast idx : UInt) >= length) null else __a[idx];

+ 4 - 0
std/flash/Boot.hx

@@ -262,10 +262,14 @@ class Boot extends flash.display.MovieClip {
 				}
 			}
 		};
+		aproto.resize = function(len) {
+			__this__.length = len;
+		};
 		aproto.setPropertyIsEnumerable("copy", false);
 		aproto.setPropertyIsEnumerable("insert", false);
 		aproto.setPropertyIsEnumerable("remove", false);
 		aproto.setPropertyIsEnumerable("iterator", false);
+		aproto.setPropertyIsEnumerable("resize", false);
 		#if (as3 || no_flash_override)
 		aproto.filterHX = function(f) {
 			var ret = [];

+ 4 - 0
std/hl/types/ArrayBase.hx

@@ -96,6 +96,10 @@ class ArrayBase extends ArrayAccess {
 		throw "Not implemented";
 	}
 
+	public function resize( len : Int ) {
+		throw "Not implemented";
+	}
+
 	public function toString() : String {
 		throw "Not implemented";
 		return null;

+ 9 - 0
std/hl/types/ArrayBytes.hx

@@ -257,6 +257,15 @@ class BytesIterator<T> {
 		return a;
 	}
 
+	override public function resize( len : Int ) : Void {
+		if (length < len) {
+			__expand(len - 1);
+		} else if (length > len) {
+			(bytes:Bytes).fill(len << bytes.sizeBits, (length - len) << bytes.sizeBits, 0);
+			this.length = len;
+		}
+	}
+
 	override function getDyn( pos : Int ) : Dynamic {
 		var pos : UInt = pos;
 		if( pos >= length )

+ 4 - 0
std/hl/types/ArrayDyn.hx

@@ -93,6 +93,10 @@ class ArrayDyn extends ArrayAccess {
 		array.reverse();
 	}
 
+	public function resize( len : Int ) {
+		array.resize(len);
+	}
+
 	public function shift() : Null<Dynamic> {
 		return array.shiftDyn();
 	}

+ 11 - 0
std/hl/types/ArrayObj.hx

@@ -241,6 +241,17 @@ class ArrayObj<T> extends ArrayBase {
 		return a;
 	}
 
+	override public function resize( len : Int ) : Void {
+		if (length < len) {
+			__expand(len - 1);
+		} else if (length > len) {
+			for (i in length ... len) {
+				array[i] = null;
+			}
+			this.length = len;
+		}
+	}
+
 	// called by compiler when accessing the array outside of its bounds, might trigger resize
 	function __expand( index : Int ) {
 		if( index < 0 ) throw "Invalid array index " + index;

+ 19 - 0
std/java/_std/Array.hx

@@ -407,6 +407,25 @@ import java.NativeArray;
 		return new ArrayIterator<T>(this);
 	}
 
+	public function resize( len : Int ) : Void
+	{
+		if (length < len)
+		{
+			if (__a.length < len)
+			{
+				var newArr = new NativeArray<T>(len);
+				if (length > 0)
+					System.arraycopy(__a, 0, newArr, 0, length);
+				this.__a = __a = newArr;
+			}
+			this.length = len;
+		}
+		else if (length > len)
+		{
+			spliceVoid(len, length - len);
+		}
+	}
+
 	public function map<S>( f : T -> S ) : Array<S> {
 		var ret = [];
 		for (elt in this)

+ 4 - 0
std/js/_std/Array.hx

@@ -71,4 +71,8 @@ extern class Array<T> {
 		return @:privateAccess HxOverrides.iter(this);
 	}
 
+	inline function resize( len : Int ) : Void {
+		this.length = len;
+	}
+
 }

+ 10 - 0
std/lua/_std/Array.hx

@@ -213,6 +213,16 @@ class Array<T> {
 			next : function() return this[cur_length++]
 		}
 	}
+	public function resize(len:Int):Void {
+		if (length < len) {
+			this.length = len;
+		} else if (length > len) {
+			for (i in len ... length) {
+				this[i] = null;
+			}
+			this.length = len;
+		}
+	}
 	private static function __init__() : Void{
 		// table-to-array helper
 		haxe.macro.Compiler.includeFile("lua/_lua/_hx_tab_array.lua");

+ 11 - 0
std/neko/_std/Array.hx

@@ -284,6 +284,17 @@
 		return ret;
 	}
 
+	public function resize ( len : Int ) : Void {
+		if (length < len) {
+			__set(len - 1, null);
+		} else if (length > len) {
+			for (i in len ... length) {
+				__a[i] = null;
+			}
+			this.length = len;
+		}
+	}
+
 
 	/* NEKO INTERNAL */
 

+ 10 - 1
std/php/_std/Array.hx

@@ -176,6 +176,15 @@ class Array<T> implements ArrayAccess<Int,T> {
 		return '[' + Global.implode(',', strings) + ']';
 	}
 
+	public function resize( len:Int ) : Void {
+		if (length < len) {
+			arr = Global.array_pad(arr, len, null);
+		} else if (length > len) {
+			Global.array_splice(arr, len, length - len);
+		}
+		length = len;
+	}
+
 	@:noCompletion
 	function offsetExists( offset:Int ) : Bool {
 		return offset < length;
@@ -254,4 +263,4 @@ private extern interface ArrayAccess<K,V> {
 	private function offsetGet( offset:K ) : V;
 	private function offsetSet( offset:K, value:V ) : Void;
 	private function offsetUnset( offset:K ) : Void;
-}
+}

+ 5 - 1
std/python/_std/Array.hx

@@ -112,6 +112,10 @@ extern class Array<T> implements ArrayAccess<T> {
 		return ArrayImpl.filter(this,f);
 	}
 
+	public inline function resize ( len : Int ) : Void {
+		ArrayImpl.resize(this, len);
+	}
+
 	@:keep private inline function _get(idx:Int):T
 	{
 		return ArrayImpl._get(this, idx);
@@ -133,4 +137,4 @@ extern class Array<T> implements ArrayAccess<T> {
 	}
 
 	@:noCompletion private function __iter__ ():NativeIterator<T>;
-}
+}

+ 10 - 1
std/python/internal/ArrayImpl.hx

@@ -181,4 +181,13 @@ class ArrayImpl {
 		Syntax.assign(Syntax.arrayAccess(x, idx), val);
 		return val;
 	}
-}
+
+	public static inline function resize<T>(x:Array<T>, len:Int):Void {
+		var l = x.length;
+		if (l < len) {
+			_set(x, len - 1, null);
+		} else if (l > len) {
+			splice(x, len, l - len);
+		}
+	}
+}

+ 18 - 1
tests/unit/src/unitstd/Array.unit.hx

@@ -280,4 +280,21 @@ var b : Dynamic = a.filter(function(x) return x & 1 == 0).map(function(x) return
 b.length == 2;
 b[0] == 0;
 b[1] == 20;
-#end
+#end
+
+// resize
+var a : Array<Int> = [1,2,3];
+a.resize(10);
+a.length == 10;
+a == [1,2,3];
+a.resize(2);
+a.length == 2;
+a == [1, 2];
+a.resize(3);
+a.length == 3;
+a[0] == 1;
+a[1] == 2;
+a[2] != 3;
+a.resize(0);
+a.length == 0;
+a == [];