Browse Source

Merge pull request #3791 from HaxeFoundation/faster_bytes

Added FPHelper to deal with Float/Double to I32/64 conversions in an efficient way
Nicolas Cannasse 10 years ago
parent
commit
c2e1858afb
6 changed files with 414 additions and 269 deletions
  1. 67 16
      std/haxe/io/Bytes.hx
  2. 319 0
      std/haxe/io/FPHelper.hx
  3. 5 122
      std/haxe/io/Input.hx
  4. 8 130
      std/haxe/io/Output.hx
  5. 10 0
      std/js/_std/haxe/io/Bytes.hx
  6. 5 1
      std/neko/NativeString.hx

+ 67 - 16
std/haxe/io/Bytes.hx

@@ -40,7 +40,7 @@ class Bytes {
 
 
 	public inline function get( pos : Int ) : Int {
 	public inline function get( pos : Int ) : Int {
 		#if neko
 		#if neko
-		return untyped __dollar__sget(b,pos);
+		return untyped $sget(b,pos);
 		#elseif flash9
 		#elseif flash9
 		return b[pos];
 		return b[pos];
 		#elseif php
 		#elseif php
@@ -58,7 +58,7 @@ class Bytes {
 
 
 	public inline function set( pos : Int, v : Int ) : Void {
 	public inline function set( pos : Int, v : Int ) : Void {
 		#if neko
 		#if neko
-		untyped __dollar__sset(b,pos,v);
+		untyped $sset(b,pos,v);
 		#elseif flash9
 		#elseif flash9
 		b[pos] = v;
 		b[pos] = v;
 		#elseif php
 		#elseif php
@@ -81,7 +81,7 @@ class Bytes {
 		if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds;
 		if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds;
 		#end
 		#end
 		#if neko
 		#if neko
-		try untyped __dollar__sblit(b,pos,src.b,srcpos,len) catch( e : Dynamic ) throw Error.OutsideBounds;
+		try untyped $sblit(b,pos,src.b,srcpos,len) catch( e : Dynamic ) throw Error.OutsideBounds;
 		#elseif php
 		#elseif php
 		b = untyped __php__("substr($this->b, 0, $pos) . substr($src->b, $srcpos, $len) . substr($this->b, $pos+$len)"); //__call__("substr", b, 0, pos)+__call__("substr", src.b, srcpos, len)+__call__("substr", b, pos+len);
 		b = untyped __php__("substr($this->b, 0, $pos) . substr($src->b, $srcpos, $len) . substr($this->b, $pos+$len)"); //__call__("substr", b, 0, pos)+__call__("substr", src.b, srcpos, len)+__call__("substr", b, pos+len);
 		#elseif flash9
 		#elseif flash9
@@ -207,10 +207,16 @@ class Bytes {
 		return length - other.length;
 		return length - other.length;
 		#end
 		#end
 	}
 	}
-
+	
+	
+	/**
+		Returns the IEEE double precision value at given position (in low endian encoding).
+		Result is unspecified if reading outside of the bounds
+	**/
+	#if (neko_v21 || cpp) inline #end
 	public function getDouble( pos : Int ) : Float {
 	public function getDouble( pos : Int ) : Float {
-		#if neko
-		return untyped Input._double_of_bytes(sub(pos,8).b,false);
+		#if neko_v21
+		return untyped $sgetd(b, pos, false);
 		#elseif flash9
 		#elseif flash9
 		b.position = pos;
 		b.position = pos;
 		return b.readDouble();
 		return b.readDouble();
@@ -218,14 +224,18 @@ class Bytes {
 		if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
 		if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
 		return untyped __global__.__hxcpp_memory_get_double(b,pos);
 		return untyped __global__.__hxcpp_memory_get_double(b,pos);
 		#else
 		#else
-		var b = new haxe.io.BytesInput(this,pos,8);
-		return b.readDouble();
+		return FPHelper.i64ToDouble(getI32(pos),getI32(pos+4));
 		#end
 		#end
 	}
 	}
 
 
+	/**
+		Returns the IEEE single precision value at given position (in low endian encoding).
+		Result is unspecified if reading outside of the bounds
+	**/
+	#if (neko_v21 || cpp) inline #end
 	public function getFloat( pos : Int ) : Float {
 	public function getFloat( pos : Int ) : Float {
-		#if neko
-		return untyped Input._float_of_bytes(sub(pos,4).b,false);
+		#if neko_v21
+		return untyped $sgetf(b, pos, false);
 		#elseif flash9
 		#elseif flash9
 		b.position = pos;
 		b.position = pos;
 		return b.readFloat();
 		return b.readFloat();
@@ -238,9 +248,16 @@ class Bytes {
 		#end
 		#end
 	}
 	}
 
 
+	/**
+		Store the IEEE double precision value at given position in low endian encoding.
+		Result is unspecified if writing outside of the bounds.
+	**/
+	#if neko_v21 inline #end
 	public function setDouble( pos : Int, v : Float ) : Void {
 	public function setDouble( pos : Int, v : Float ) : Void {
-		#if neko
-		untyped $sblit(b, pos, Output._double_bytes(v,false), 0, 8);
+		#if neko_v21
+		untyped $ssetd(b, pos, v, false);
+		#elseif neko
+		untyped $sblit(b, pos, FPHelper._double_bytes(v,false), 0, 8);
 		#elseif flash9
 		#elseif flash9
 		b.position = pos;
 		b.position = pos;
 		b.writeDouble(v);
 		b.writeDouble(v);
@@ -248,13 +265,22 @@ class Bytes {
 		if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
 		if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
 		untyped __global__.__hxcpp_memory_set_double(b,pos,v);
 		untyped __global__.__hxcpp_memory_set_double(b,pos,v);
 		#else
 		#else
-		throw "Not supported";
+		var i = FPHelper.doubleToI64(v);
+		setI32(pos, haxe.Int64.getLow(i));
+		setI32(pos + 4, haxe.Int64.getHigh(i));
 		#end
 		#end
 	}
 	}
 
 
+	/**
+		Store the IEEE single precision value at given position in low endian encoding.
+		Result is unspecified if writing outside of the bounds.
+	**/
+	#if neko_v21 inline #end
 	public function setFloat( pos : Int, v : Float ) : Void {
 	public function setFloat( pos : Int, v : Float ) : Void {
-		#if neko
-		untyped $sblit(b, pos, Output._float_bytes(v,false), 0, 4);
+		#if neko_v21
+		untyped $ssetf(b, pos, v, false);
+		#elseif neko
+		untyped $sblit(b, pos, FPHelper._float_bytes(v,false), 0, 4);
 		#elseif flash9
 		#elseif flash9
 		b.position = pos;
 		b.position = pos;
 		b.writeFloat(v);
 		b.writeFloat(v);
@@ -262,7 +288,32 @@ class Bytes {
 		if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds;
 		if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds;
 		untyped __global__.__hxcpp_memory_set_float(b,pos,v);
 		untyped __global__.__hxcpp_memory_set_float(b,pos,v);
 		#else
 		#else
-		throw "Not supported";
+		setI32(pos, FPHelper.floatToI32(v));
+		#end
+	}
+	
+	/** 
+		Returns the 32 bit integer at given position (in low endian encoding).
+	**/
+	public inline function getI32( pos : Int ) : Int {
+		#if neko_v21
+		return untyped $sget32(b, pos, false);
+		#else
+		return get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
+		#end
+	}
+
+	/**
+		Store the 32 bit integer at given position (in low endian encoding).
+	**/
+	public inline function setI32( pos : Int, value : Int ) : Void {
+		#if neko_v21
+		untyped $sset32(b, pos, value, false);
+		#else
+		set(pos, value);
+		set(pos + 1, value >> 8);
+		set(pos + 2, value >> 16);
+		set(pos + 3, value >>> 24);
 		#end
 		#end
 	}
 	}
 
 

+ 319 - 0
std/haxe/io/FPHelper.hx

@@ -0,0 +1,319 @@
+package haxe.io;
+
+/**
+	Helper that converts between floating point and binary representation.
+	Always works in low-endian encoding.
+**/
+class FPHelper {
+
+	#if !(java || cs)
+	static var i64tmp = Int64.ofInt(0);
+	#end
+
+	#if neko
+		#if neko_v21
+		static var helper = neko.NativeArray.alloc(2);
+		#else
+		static var helperf = neko.NativeString.alloc(4);
+		static var helperd = neko.NativeString.alloc(8);
+		static var _float_of_bytes = neko.Lib.load("std","float_of_bytes",2);
+		static var _double_of_bytes = neko.Lib.load("std","double_of_bytes",2);
+		static var _float_bytes = neko.Lib.load("std","float_bytes",2);
+		static var _double_bytes = neko.Lib.load("std","double_bytes",2);
+		#end
+	#elseif cpp
+		static var helper = haxe.io.Bytes.alloc(8);
+		static var _float_of_bytes = cpp.Lib.load("std","float_of_bytes",2);
+		static var _double_of_bytes = cpp.Lib.load("std","double_of_bytes",2);
+		static var _float_bytes = cpp.Lib.load("std","float_bytes",2);
+		static var _double_bytes = cpp.Lib.load("std","double_bytes",2);
+	#elseif flash9
+		static var helper = {
+			var b = new flash.utils.ByteArray();
+			b.endian = flash.utils.Endian.LITTLE_ENDIAN;
+			b;
+		}
+	#elseif php
+		static var isLittleEndian : Bool = untyped __call__('unpack','S','\x01\x00')[1] == 1;
+	#else
+		static inline var LN2 = 0.6931471805599453; // Math.log(2)
+	#end
+
+	#if neko_v21 inline #end
+	public static function i32ToFloat( i : Int ) : Float {
+		#if neko
+			#if neko_v21
+			return untyped $itof(i);
+			#else
+			var helper = helperf;
+			untyped $sset(helper,0,i&0xFF);
+			untyped $sset(helper,1,(i>>8)&0xFF);
+			untyped $sset(helper,2,(i>>16)&0xFF);
+			untyped $sset(helper,3,i>>>24);
+			return _float_of_bytes(helper,false);
+			#end
+		#elseif cpp
+			// TODO : more direct version
+			var helper = helper;
+			helper.set(0,i);
+			helper.set(1,i>>8);
+			helper.set(2,i>>16);
+			helper.set(3,i>>>24);
+			return _float_of_bytes(helper.getData(),false);
+		#elseif cs
+			var helper = new SingleHelper(0);
+			if( cs.system.BitConverter.IsLittleEndian )
+			{
+				helper.i = i;
+			} else {
+				helper.i = ((i >>> 24) & 0xFF) | (((i >> 16) & 0xFF) << 8) | (((i >> 8) & 0xFF) << 16) | ((i & 0xFF) << 24);
+			}
+
+			return helper.f;
+		#elseif java
+			return java.lang.Float.intBitsToFloat(i);
+		#elseif php
+			return untyped  __call__('unpack', 'f', __call__('pack', 'l', i))[1];
+		#elseif flash9
+			var helper = helper;
+			helper.position = 0;
+			helper.writeUnsignedInt(i);
+			helper.position = 0;
+			return helper.readFloat();
+		#else
+			var sign = 1 - ((i >>> 31) << 1);
+			var exp = (i >>> 23) & 0xFF;
+			var sig = i & 0x7FFFFF;
+			if( sig == 0 && exp == 0 )
+				return 0.0;
+			return sign*(1 + Math.pow(2, -23)*sig) * Math.pow(2, exp-127);
+		#end
+	}
+
+	#if neko_v21 inline #end
+	public static function floatToI32( f : Float ) : Int {
+		#if neko
+			#if neko_v21
+			return untyped $ftoi(f);
+			#else
+			var r = _float_bytes(f,false);
+			return untyped $sget(r,0) | ($sget(r,1)<<8) | ($sget(r,2)<<16) | ($sget(r,3)<<24);
+			#end
+		#elseif cpp
+			// TODO : no allocation version
+			var r = haxe.io.Bytes.ofData(_float_bytes(f,false));
+			return r.getI32(0);
+		#elseif cs
+			var helper = new SingleHelper(f);
+			if( cs.system.BitConverter.IsLittleEndian )
+			{
+				return helper.i;
+			} else {
+				var i = helper.i;
+				return ((i >>> 24) & 0xFF) | (((i >> 16) & 0xFF) << 8) | (((i >> 8) & 0xFF) << 16) | ((i & 0xFF) << 24);
+			}
+		#elseif java
+			return java.lang.Float.floatToRawIntBits(f);
+		#elseif flash9
+			var helper = helper;
+			helper.position = 0;
+			helper.writeFloat(f);
+			helper.position = 0;
+			return helper.readUnsignedInt();
+		#elseif php
+			return untyped __call__('unpack','l',__call__('pack', 'f', f))[1];
+		#else
+			if( f == 0 ) return 0;
+			var af = f < 0 ? -f : f;
+			var exp = Math.round(Math.log(af) / LN2);
+			if( exp < -127 ) exp = -127 else if( exp > 128 ) exp = 128;
+			var sig = Math.round(af / Math.pow(2, exp) * 0x800000) & 0x7FFFFF;
+			return (f < 0 ? 0x80000000 : 0) | ((exp + 127) << 23) | sig;
+		#end
+	}
+
+	#if neko_v21 inline #end
+	public static function i64ToDouble( low : Int, high : Int ) : Float {
+		#if neko
+			#if neko_v21
+			return untyped $itod(low,high);
+			#else
+			var helper = helperd;
+			untyped $sset(helper,0,low&0xFF);
+			untyped $sset(helper,1,(low>>8)&0xFF);
+			untyped $sset(helper,2,(low>>16)&0xFF);
+			untyped $sset(helper,3,low>>>24);
+			untyped $sset(helper,4,high&0xFF);
+			untyped $sset(helper,5,(high>>8)&0xFF);
+			untyped $sset(helper,6,(high>>16)&0xFF);
+			untyped $sset(helper,7,high>>>24);
+			return _double_of_bytes(helper,false);
+			#end
+		#elseif cpp
+			// TODO : more direct version
+			var helper = helper;
+			helper.set(0,low);
+			helper.set(1,low>>8);
+			helper.set(2,low>>16);
+			helper.set(3,low>>>24);
+			helper.set(4,high);
+			helper.set(5,high>>8);
+			helper.set(6,high>>16);
+			helper.set(7,high>>>24);
+			return _double_of_bytes(helper.getData(),false);
+		#elseif cs
+			var helper = new FloatHelper(0);
+			if( cs.system.BitConverter.IsLittleEndian )
+			{
+				helper.i = haxe.Int64.make(high,low);
+			} else {
+				var i1 = high,
+				    i2 = low;
+				var j2 = ((i1 >>> 24) & 0xFF) | (((i1 >> 16) & 0xFF) << 8) | (((i1 >> 8) & 0xFF) << 16) | ((i1 & 0xFF) << 24);
+				var j1 = ((i2 >>> 24) & 0xFF) | (((i2 >> 16) & 0xFF) << 8) | (((i2 >> 8) & 0xFF) << 16) | ((i2 & 0xFF) << 24);
+				helper.i = haxe.Int64.make(j1,j2);
+			}
+			return helper.f;
+		#elseif java
+			return java.lang.Double.longBitsToDouble( Int64.make(high,low) );
+		#elseif flash9
+			var helper = helper;
+			helper.position = 0;
+			helper.writeUnsignedInt(low);
+			helper.writeUnsignedInt(high);
+			helper.position = 0;
+			return helper.readDouble();
+		#elseif php
+			return untyped  __call__('unpack', 'd', __call__('pack', 'ii', isLittleEndian ? low : high, isLittleEndian ? high : low))[1];
+		#else
+			var sign = 1 - ((high >>> 31) << 1);
+			var exp = ((high >> 20) & 0x7FF) - 1023;
+			var sig = (high&0xFFFFF) * 4294967296. + (low>>>31) * 2147483648. + (low&0x7FFFFFFF);
+			if( sig == 0 && exp == -1023 )
+				return 0.0;
+			return sign*(1.0 + Math.pow(2, -52)*sig) * Math.pow(2, exp);
+		#end
+	}
+
+	/**
+		Returns an Int64 representing the bytes representation of the double precision IEEE float value.
+		WARNING : for performance reason, the same Int64 value might be reused every time. Copy its low/high values before calling again.
+	**/
+	#if neko_v21 inline #end
+	public static function doubleToI64( v : Float ) : Int64 {
+		#if neko
+			#if neko_v21
+			var helper = helper, i64 = i64tmp;
+			untyped $dtoi(v,helper);
+			@:privateAccess {
+				i64.low = helper[0];
+				i64.high = helper[1];
+			}
+			return i64;
+			#else
+			var r = _double_bytes(v,false), i64 = i64tmp;
+			@:privateAccess {
+				i64.low = untyped $sget(r,0) | ($sget(r,1)<<8) | ($sget(r,2)<<16) | ($sget(r,3)<<24);
+				i64.high =  untyped $sget(r,4) | ($sget(r,5)<<8) | ($sget(r,6)<<16) | ($sget(r,7)<<24);
+			}
+			return i64;
+			#end
+		#elseif cpp
+			// TODO : no allocation version
+			var r = haxe.io.Bytes.ofData(_double_bytes(v,false)), i64 = i64tmp;
+			@:privateAccess {
+				i64.low = r.getI32(0);
+				i64.high = r.getI32(4);
+			}
+			return i64;
+		#elseif java
+			return java.lang.Double.doubleToRawLongBits(v);
+		#elseif cs
+			var helper = new FloatHelper(v);
+			if( cs.system.BitConverter.IsLittleEndian )
+			{
+				return helper.i;
+			} else {
+				var i = helper.i;
+				var i1 = haxe.Int64.getHigh(i),
+				    i2 = haxe.Int64.getLow(i);
+				var j2 = ((i1 >>> 24) & 0xFF) | (((i1 >> 16) & 0xFF) << 8) | (((i1 >> 8) & 0xFF) << 16) | ((i1 & 0xFF) << 24);
+				var j1 = ((i2 >>> 24) & 0xFF) | (((i2 >> 16) & 0xFF) << 8) | (((i2 >> 8) & 0xFF) << 16) | ((i2 & 0xFF) << 24);
+
+				return haxe.Int64.make(j1,j2);
+			}
+		#elseif flash9
+			var helper = helper;
+			helper.position = 0;
+			helper.writeDouble(v);
+			helper.position = 0;
+			var i64 = i64tmp;
+			@:privateAccess {
+				i64.low = helper.readUnsignedInt();
+				i64.high = helper.readUnsignedInt();
+			}
+			return i64;
+		#elseif php
+			var a = untyped __call__('unpack',isLittleEndian ? 'V2' : 'N2',__call__('pack', 'd', v));
+			var i64 = i64tmp;
+			@:privateAccess {
+				i64.low = a[isLittleEndian ? 1 : 2];
+				i64.high = a[isLittleEndian ? 2 : 1];
+			}
+			return i64;
+		#else
+			var i64 = i64tmp;
+			if( v == 0 ) {
+				@:privateAccess {
+					i64.low = 0;
+					i64.high = 0;
+				}
+			} else {
+				var av = v < 0 ? -v : v;
+				var exp = Math.round(Math.log(av) / LN2);
+				var sig = Math.fround((av / Math.pow(2, exp)) * 4503599627370496.); // 2^52
+				var sig_l = Std.int(sig);
+				var sig_h = Std.int(sig / 4294967296.0);
+				@:privateAccess {
+					i64.low = sig_l;
+					i64.high = (v < 0 ? 0x80000000 : 0) | ((exp + 1023) << 20) | sig_h;
+				}
+			}
+			return i64;
+		#end
+	}
+
+}
+
+#if cs
+@:meta(System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit))
+@:nativeGen @:struct private class SingleHelper
+{
+	@:meta(System.Runtime.InteropServices.FieldOffset(0))
+	public var i:Int;
+	@:meta(System.Runtime.InteropServices.FieldOffset(0))
+	public var f:Single;
+
+	public function new(f:Single)
+	{
+		this.i = 0;
+		this.f = f;
+	}
+}
+
+@:meta(System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit))
+@:nativeGen @:struct private class FloatHelper
+{
+	@:meta(System.Runtime.InteropServices.FieldOffset(0))
+	public var i:haxe.Int64;
+	@:meta(System.Runtime.InteropServices.FieldOffset(0))
+	public var f:Float;
+
+	public function new(f:Float)
+	{
+		this.i = haxe.Int64.ofInt(0);
+		this.f = f;
+	}
+}
+
+#end

+ 5 - 122
std/haxe/io/Input.hx

@@ -190,58 +190,8 @@ class Input {
 
 
 		Endianness is specified by the `bigEndian` property.
 		Endianness is specified by the `bigEndian` property.
 	**/
 	**/
-	public function readFloat() : Float {
-		#if neko
-			return _float_of_bytes(untyped read(4).b,bigEndian);
-		#elseif cpp
-			return _float_of_bytes(read(4).getData(),bigEndian);
-		#elseif php
-			var a = untyped __call__('unpack', 'f', readString(4));
-			return a[1];
-		#elseif cs
-			if (helper == null) helper = new cs.NativeArray(8);
-
-			var helper = helper;
-			if (bigEndian == !cs.system.BitConverter.IsLittleEndian)
-			{
-				helper[0] = readByte();
-				helper[1] = readByte();
-				helper[2] = readByte();
-				helper[3] = readByte();
-			} else {
-				helper[3] = readByte();
-				helper[2] = readByte();
-				helper[1] = readByte();
-				helper[0] = readByte();
-			}
-
-			return cs.system.BitConverter.ToSingle(helper, 0);
-		#elseif java
-			if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8);
-			var helper = helper;
-			helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN);
-
-			helper.put(0, cast readByte());
-			helper.put(1, cast readByte());
-			helper.put(2, cast readByte());
-			helper.put(3, cast readByte());
-
-			return helper.getFloat(0);
-		#else
-			var bytes = [];
-			bytes.push(cast readByte());
-			bytes.push(cast readByte());
-			bytes.push(cast readByte());
-			bytes.push(cast readByte());
-			if (!bigEndian)
-				bytes.reverse();
-			var sign = 1 - ((bytes[0] >> 7) << 1);
-			var exp = (((bytes[0] << 1) & 0xFF) | (bytes[1] >> 7)) - 127;
-			var sig = ((bytes[1] & 0x7F) << 16) | (bytes[2] << 8) | bytes[3];
-			if (sig == 0 && exp == -127)
-				return 0.0;
-			return sign*(1 + Math.pow(2, -23)*sig) * Math.pow(2, exp);
-		#end
+	public #if !(flash || python) inline #end function readFloat() : Float {
+		return FPHelper.i32ToFloat(readInt32());
 	}
 	}
 
 
 	/**
 	/**
@@ -250,76 +200,9 @@ class Input {
 		Endianness is specified by the `bigEndian` property.
 		Endianness is specified by the `bigEndian` property.
 	**/
 	**/
 	public function readDouble() : Float {
 	public function readDouble() : Float {
-		#if neko
-			return _double_of_bytes(untyped read(8).b,bigEndian);
-		#elseif cpp
-			return _double_of_bytes(read(8).getData(),bigEndian);
-		#elseif php
-			var a = untyped __call__('unpack', 'd', readString(8));
-			return a[1];
-		#elseif (flash || js || python)
-		var bytes = [];
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		bytes.push(readByte());
-		if (!bigEndian)
-			bytes.reverse();
-
-		var sign = 1 - ((bytes[0] >> 7) << 1); // sign = bit 0
-		var exp = (((bytes[0] << 4) & 0x7FF) | (bytes[1] >> 4)) - 1023; // exponent = bits 1..11
-		var sig = getDoubleSig(bytes);
-		if (sig == 0 && exp == -1023)
-			return 0.0;
-		return sign * (1.0 + Math.pow(2, -52) * sig) * Math.pow(2, exp);
-		#elseif cs
-		if (helper == null) helper = new cs.NativeArray(8);
-
-		var helper = helper;
-		if (bigEndian == !cs.system.BitConverter.IsLittleEndian)
-		{
-			helper[0] = readByte();
-			helper[1] = readByte();
-			helper[2] = readByte();
-			helper[3] = readByte();
-			helper[4] = readByte();
-			helper[5] = readByte();
-			helper[6] = readByte();
-			helper[7] = readByte();
-		} else {
-			helper[7] = readByte();
-			helper[6] = readByte();
-			helper[5] = readByte();
-			helper[4] = readByte();
-			helper[3] = readByte();
-			helper[2] = readByte();
-			helper[1] = readByte();
-			helper[0] = readByte();
-		}
-
-		return cs.system.BitConverter.ToDouble(helper, 0);
-		#elseif java
-		if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8);
-		var helper = helper;
-		helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN);
-
-		helper.put(0, cast readByte());
-		helper.put(1, cast readByte());
-		helper.put(2, cast readByte());
-		helper.put(3, cast readByte());
-		helper.put(4, cast readByte());
-		helper.put(5, cast readByte());
-		helper.put(6, cast readByte());
-		helper.put(7, cast readByte());
-
-		return helper.getDouble(0);
-		#else
-		return throw "not implemented";
-		#end
+		var i1 = readInt32();
+		var i2 = readInt32();
+		return bigEndian ? FPHelper.i64ToDouble(i2,i1) : FPHelper.i64ToDouble(i1,i2);
 	}
 	}
 
 
 	/**
 	/**

+ 8 - 130
std/haxe/io/Output.hx

@@ -28,7 +28,6 @@ package haxe.io;
 	Output.
 	Output.
 **/
 **/
 class Output {
 class Output {
-	private static var LN2 = Math.log(2);
 
 
 	/**
 	/**
 		Endianness (word byte order) used when writing numbers.
 		Endianness (word byte order) used when writing numbers.
@@ -131,58 +130,8 @@ class Output {
 
 
 		Endianness is specified by the `bigEndian` property.
 		Endianness is specified by the `bigEndian` property.
 	**/
 	**/
-	public function writeFloat( x : Float ) {
-		#if neko
-		write(untyped new Bytes(4,_float_bytes(x,bigEndian)));
-		#elseif cpp
-		write(Bytes.ofData(_float_bytes(x,bigEndian)));
-		#elseif php
-		write(untyped Bytes.ofString(__call__('pack', 'f', x)));
-		#elseif cs
-		var bytes = cs.system.BitConverter.GetBytes(cast(x, Single));
-		if (bigEndian == cs.system.BitConverter.IsLittleEndian)
-		{
-			writeByte(bytes[3]);
-			writeByte(bytes[2]);
-			writeByte(bytes[1]);
-			writeByte(bytes[0]);
-		} else {
-			writeByte(bytes[0]);
-			writeByte(bytes[1]);
-			writeByte(bytes[2]);
-			writeByte(bytes[3]);
-		}
-		#elseif java
-		if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8);
-		var helper = helper;
-		helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN);
-
-		helper.putFloat(0, x);
-		writeByte(untyped helper.get(0));
-		writeByte(untyped helper.get(1));
-		writeByte(untyped helper.get(2));
-		writeByte(untyped helper.get(3));
-		#else
-		if (x == 0.0)
-		{
-			writeByte(0); writeByte(0); writeByte(0); writeByte(0);
-			return;
-		}
-		var exp = Math.floor(Math.log(Math.abs(x)) / LN2);
-		var sig = (Math.floor(Math.abs(x) / Math.pow(2, exp) * (2 << 22)) & 0x7FFFFF);
-		var b4 = (exp + 0x7F) >> 1 | (exp>0 ? ((x<0) ? 1<<7 : 1<<6) : ((x<0) ? 1<<7 : 0)),
-			b3 = (exp + 0x7F) << 7 & 0xFF | (sig >> 16 & 0x7F),
-			b2 = (sig >> 8) & 0xFF,
-			b1 = sig & 0xFF;
-		if (bigEndian)
-		{
-			writeByte(b4); writeByte(b3); writeByte(b2); writeByte(b1);
-		}
-		else
-		{
-			writeByte(b1); writeByte(b2); writeByte(b3); writeByte(b4);
-		}
-		#end
+	public #if !(flash || python) inline #end function writeFloat( x : Float ) {
+		writeInt32(FPHelper.floatToI32(x));
 	}
 	}
 
 
 	/**
 	/**
@@ -191,80 +140,14 @@ class Output {
 		Endianness is specified by the `bigEndian` property.
 		Endianness is specified by the `bigEndian` property.
 	**/
 	**/
 	public function writeDouble( x : Float ) {
 	public function writeDouble( x : Float ) {
-		#if neko
-		write(untyped new Bytes(8,_double_bytes(x,bigEndian)));
-		#elseif cpp
-		write(Bytes.ofData(_double_bytes(x,bigEndian)));
-		#elseif php
-		write(untyped Bytes.ofString(__call__('pack', 'd', x)));
-		#elseif cs
-		var bytes = cs.system.BitConverter.GetBytes(x);
-		if (bigEndian == cs.system.BitConverter.IsLittleEndian)
-		{
-			writeByte(bytes[7]);
-			writeByte(bytes[6]);
-			writeByte(bytes[5]);
-			writeByte(bytes[4]);
-			writeByte(bytes[3]);
-			writeByte(bytes[2]);
-			writeByte(bytes[1]);
-			writeByte(bytes[0]);
+		var i64 = FPHelper.doubleToI64(x);
+		if( bigEndian ) {
+			writeInt32(haxe.Int64.getHigh(i64));
+			writeInt32(haxe.Int64.getLow(i64));
 		} else {
 		} else {
-			writeByte(bytes[0]);
-			writeByte(bytes[1]);
-			writeByte(bytes[2]);
-			writeByte(bytes[3]);
-			writeByte(bytes[4]);
-			writeByte(bytes[5]);
-			writeByte(bytes[6]);
-			writeByte(bytes[7]);
-		}
-		#elseif java
-		if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8);
-		var helper = helper;
-		helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN);
-
-		helper.putDouble(0, x);
-
-		writeByte(untyped helper.get(0));
-		writeByte(untyped helper.get(1));
-		writeByte(untyped helper.get(2));
-		writeByte(untyped helper.get(3));
-		writeByte(untyped helper.get(4));
-		writeByte(untyped helper.get(5));
-		writeByte(untyped helper.get(6));
-		writeByte(untyped helper.get(7));
-		#else
-		if (x == 0.0)
-		{
-			writeByte(0); writeByte(0); writeByte(0); writeByte(0);
-			writeByte(0); writeByte(0); writeByte(0); writeByte(0);
-			return;
+			writeInt32(haxe.Int64.getLow(i64));
+			writeInt32(haxe.Int64.getHigh(i64));
 		}
 		}
-
-		var exp = Math.floor(Math.log(Math.abs(x)) / LN2);
-		var sig : Int = Math.floor(Math.abs(x) / Math.pow(2, exp) * Math.pow(2, 52));
-		var sig_h = (sig & cast 34359738367);
-		var sig_l = Math.floor((sig / Math.pow(2,32)));
-		var b8 = (exp + 0x3FF) >> 4 | (exp>0 ? ((x<0) ? 1<<7 : 1<<6) : ((x<0) ? 1<<7 : 0)),
-			b7 = (exp + 0x3FF) << 4 & 0xFF | (sig_l >> 16 & 0xF),
-			b6 = (sig_l >> 8) & 0xFF,
-			b5 = sig_l & 0xFF,
-			b4 = (sig_h >> 24) & 0xFF,
-			b3 = (sig_h >> 16) & 0xFF,
-			b2 = (sig_h >> 8) & 0xFF,
-			b1 = sig_h & 0xFF;
-		if (bigEndian)
-		{
-			writeByte(b8); writeByte(b7); writeByte(b6); writeByte(b5);
-			writeByte(b4); writeByte(b3); writeByte(b2); writeByte(b1);
-		}
-		else
-		{
-			writeByte(b1); writeByte(b2); writeByte(b3); writeByte(b4);
-			writeByte(b5); writeByte(b6); writeByte(b7); writeByte(b8);
-		}
-		#end
 	}
 	}
 
 
 	/**
 	/**
@@ -400,14 +283,9 @@ class Output {
 	}
 	}
 
 
 #if neko
 #if neko
-	static var _float_bytes = neko.Lib.load("std","float_bytes",2);
-	static var _double_bytes = neko.Lib.load("std","double_bytes",2);
 	static function __init__() untyped {
 	static function __init__() untyped {
 		Output.prototype.bigEndian = false;
 		Output.prototype.bigEndian = false;
 	}
 	}
-#elseif cpp
-	static var _float_bytes = cpp.Lib.load("std","float_bytes",2);
-	static var _double_bytes = cpp.Lib.load("std","double_bytes",2);
 #end
 #end
 
 
 }
 }

+ 10 - 0
std/js/_std/haxe/io/Bytes.hx

@@ -93,7 +93,17 @@ class Bytes {
 		initData();
 		initData();
 		data.setFloat32(pos, v, true);
 		data.setFloat32(pos, v, true);
 	}
 	}
+	
+	public function getI32( pos : Int ) : Int {
+		initData();
+		return data.getInt32(pos);
+	}
 
 
+	public function setI32( pos : Int, value : Int ) : Void {
+		initData();
+		data.setInt32(pos, value);
+	}
+	
 	public function getString( pos : Int, len : Int ) : String {
 	public function getString( pos : Int, len : Int ) : String {
 		if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
 		if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
 		var s = "";
 		var s = "";

+ 5 - 1
std/neko/NativeString.hx

@@ -32,7 +32,11 @@ class NativeString {
 	}
 	}
 
 
 	public static inline function length( s : NativeString ) : Int {
 	public static inline function length( s : NativeString ) : Int {
-		return untyped __dollar__ssize(s);
+		return untyped $ssize(s);
+	}
+	
+	public static inline function alloc( size : Int ) : NativeString {
+		return untyped $smake(size);
 	}
 	}
 
 
 }
 }