From dcbfeb652bb459852265172e7c8d5181dc3095f2 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 1 Feb 2015 13:41:25 +0100 Subject: [PATCH 1/7] cross platform typed array proposal --- std/haxe/io/ArrayBufferView.hx | 63 +++++++++++ std/haxe/io/BytesBuffer.hx | 12 ++- std/haxe/io/BytesData.hx | 2 +- std/haxe/io/BytesInput.hx | 6 +- std/haxe/io/Float32Array.hx | 102 ++++++++++++++++++ std/haxe/io/Input.hx | 2 +- std/haxe/io/Uint8Array.hx | 102 ++++++++++++++++++ std/js/_std/haxe/io/Bytes.hx | 24 +++-- .../src/unitstd/haxe/io/Float32Array.unit.hx | 52 +++++++++ .../src/unitstd/haxe/io/Uint8Array.unit.hx | 55 ++++++++++ 10 files changed, 404 insertions(+), 16 deletions(-) create mode 100644 std/haxe/io/ArrayBufferView.hx create mode 100644 std/haxe/io/Float32Array.hx create mode 100644 std/haxe/io/Uint8Array.hx create mode 100644 tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx create mode 100644 tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx diff --git a/std/haxe/io/ArrayBufferView.hx b/std/haxe/io/ArrayBufferView.hx new file mode 100644 index 00000000000..4c66e57faae --- /dev/null +++ b/std/haxe/io/ArrayBufferView.hx @@ -0,0 +1,63 @@ +package haxe.io; + +typedef ArrayBufferViewData = #if js js.html.ArrayBufferView #else ArrayBufferViewImpl #end + +#if !js +class ArrayBufferViewImpl { + public var bytes : haxe.io.Bytes; + public var byteOffset : Int; + public var byteLength : Int; + public function new(bytes, pos, length) { + this.bytes = bytes; + this.byteOffset = pos; + this.byteLength = length; + } + public function sub( begin : Int, ?length : Int ) { + if( length == null ) length = byteLength - begin; + if( begin < 0 || length < 0 || begin + length > byteLength ) throw Error.OutsideBounds; + return new ArrayBufferViewImpl(bytes, byteOffset + begin, length); + } +} +#end + +abstract ArrayBufferView(ArrayBufferViewData) { + + public var buffer(get,never) : haxe.io.Bytes; + public var byteOffset(get, never) : Int; + public var byteLength(get, never) : Int; + + public inline function new( size : Int ) { + #if js + this = new js.html.Uint8Array(size); + #else + this = new ArrayBufferViewData(haxe.io.Bytes.alloc(size), 0, size); + #end + } + + inline function get_byteOffset() return this.byteOffset; + inline function get_byteLength() return this.byteLength; + function get_buffer() : haxe.io.Bytes { + #if js + return haxe.io.Bytes.ofData(this.buffer); + #else + return this.bytes; + #end + } + + public inline function sub( begin : Int, ?length : Int ) { + #if js + return fromData(new js.html.Uint8Array(this.buffer.slice(begin, length == null ? null : begin+length))); + #else + return fromData(this.sub(begin,length)); + #end + } + + public inline function getData() : ArrayBufferViewData { + return this; + } + + public static inline function fromData( a : ArrayBufferViewData ) : ArrayBufferView { + return cast a; + } + +} \ No newline at end of file diff --git a/std/haxe/io/BytesBuffer.hx b/std/haxe/io/BytesBuffer.hx index 87b076384b3..d2f80c3ce3b 100644 --- a/std/haxe/io/BytesBuffer.hx +++ b/std/haxe/io/BytesBuffer.hx @@ -102,6 +102,11 @@ class BytesBuffer { b.Write(src.getData(), 0, src.length); #elseif java b.write(src.getData(), 0, src.length); + #elseif js + var b1 = b; + var b2 = @:privateAccess src.b; + for( i in 0...src.length ) + b.push(b2[i]); #else var b1 = b; var b2 = src.getData(); @@ -158,6 +163,11 @@ class BytesBuffer { b.Write(src.getData(), pos, len); #elseif java b.write(src.getData(), pos, len); + #elseif js + var b1 = b; + var b2 = @:privateAccess src.b; + for( i in pos...pos+len ) + b.push(b2[i]); #else var b1 = b; var b2 = src.getData(); @@ -189,7 +199,7 @@ class BytesBuffer { var buf = python.lib.Builtin.bytearray(b); var bytes = new Bytes(buf.length, buf); #elseif js - var bytes = new Bytes(b.length,new BytesData(b)); + var bytes = new Bytes(new js.html.Uint8Array(b).buffer); #else var bytes = new Bytes(b.length,b); #end diff --git a/std/haxe/io/BytesData.hx b/std/haxe/io/BytesData.hx index 9f70b141fb5..b350386ecd1 100644 --- a/std/haxe/io/BytesData.hx +++ b/std/haxe/io/BytesData.hx @@ -37,7 +37,7 @@ package haxe.io; #elseif python typedef BytesData = python.lib.ByteArray; #elseif js - typedef BytesData = js.html.Uint8Array; + typedef BytesData = js.html.ArrayBuffer; #else typedef BytesData = Array; #end diff --git a/std/haxe/io/BytesInput.hx b/std/haxe/io/BytesInput.hx index ef50236be4f..b5a4ea1d61c 100644 --- a/std/haxe/io/BytesInput.hx +++ b/std/haxe/io/BytesInput.hx @@ -22,7 +22,7 @@ package haxe.io; class BytesInput extends Input { - var b : BytesData; + var b : #if js js.html.Uint8Array #else BytesData #end; #if !flash9 var pos : Int; var len : Int; @@ -50,7 +50,7 @@ class BytesInput extends Input { this.b = ba; this.b.endian = flash.utils.Endian.LITTLE_ENDIAN; #else - this.b = b.getData(); + this.b = #if js @:privateAccess b.b #else b.getData() #end; this.pos = pos; this.len = len; this.totlen = len; @@ -144,7 +144,7 @@ class BytesInput extends Input { untyped __php__("$buf->b = substr($buf->b, 0, $pos) . substr($this->b, $this->pos, $len) . substr($buf->b, $pos+$len)"); #else var b1 = b; - var b2 = buf.getData(); + var b2 = #if js @:privateAccess buf.b #else buf.getData() #end; for( i in 0...len ) b2[pos+i] = b1[this.pos+i]; #end diff --git a/std/haxe/io/Float32Array.hx b/std/haxe/io/Float32Array.hx new file mode 100644 index 00000000000..07d5684518e --- /dev/null +++ b/std/haxe/io/Float32Array.hx @@ -0,0 +1,102 @@ +/* + * Copyright (C)2005-2015 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.io; + +typedef Float32ArrayData = #if js js.html.Float32Array #else ArrayBufferView.ArrayBufferViewData #end + +abstract Float32Array(Float32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + #if js + this = new Float32ArrayData(elements); + #else + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + #end + } + + inline function get_length() { + #if js + return this.length; + #else + return this.byteLength >> 2; + #end + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Float { + #if js + return this[index]; + #else + return this.bytes.getFloat((index<<2) + this.byteOffset); + #end + } + + @:arrayAccess public inline function set( index : Int, value : Float ) : Float { + #if js + return this[index] = value; + #else + if( index >= 0 && index < length ) { + this.bytes.setFloat((index<<2) + this.byteOffset, value); + return value; + } + return 0; + #end + } + + public inline function sub( begin : Int, ?length : Int ) { + #if js + return fromData(this.subarray(begin, length == null ? null : begin+length)); + #else + return fromData(this.sub(begin<<2,length<<2)); + #end + } + + public inline function getData() : Float32ArrayData { + return this; + } + + public static function fromData( d : Float32ArrayData ) : Float32Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length ) : Float32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + #if js + if( pos == 0 && length == a.length ) + return fromData(new Float32ArrayData(a)); + #end + var i = new Float32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + +} + diff --git a/std/haxe/io/Input.hx b/std/haxe/io/Input.hx index a44ffc94064..b1f9ff5b1a0 100644 --- a/std/haxe/io/Input.hx +++ b/std/haxe/io/Input.hx @@ -60,7 +60,7 @@ class Input { **/ public function readBytes( s : Bytes, pos : Int, len : Int ) : Int { var k = len; - var b = s.getData(); + var b = #if js @:privateAccess s.b #else s.getData() #end; if( pos < 0 || len < 0 || pos + len > s.length ) throw Error.OutsideBounds; while( k > 0 ) { diff --git a/std/haxe/io/Uint8Array.hx b/std/haxe/io/Uint8Array.hx new file mode 100644 index 00000000000..3c1b8a69c60 --- /dev/null +++ b/std/haxe/io/Uint8Array.hx @@ -0,0 +1,102 @@ +/* + * Copyright (C)2005-2015 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.io; + +typedef Uint8ArrayData = #if js js.html.Uint8Array #else ArrayBufferView.ArrayBufferViewData #end + +abstract Uint8Array(Uint8ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 1; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + #if js + this = new Uint8ArrayData(elements * BYTES_PER_ELEMENT); + #else + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + #end + } + + inline function get_length() { + #if js + return this.length; + #else + return this.byteLength; + #end + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) { + #if js + return this[index]; + #else + return this.bytes.get(index + this.byteOffset); + #end + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + #if js + return this[index] = value; + #else + if( index >= 0 && index < length ) { + this.bytes.set(index + this.byteOffset, value); + return value; + } + return 0; + #end + } + + public inline function sub( begin : Int, ?length : Int ) { + #if js + return fromData(this.subarray(begin, length == null ? null : begin+length)); + #else + return fromData(this.sub(begin,length)); + #end + } + + public inline function getData() : Uint8ArrayData { + return this; + } + + public static function fromData( d : Uint8ArrayData ) : Uint8Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length ) : Uint8Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + #if js + if( pos == 0 && length == a.length ) + return fromData(new Uint8ArrayData(a)); + #end + var i = new Uint8Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + +} + diff --git a/std/js/_std/haxe/io/Bytes.hx b/std/js/_std/haxe/io/Bytes.hx index 8811ab9a31b..57e8595d984 100644 --- a/std/js/_std/haxe/io/Bytes.hx +++ b/std/js/_std/haxe/io/Bytes.hx @@ -26,12 +26,13 @@ import js.html.compat.Uint8Array; class Bytes { public var length(default,null) : Int; - var b : BytesData; + var b : js.html.Uint8Array; var data : js.html.DataView; - function new(length:Int,b:BytesData) { - this.length = length; - this.b = b; + function new(b:BytesData) { + this.length = b.byteLength; + this.b = new js.html.Uint8Array(b); + untyped b.hxBytes = this; } public inline function get( pos : Int ) : Int { @@ -57,7 +58,7 @@ class Bytes { public function sub( pos : Int, len : Int ) : Bytes { if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds; - return new Bytes(len,new BytesData(b.buffer.slice(pos+b.byteOffset,pos+b.byteOffset+len))); + return new Bytes(b.buffer.slice(pos+b.byteOffset,pos+b.byteOffset+len)); } public function compare( other : Bytes ) : Int { @@ -159,11 +160,11 @@ class Bytes { } public inline function getData() : BytesData { - return b; + return b.buffer; } public static function alloc( length : Int ) : Bytes { - return new Bytes(length,new BytesData(length)); + return new Bytes(new BytesData(length)); } public static function ofString( s : String ) : Bytes { @@ -191,15 +192,18 @@ class Bytes { a.push( 0x80 | (c & 63) ); } } - return new Bytes(a.length,new BytesData(a)); + return new Bytes(new js.html.Uint8Array(a).buffer); } public static function ofData( b : BytesData ) : Bytes { - return new Bytes(b.length,b); + var hb = untyped b.hxBytes; + if( hb != null ) return hb; + return new Bytes(b); } public inline static function fastGet( b : BytesData, pos : Int ) : Int { - return b[pos]; + // this requires that we have wrapped it with haxe.io.Bytes beforehand + return untyped b.bytes[pos]; } } diff --git a/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx new file mode 100644 index 00000000000..a06cf5f2a85 --- /dev/null +++ b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx @@ -0,0 +1,52 @@ +var b = new haxe.io.Float32Array(5); +b[0] == 0; +b[4] == 0; +b.length == 5; + +// check float write +b[1] = 1.25; +b[1] == 1.25; + +// check loss of precision +b[1] = 8589934592.; +b[1] == 8589934592.; + +// set +for( i in 0...5 ) + b[i] = i + 1; +b[0] == 1; +b[4] == 5; + +// access outside bounds is unspecified but should not crash +try b[-1] catch( e : Dynamic ) {}; +try b[5] catch(e : Dynamic) {}; + +// same for writing +try b[-1] = 55 catch( e : Dynamic ) {}; +try b[5] = 55 catch(e : Dynamic) {}; + +var b2 = b.sub(1,3); +b2[0] == 2; +b2[2] == 4; +b2.length == 3; + +// check memory sharing +b2[0] = 0xCC; +b2[0] == 0xCC; +b[1] == 0xCC; + +// should we allow writing past bounds ? +try b2[-1] = 0xBB catch( e : Dynamic ) {}; +b[0] == 1; + +try b2[3] = 0xBB catch( e : Dynamic ) {}; +b[4] == 5; + + +b.view == b.view; // no alloc + +b.view.buffer == b2.view.buffer; +b.view.byteLength == 20; +b.view.byteOffset == 0; +b2.view.byteLength == 12; +b2.view.byteOffset == 4; diff --git a/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx new file mode 100644 index 00000000000..1a52af3e0da --- /dev/null +++ b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx @@ -0,0 +1,55 @@ +var b = new haxe.io.Uint8Array(5); +b[0] == 0; +b[4] == 0; +b.length == 5; + +// check write mod 255 +b[0] = 513; +b[0] == 1; +b[0] = -2; +b[0] == 254; + +// vheck write for big int +b[1] = 65535 * 65534 * 65533; +b[1] == 0xFA; + +// set +for( i in 0...5 ) + b[i] = i + 1; +b[0] == 1; +b[4] == 5; + +// access outside bounds is unspecified but should not crash +try b[-1] catch( e : Dynamic ) {}; +try b[5] catch(e : Dynamic) {}; + +// same for writing +try b[-1] = 55 catch( e : Dynamic ) {}; +try b[5] = 55 catch(e : Dynamic) {}; + +var b2 = b.sub(1,3); +b2[0] == 2; +b2[2] == 4; +b2.length == 3; + +// check memory sharing +b2[0] = 0xCC; +b2[0] == 0xCC; +b[1] == 0xCC; + +// should we allow writing past bounds ? +try b2[-1] = 0xBB catch( e : Dynamic ) {}; +b[0] == 1; + +try b2[3] = 0xBB catch( e : Dynamic ) {}; +b[4] == 5; + +b.view == b.view; // no alloc + +b.view.buffer == b2.view.buffer; +b.view.byteLength == 5; +b.view.byteOffset == 0; +b2.view.byteLength == 3; +b2.view.byteOffset == 1; + + From 2b77352731e7d77739e1f045231a835db545096e Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 1 Feb 2015 14:03:17 +0100 Subject: [PATCH 2/7] disabled polygonalDS tests until we merge #3827 --- tests/RunCi.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/RunCi.hx b/tests/RunCi.hx index 9be02f9c035..be8fc162289 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -592,7 +592,7 @@ class RunCi { getCppDependencies(); //getOpenFLDependencies(); - testPolygonalDs(); + //testPolygonalDs(); // if (systemName == "Linux") testFlambe(); //#3439 testHxTemplo(); testMUnit(); From a9907d7535c24d9c23a210cf27d93cc200d5478e Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 1 Feb 2015 14:26:25 +0100 Subject: [PATCH 3/7] more arraybuffer compat support --- std/js/html/compat/ArrayBuffer.hx | 9 +++++++-- std/js/html/compat/Uint8Array.hx | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/std/js/html/compat/ArrayBuffer.hx b/std/js/html/compat/ArrayBuffer.hx index a42cf464ffe..4fa69f9965b 100644 --- a/std/js/html/compat/ArrayBuffer.hx +++ b/std/js/html/compat/ArrayBuffer.hx @@ -31,8 +31,13 @@ class ArrayBuffer { if( Std.is(a,Array) ) { this.a = a; byteLength = a.length; - } else - throw "TODO"; + } else { + var len : Int = a; + this.a = []; + for( i in 0...len ) + this.a[i] = 0; + byteLength = len; + } } public function slice(begin,?end) { diff --git a/std/js/html/compat/Uint8Array.hx b/std/js/html/compat/Uint8Array.hx index c403a84789f..c752fa12c91 100644 --- a/std/js/html/compat/Uint8Array.hx +++ b/std/js/html/compat/Uint8Array.hx @@ -60,7 +60,7 @@ class Uint8Array { arr.buffer = new ArrayBuffer(arr); } } else - throw "TODO"; + throw "TODO "+arg1; untyped { arr.subarray = _subarray; arr.set = _set; From 3d7763a740bef5053a7d8a9534e5da8bfc173177 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 1 Feb 2015 22:17:37 +0100 Subject: [PATCH 4/7] more js.html.compat + detect nodeJS typedarray support --- std/haxe/io/Float32Array.hx | 2 + std/js/html/compat/ArrayBuffer.hx | 2 +- std/js/html/compat/Float32Array.hx | 107 +++++++++++++++++++++++++++++ std/js/html/compat/Uint8Array.hx | 4 +- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 std/js/html/compat/Float32Array.hx diff --git a/std/haxe/io/Float32Array.hx b/std/haxe/io/Float32Array.hx index 07d5684518e..eb65e471c8d 100644 --- a/std/haxe/io/Float32Array.hx +++ b/std/haxe/io/Float32Array.hx @@ -21,6 +21,8 @@ */ package haxe.io; +import js.html.compat.Float32Array; + typedef Float32ArrayData = #if js js.html.Float32Array #else ArrayBufferView.ArrayBufferViewData #end abstract Float32Array(Float32ArrayData) { diff --git a/std/js/html/compat/ArrayBuffer.hx b/std/js/html/compat/ArrayBuffer.hx index 4fa69f9965b..f6db18c98cc 100644 --- a/std/js/html/compat/ArrayBuffer.hx +++ b/std/js/html/compat/ArrayBuffer.hx @@ -53,7 +53,7 @@ class ArrayBuffer { } static function __init__() untyped { - var ArrayBuffer = __js__('typeof(window) != "undefined" && window.ArrayBuffer') || ArrayBuffer; + var ArrayBuffer = __js__('typeof(window) != "undefined" && window.ArrayBuffer') || __js__('typeof(global) != "undefined" && global.ArrayBuffer') || ArrayBuffer; if( ArrayBuffer.prototype.slice == null ) ArrayBuffer.prototype.slice = sliceImpl; // IE10 } } \ No newline at end of file diff --git a/std/js/html/compat/Float32Array.hx b/std/js/html/compat/Float32Array.hx new file mode 100644 index 00000000000..607063c8575 --- /dev/null +++ b/std/js/html/compat/Float32Array.hx @@ -0,0 +1,107 @@ +/* + * Copyright (C)2005-2014 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 js.html.compat; + +@:keep +class Float32Array { + + static var BYTES_PER_ELEMENT = 4; + + static function _new( ?arg1 : Dynamic, ?offset : Int, ?length : Int ) { + var arr : Array; + if( untyped __typeof__(arg1) == 'number' ) { + arr = new Array(); + for( i in 0...arg1 ) + arr[i] = 0; + untyped { + arr.byteLength = arr.length << 2; + arr.byteOffset = 0; + arr.buffer = new ArrayBuffer([for( i in 0...arr.length << 2 ) 0]); // no sync + } + } else if( Std.is(arg1,ArrayBuffer) ) { + var buffer : ArrayBuffer = arg1; + if( offset == null ) offset = 0; + if( length == null ) length = (buffer.byteLength - offset) >> 2; + arr = []; + // decode buffer + for( i in 0...length ) { + var val = untyped buffer.a[offset++] | (buffer.a[offset++] << 8) | (buffer.a[offset++] << 16) | (buffer.a[offset++] << 24); + arr.push(haxe.io.FPHelper.i32ToFloat(val)); + } + untyped { + arr.byteLength = arr.length<<2; + arr.byteOffset = offset; + arr.buffer = buffer; + } + } else if( Std.is(arg1, Array) ) { + arr = (arg1 : Array).copy(); + // loss of memory sync between buffer and array + var buffer = []; + for( f in arr ) { + var i = haxe.io.FPHelper.floatToI32(f); + buffer.push(i&0xFF); + buffer.push((i>>8)&0xFF); + buffer.push((i>>16)&0xFF); + buffer.push(i>>>24); + } + untyped { + arr.byteLength = arr.length << 2; + arr.byteOffset = 0; + arr.buffer = new ArrayBuffer(buffer); + } + } else + throw "TODO "+arg1; + untyped { + arr.subarray = _subarray; + arr.set = _set; + } + return arr; + } + + static function _set( ?arg : Dynamic, ?offset : Int ) { + var t : Dynamic = untyped __js__("this"); + if( Std.is(arg.buffer,ArrayBuffer) ) { + var a : Array = arg; + if( arg.byteLength + offset > t.byteLength ) + throw "set() outside of range"; + for( i in 0...arg.byteLength ) + t[i + offset] = a[i]; + } else if( Std.is(arg,Array) ) { + var a : Array = arg; + if( a.length + offset > t.byteLength ) + throw "set() outside of range"; + for( i in 0...a.length ) + t[i + offset] = a[i]; + } else + throw "TODO"; + } + + static function _subarray( start : Int, ?end : Int ) { + var t : Dynamic = untyped __js__("this"); + return _new(t.slice(start,end)); + } + + static function __init__() untyped { + var Float32Array = __js__('typeof(window) != "undefined" && window.Float32Array') || (__js__('typeof(global) != "undefined" && global.Float32Array')) || _new; + } + +} \ No newline at end of file diff --git a/std/js/html/compat/Uint8Array.hx b/std/js/html/compat/Uint8Array.hx index c752fa12c91..9d12a47f6e3 100644 --- a/std/js/html/compat/Uint8Array.hx +++ b/std/js/html/compat/Uint8Array.hx @@ -88,11 +88,11 @@ class Uint8Array { static function _subarray( start : Int, ?end : Int ) { var t : Dynamic = untyped __js__("this"); - return _new(t.buffer, start + t.byteOffset, (end == null ? null : end - start)); + return _new(t.slice(start,end)); } static function __init__() untyped { - var Uint8Array = __js__('typeof(window) != "undefined" && window.Uint8Array') || _new; + var Uint8Array = __js__('typeof(window) != "undefined" && window.Uint8Array') || (__js__('typeof(global) != "undefined" && global.Uint8Array')) || _new; } } \ No newline at end of file From dcf67c32575e81b8757fd452372e688432f019d8 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 1 Feb 2015 22:47:06 +0100 Subject: [PATCH 5/7] oops --- std/haxe/io/Float32Array.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/haxe/io/Float32Array.hx b/std/haxe/io/Float32Array.hx index eb65e471c8d..bf0a826e216 100644 --- a/std/haxe/io/Float32Array.hx +++ b/std/haxe/io/Float32Array.hx @@ -21,7 +21,9 @@ */ package haxe.io; +#if js import js.html.compat.Float32Array; +#end typedef Float32ArrayData = #if js js.html.Float32Array #else ArrayBufferView.ArrayBufferViewData #end From 06068a529896ad40066cb3a5796fcb8c834925d4 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Mon, 2 Feb 2015 00:10:19 +0100 Subject: [PATCH 6/7] more work on ie8-9 emulation --- std/haxe/io/ArrayBufferView.hx | 5 +++++ std/haxe/io/Uint8Array.hx | 2 +- .../src/unitstd/haxe/io/Float32Array.unit.hx | 19 +++++++++++++------ .../src/unitstd/haxe/io/Uint8Array.unit.hx | 13 +++++++++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/std/haxe/io/ArrayBufferView.hx b/std/haxe/io/ArrayBufferView.hx index 4c66e57faae..f2ed71294a1 100644 --- a/std/haxe/io/ArrayBufferView.hx +++ b/std/haxe/io/ArrayBufferView.hx @@ -22,6 +22,11 @@ class ArrayBufferViewImpl { abstract ArrayBufferView(ArrayBufferViewData) { + public static var EMULATED(get,never) : Bool; + static #if !js inline #end function get_EMULATED() { + return #if js (cast js.html.ArrayBuffer) == js.html.compat.ArrayBuffer #else false #end; + } + public var buffer(get,never) : haxe.io.Bytes; public var byteOffset(get, never) : Int; public var byteLength(get, never) : Int; diff --git a/std/haxe/io/Uint8Array.hx b/std/haxe/io/Uint8Array.hx index 3c1b8a69c60..32a7d57f50f 100644 --- a/std/haxe/io/Uint8Array.hx +++ b/std/haxe/io/Uint8Array.hx @@ -59,7 +59,7 @@ abstract Uint8Array(Uint8ArrayData) { @:arrayAccess public inline function set( index : Int, value : Int ) : Int { #if js - return this[index] = value; + return this[index] = value & 0xFF; // &0xFF necessary for html compat #else if( index >= 0 && index < length ) { this.bytes.set(index + this.byteOffset, value); diff --git a/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx index a06cf5f2a85..48aa8ce64e5 100644 --- a/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx +++ b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx @@ -1,3 +1,6 @@ + +var emulated = haxe.io.ArrayBufferView.EMULATED; + var b = new haxe.io.Float32Array(5); b[0] == 0; b[4] == 0; @@ -7,9 +10,11 @@ b.length == 5; b[1] = 1.25; b[1] == 1.25; -// check loss of precision -b[1] = 8589934592.; -b[1] == 8589934592.; +// check loss of precision due to 32 bits +if( !emulated ) { + b[1] = 8589934591.; + b[1] == 8589934592.; +} // set for( i in 0...5 ) @@ -31,9 +36,11 @@ b2[2] == 4; b2.length == 3; // check memory sharing -b2[0] = 0xCC; -b2[0] == 0xCC; -b[1] == 0xCC; +if( !emulated ) { + b2[0] = 0xCC; + b2[0] == 0xCC; + b[1] == 0xCC; +} // should we allow writing past bounds ? try b2[-1] = 0xBB catch( e : Dynamic ) {}; diff --git a/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx index 1a52af3e0da..12e5608dc21 100644 --- a/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx +++ b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx @@ -1,3 +1,6 @@ + +var emulated = haxe.io.ArrayBufferView.EMULATED; + var b = new haxe.io.Uint8Array(5); b[0] == 0; b[4] == 0; @@ -9,7 +12,7 @@ b[0] == 1; b[0] = -2; b[0] == 254; -// vheck write for big int +// check write for big int b[1] = 65535 * 65534 * 65533; b[1] == 0xFA; @@ -33,9 +36,11 @@ b2[2] == 4; b2.length == 3; // check memory sharing -b2[0] = 0xCC; -b2[0] == 0xCC; -b[1] == 0xCC; +if( !emulated ) { + b2[0] = 0xCC; + b2[0] == 0xCC; + b[1] == 0xCC; +} // should we allow writing past bounds ? try b2[-1] = 0xBB catch( e : Dynamic ) {}; From 0c76e7961c676e95bad2e7710cdc888cad5e5e9b Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 15 Feb 2015 11:38:43 +0100 Subject: [PATCH 7/7] final fixes for IE8/9 --- std/js/html/compat/Float32Array.hx | 6 ++++-- std/js/html/compat/Uint8Array.hx | 6 ++++-- tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx | 2 +- tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/std/js/html/compat/Float32Array.hx b/std/js/html/compat/Float32Array.hx index 607063c8575..0e3cb3464c6 100644 --- a/std/js/html/compat/Float32Array.hx +++ b/std/js/html/compat/Float32Array.hx @@ -26,7 +26,7 @@ class Float32Array { static var BYTES_PER_ELEMENT = 4; - static function _new( ?arg1 : Dynamic, ?offset : Int, ?length : Int ) { + static function _new( ?arg1 : Dynamic, ?offset : Int, ?length : Int ) : Dynamic { var arr : Array; if( untyped __typeof__(arg1) == 'number' ) { arr = new Array(); @@ -97,7 +97,9 @@ class Float32Array { static function _subarray( start : Int, ?end : Int ) { var t : Dynamic = untyped __js__("this"); - return _new(t.slice(start,end)); + var a = _new(t.slice(start,end)); + a.byteOffset = start * 4; + return a; } static function __init__() untyped { diff --git a/std/js/html/compat/Uint8Array.hx b/std/js/html/compat/Uint8Array.hx index 9d12a47f6e3..fa0caf45af0 100644 --- a/std/js/html/compat/Uint8Array.hx +++ b/std/js/html/compat/Uint8Array.hx @@ -26,7 +26,7 @@ class Uint8Array { static var BYTES_PER_ELEMENT = 1; - static function _new( ?arg1 : Dynamic, ?offset : Int, ?length : Int ) { + static function _new( ?arg1 : Dynamic, ?offset : Int, ?length : Int ) : Dynamic { var arr; if( untyped __typeof__(arg1) == 'number' ) { arr = new Array(); @@ -88,7 +88,9 @@ class Uint8Array { static function _subarray( start : Int, ?end : Int ) { var t : Dynamic = untyped __js__("this"); - return _new(t.slice(start,end)); + var a = _new(t.slice(start,end)); + a.byteOffset = start; + return a; } static function __init__() untyped { diff --git a/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx index 48aa8ce64e5..19d4f2b69b0 100644 --- a/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx +++ b/tests/unit/src/unitstd/haxe/io/Float32Array.unit.hx @@ -52,7 +52,7 @@ b[4] == 5; b.view == b.view; // no alloc -b.view.buffer == b2.view.buffer; +if( !emulated ) b.view.buffer == b2.view.buffer; b.view.byteLength == 20; b.view.byteOffset == 0; b2.view.byteLength == 12; diff --git a/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx index 12e5608dc21..3eb292f77a9 100644 --- a/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx +++ b/tests/unit/src/unitstd/haxe/io/Uint8Array.unit.hx @@ -51,7 +51,7 @@ b[4] == 5; b.view == b.view; // no alloc -b.view.buffer == b2.view.buffer; +if( !emulated ) b.view.buffer == b2.view.buffer; b.view.byteLength == 5; b.view.byteOffset == 0; b2.view.byteLength == 3;