Skip to content

Instantly share code, notes, and snippets.

@frabbit
Last active November 14, 2016 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frabbit/7aa259971419b30655f8b920ff31c672 to your computer and use it in GitHub Desktop.
Save frabbit/7aa259971419b30655f8b920ff31c672 to your computer and use it in GitHub Desktop.
ByteArray haxe
// fast byte access without class overhead and bounds checks like in haxe.io.Bytes
package haxe.io;
@:coreType abstract ByteArray {
public static var getIsChecked:Bool; // flags can be used in bytes to remove unnecessary or multiple bounds checks on different targets
public static var setIsChecked:Bool;
public static var blitCanThrow:Bool; // throws are neko specific flags, can be used in bytes to remove a bounds check
public static var subCanThrow:Bool;
public static var getStringCanThrow:Bool;
public var length(get,never) : Int;
public function new ():Void;
public function getData ():BytesData;
public static function ofData (data:BytesData):ByteArray;
function get_length() : Int;
public function get( pos : Int ) : Int;
public function set( pos : Int, v : Int ) : Void;
public function blit( pos : Int, src : ByteArray, srcpos : Int, len : Int ) : Void;
public function fill( pos : Int, len : Int, value : Int ):Void;
public function sub( pos : Int, len : Int ) : ByteArray;
public function compare( other : ByteArray ) : Int;
public function getDouble( pos : Int ) : Float;
public function getFloat( pos : Int ) : Float;
public function setDouble( pos : Int, v : Float ) : Void;
public function setFloat( pos : Int, v : Float ) : Void;
public function getUInt16( pos : Int ) : Int;
public function setUInt16( pos : Int, v : Int ) : Void;
public function getInt32( pos : Int ) : Int;
public function getInt64( pos : Int ) : haxe.Int64;
public function setInt32( pos : Int, v : Int ) : Void;
public function setInt64( pos : Int, v : haxe.Int64 ) : Void;
public function getString( pos : Int, len : Int ) : String;
public function toString() : String;
public static function alloc( length : Int ) : ByteArray;
public static function ofString( s : String ) : ByteArray;
}
// this is the implementation for cpp (java, c#, neko etc. are quite similar)
package haxe.io;
using cpp.NativeArray;
private typedef ByteArrayImpl = BytesData;
abstract ByteArray(ByteArrayImpl) {
public static inline var getIsChecked = false;
public static inline var setIsChecked = false;
public static inline var blitCanThrow = false;
public static inline var subCanThrow = false;
public static inline var getStringCanThrow = false;
public var length(get,never) : Int;
inline function new (impl:ByteArrayImpl) {
this = impl;
}
public inline function getData ():BytesData {
return this;
}
inline function raw () return this;
public static inline function ofData (data:BytesData) {
return mk(data);
}
inline function get_length ():Int {
return untyped this.length;
}
static inline function mk (data:ByteArrayImpl):ByteArray {
return new ByteArray(data);
}
public inline function get( pos : Int ) : Int {
return untyped this.unsafeGet(pos);
}
public inline function set( pos : Int, v : Int ) : Void {
untyped this[pos] = v;
}
public inline function blit( pos : Int, src : ByteArray, srcpos : Int, len : Int ) : Void {
this.blit(pos, src.raw(), srcpos, len);
}
public inline function fill( pos : Int, len : Int, value : Int ):Void {
untyped __global__.__hxcpp_memory_memset(this,pos,len,value);
}
public inline function sub( pos : Int, len : Int ) : ByteArray {
return mk(this.slice(pos,pos+len));
}
public inline function compare( other : ByteArray ) : Int {
return this.memcmp(other.raw());
}
public inline function getDouble( pos : Int ) : Float {
return untyped __global__.__hxcpp_memory_get_double(this,pos);
}
public inline function getFloat( pos : Int ) : Float {
return untyped __global__.__hxcpp_memory_get_float(this,pos);
}
public inline function setDouble( pos : Int, v : Float ) : Void {
untyped __global__.__hxcpp_memory_set_double(this,pos,v);
}
public inline function setFloat( pos : Int, v : Float ) : Void {
untyped __global__.__hxcpp_memory_set_float(this,pos,v);
}
public inline function getUInt16( pos : Int ) : Int {
return get(pos) | (get(pos + 1) << 8);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
set(pos, v);
set(pos + 1, v >> 8);
}
public inline function getInt32( pos : Int ) : Int {
return get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
}
public inline function getInt64( pos : Int ) : haxe.Int64 {
return haxe.Int64.make(getInt32(pos+4),getInt32(pos));
}
public inline function setInt32( pos : Int, v : Int ) : Void {
set(pos, v);
set(pos + 1, v >> 8);
set(pos + 2, v >> 16);
set(pos + 3, v >>> 24);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
setInt32(pos, v.low);
setInt32(pos + 4, v.high);
}
public function getString( pos : Int, len : Int ) : String {
var result:String="";
untyped __global__.__hxcpp_string_of_bytes(this,result,pos,len);
return result;
}
public inline function toString() : String {
return getString(0,length);
}
public static function alloc( length : Int ) : ByteArray {
var a = new ByteArrayImpl();
if (length>0) cpp.NativeArray.setSize(a, length);
return mk(a);
}
public static function ofString( s : String ) : ByteArray {
var a = new ByteArrayImpl();
untyped __global__.__hxcpp_bytes_of_string(a,s);
return mk(a);
}
}
// The new default implementation for Bytes (hl and js have their own to avoid indirection). Very
// clean compared to the current one.
package haxe.io;
class Bytes {
public var length(default,null) : Int;
var b : ByteArray;
function new(b) {
this.b = b;
this.length = b.length;
}
inline function out(pos:Int) : Bool {
return (pos:UInt) >= (length:UInt);
}
public inline function get( pos : Int ) : Int {
return if (ByteArray.getIsChecked && out(pos)) 0 else b.get(pos);
}
public inline function set( pos : Int, v : Int ) : Void {
if( ByteArray.setIsChecked && out(pos) ) throw Error.OutsideBounds;
b.set(pos, v);
}
public inline function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
return if (ByteArray.blitCanThrow) {
try b.blit(pos, src.b, srcpos, len) catch (e:Dynamic) throw Error.OutsideBounds;
} else {
if( (pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length) ) throw Error.OutsideBounds;
b.blit(pos, src.b, srcpos, len);
}
}
public inline function fill( pos : Int, len : Int, value : Int ) {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
b.fill(pos, len, value);
}
public inline function sub( pos : Int, len : Int ) : Bytes {
return if (ByteArray.subCanThrow) {
try new Bytes(b.sub(pos, len)) catch (e:Dynamic) throw Error.OutsideBounds;
} else {
if( (pos < 0 || len < 0 || pos + len > length) ) throw Error.OutsideBounds;
new Bytes(b.sub(pos, len));
}
}
public inline function compare( other : Bytes ) : Int {
return b.compare(other.b);
}
public inline function getDouble( pos : Int ) : Float {
if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
return b.getDouble(pos);
}
public inline function getFloat( pos : Int ) : Float {
if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds;
return b.getFloat(pos);
}
public inline function setDouble( pos : Int, v : Float ) : Void {
if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
b.setDouble(pos, v);
}
public inline function setFloat( pos : Int, v : Float ) : Void {
if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds;
b.setFloat(pos, v);
}
public inline function getUInt16( pos : Int ) : Int {
if( pos < 0 || pos + 2 > length ) throw Error.OutsideBounds;
return b.getUInt16(pos);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
if( pos < 0 || pos + 2 > length ) throw Error.OutsideBounds;
b.setUInt16(pos, v);
}
public inline function getInt32( pos : Int ) : Int {
if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds;
return b.getInt32(pos);
}
public inline function getInt64( pos : Int ) : haxe.Int64 {
if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
return b.getInt64(pos);
}
public inline function setInt32( pos : Int, v : Int ) : Void {
if( pos < 0 || pos + 2 > length ) throw Error.OutsideBounds;
b.setInt32(pos, v);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds;
b.setInt64(pos, v);
}
public function getString( pos : Int, len : Int ) : String {
return if (ByteArray.getStringCanThrow) {
try b.getString(pos, len) catch( e : Dynamic ) throw Error.OutsideBounds;
} else {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
b.getString(pos, len);
}
}
@:deprecated("readString is deprecated, use getString instead")
@:noCompletion
public inline function readString(pos:Int, len:Int):String {
return getString(pos, len);
}
@:keep public inline function toString() : String {
return b.toString();
}
public function toHex() : String {
var s = new StringBuf();
var chars = [];
var str = "0123456789abcdef";
for( i in 0...str.length )
chars.push(str.charCodeAt(i));
for( i in 0...length ) {
var c = get(i);
s.addChar(chars[c >> 4]);
s.addChar(chars[c & 15]);
}
return s.toString();
}
public function getData() : BytesData {
return b.getData();
}
public static function alloc( length : Int ) : Bytes {
return new Bytes(ByteArray.alloc(length));
}
@:pure
public static function ofString( s : String ) : Bytes {
return new Bytes(ByteArray.ofString(s));
}
public static function ofData( b : BytesData ) {
return new Bytes(ByteArray.ofData(b));
}
public inline static function fastGet( b : BytesData, pos : Int ) : Int {
// ByteArray.ofData is a noop, targets where is is not the case have their own Bytes implementation
return ByteArray.ofData(b).get(pos);
}
}
// hl ByteArray uses an underlying BytesData object.
package haxe.io;
typedef ByteArrayImpl = haxe.io.BytesData;
abstract ByteArray(ByteArrayImpl) {
public var length(get,never) : Int;
inline function new (impl:ByteArrayImpl) {
this = impl;
}
inline function get_length ():Int {
return this.length;
}
public inline function getData ():BytesData {
return this;
}
inline function raw () return this;
public static inline function ofData (data:BytesData) {
return mk(data);
}
static inline function mk (data:ByteArrayImpl):ByteArray {
return new ByteArray(data);
}
public inline function get( pos : Int ) : Int {
return this.bytes[pos];
}
public inline function set( pos : Int, v : Int ) : Void {
this.bytes[pos] = v;
}
public inline function blit( pos : Int, src : ByteArray, srcpos : Int, len : Int ) : Void {
this.bytes.blit(pos, src.raw().bytes, srcpos, len);
}
public inline function fill( pos : Int, len : Int, value : Int ):Void {
this.bytes.fill(pos, len, value);
}
public inline function sub( pos : Int, len : Int ) : ByteArray {
var impl = new ByteArrayImpl(this.bytes.sub(pos, len), len);
return mk(impl);
}
public function compare( other : ByteArray ) : Int {
var len = length < other.length ? length : other.length;
var r = this.bytes.compare(0, other.raw().bytes, 0, len);
if( r == 0 )
r = length - other.length;
return r;
}
public inline function getDouble( pos : Int ) : Float {
return this.bytes.getF64(pos);
}
public inline function getFloat( pos : Int ) : Float {
return this.bytes.getF32(pos);
}
public inline function setDouble( pos : Int, v : Float ) : Void {
this.bytes.setF64(pos, v);
}
public inline function setFloat( pos : Int, v : Float ) : Void {
this.bytes.setF32(pos, v);
}
public inline function getUInt16( pos : Int ) : Int {
return this.bytes.getUI16(pos);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
this.bytes.setUI16(pos, v);
}
public inline function getInt32( pos : Int ) : Int {
return this.bytes.getI32(pos);
}
public inline function getInt64( pos : Int ) : haxe.Int64 {
return haxe.Int64.make(this.bytes.getI32(pos+4), this.bytes.getI32(pos));
}
public inline function setInt32( pos : Int, v : Int ) : Void {
return this.bytes.setI32(pos, v);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
setInt32(pos + 4, v.high);
setInt32(pos, v.low);
}
public function getString( pos : Int, len : Int ) : String {
var b = new hl.types.Bytes(len + 1);
b.blit(0, this.bytes, pos, len);
b[len] = 0;
return @:privateAccess String.fromUTF8(b);
}
public inline function toString() : String {
return getString(0,length);
}
public static function alloc( length : Int ) : ByteArray {
var b = new hl.types.Bytes(length);
b.fill(0, length, 0);
var impl = new ByteArrayImpl(b, length);
return mk(impl);
}
public static function ofString( s : String ) : ByteArray @:privateAccess {
var size = 0;
var b = s.bytes.utf16ToUtf8(0, size);
var impl = new ByteArrayImpl(b, size);
return mk(impl);
}
public inline function fastGet( pos : Int ) : Int {
return this.bytes[pos];
}
}
// hl version doesn't use the ByteArray to implement Bytes
package haxe.io;
@:coreApi
class Bytes {
public var length(default,null) : Int;
var b : hl.types.Bytes;
function new(b:hl.types.Bytes,length:Int) : Void {
this.b = b;
this.length = length;
}
inline function out(pos:Int) : Bool {
return (pos:UInt) >= (length : UInt);
}
public function get( pos : Int ) : Int {
return if( out(pos) ) 0 else b[pos];
}
public function set( pos : Int, v : Int ) : Void {
if( out(pos) ) throw Error.OutsideBounds;
b[pos] = v;
}
public function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds;
b.blit(pos, src.b, srcpos, len);
}
public function fill( pos : Int, len : Int, value : Int ) : Void {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
b.fill(pos, len, value);
}
public function sub( pos : Int, len : Int ) : Bytes {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
return new Bytes(b.sub(pos, len), len);
}
public function compare( other : Bytes ) : Int {
var len = length < other.length ? length : other.length;
var r = b.compare(0, other.b, 0, len);
if( r == 0 )
r = length - other.length;
return r;
}
public function getDouble( pos : Int ) : Float {
return if( out(pos + 7) ) 0. else b.getF64(pos);
}
public function getFloat( pos : Int ) : Float {
return if( out(pos + 3) ) 0. else b.getF32(pos);
}
public function setDouble( pos : Int, v : Float ) : Void {
if( out(pos + 7) ) throw Error.OutsideBounds;
b.setF64(pos, v);
}
public function setFloat( pos : Int, v : Float ) : Void {
if( out(pos + 3) ) throw Error.OutsideBounds;
b.setF32(pos, v);
}
public inline function getUInt16( pos : Int ) : Int {
return if( out(pos + 1) ) 0 else b.getUI16(pos);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
if( out(pos + 1) ) throw Error.OutsideBounds;
b.setUI16(pos, v);
}
public function getInt32( pos : Int ) : Int {
return if( out(pos + 3) ) 0 else b.getI32(pos);
}
public function getInt64( pos : Int ) : haxe.Int64 {
if( out(pos + 7) )
return haxe.Int64.ofInt(0);
return haxe.Int64.make(b.getI32(pos+4), b.getI32(pos));
}
public function setInt32( pos : Int, v : Int ) : Void {
if( out(pos + 3) ) throw Error.OutsideBounds;
b.setI32(pos, v);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
setInt32(pos + 4, v.high);
setInt32(pos, v.low);
}
public function getString( pos : Int, len : Int ) : String {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
var b = new hl.types.Bytes(len + 1);
b.blit(0, this.b, pos, len);
b[len] = 0;
return @:privateAccess String.fromUTF8(b);
}
@:deprecated("readString is deprecated, use getString instead")
@:noCompletion
public inline function readString(pos:Int, len:Int):String {
return getString(pos, len);
}
public function toString() : String {
return getString(0,length);
}
public function toHex() : String {
var s = new StringBuf();
var chars = [];
var str = "0123456789abcdef";
for( i in 0...str.length )
chars.push(str.charCodeAt(i));
for( i in 0...length ) {
var c = get(i);
s.addChar(chars[c >> 4]);
s.addChar(chars[c & 15]);
}
return s.toString();
}
public inline function getData() : BytesData {
return new haxe.io.BytesData(b,length);
}
public static function alloc( length : Int ) : Bytes {
var b = new hl.types.Bytes(length);
b.fill(0, length, 0);
return new Bytes(b,length);
}
public static function ofString( s : String ) : Bytes @:privateAccess {
var size = 0;
var b = s.bytes.utf16ToUtf8(0, size);
return new Bytes(b,size);
}
public static function ofData( b : BytesData ) : Bytes {
return new Bytes(b.bytes,b.length);
}
public inline static function fastGet( b : BytesData, pos : Int ) : Int {
return b[pos];
}
}
// same for js, but a lot of functionality can be shared with ByteArray (see ByteHelper next file),
// this is achieved through a typedef ByteArrayImpl (see next file) that matches the structure of Bytes and also the underlying type of ByteArray.
package haxe.io;
#if !nodejs
import js.html.compat.Uint8Array;
import js.html.compat.DataView;
#end
import haxe.io.ByteArray.ByteHelper;
@:coreApi
class Bytes {
public var length(default,null) : Int;
var b : js.html.Uint8Array;
var data : js.html.DataView;
function new(data:BytesData) {
this.length = data.byteLength;
this.b = new js.html.Uint8Array(data);
untyped {
b.bufferValue = data; // some impl does not return the same instance in .buffer
data.hxBytes = this; // store the Bytes instance, this way no new allocation is required when converting BytesData to Bytes
data.bytes = this.b; // for fastGet of BytesData
}
}
public inline function get( pos : Int ) : Int {
return ByteHelper.get(this, pos);
}
public inline function set( pos : Int, v : Int ) : Void {
ByteHelper.set(this, pos, v);
}
public inline function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds;
ByteHelper.blit(this, pos, src, srcpos, len);
}
public inline function fill( pos : Int, len : Int, value : Int ) : Void {
ByteHelper.fill(this, pos, len, value);
}
public inline function sub( pos : Int, len : Int ) : Bytes {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
return Bytes.ofData(ByteHelper.sub(this, pos, len));
}
public inline function compare( other : Bytes ) : Int {
return ByteHelper.compare(this, other);
}
public inline function getDouble( pos : Int ) : Float {
return ByteHelper.getDouble(this, pos);
}
public inline function getFloat( pos : Int ) : Float {
return ByteHelper.getFloat(this, pos);
}
public inline function setDouble( pos : Int, v : Float ) : Void {
ByteHelper.setDouble(this, pos, v);
}
public inline function setFloat( pos : Int, v : Float ) : Void {
ByteHelper.setFloat(this, pos, v);
}
public inline function getUInt16( pos : Int ) : Int {
return ByteHelper.getUInt16(this, pos);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
ByteHelper.setUInt16(this, pos, v);
}
public inline function getInt32( pos : Int ) : Int {
return ByteHelper.getInt32(this, pos);
}
public inline function setInt32( pos : Int, v : Int ) : Void {
ByteHelper.setInt32(this, pos, v);
}
public inline function getInt64( pos : Int ) : haxe.Int64 {
return ByteHelper.getInt64(this, pos);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
ByteHelper.setInt64(this, pos, v);
}
public function getString( pos : Int, len : Int ) : String {
if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
return ByteHelper.getString(this, pos, len);
}
@:deprecated("readString is deprecated, use getString instead")
@:noCompletion
public inline function readString(pos:Int, len:Int):String {
return getString(pos, len);
}
public inline function toString() : String {
return ByteHelper.getString(this, 0, length);
}
public function toHex() : String {
var s = new StringBuf();
var chars = [];
var str = "0123456789abcdef";
for( i in 0...str.length )
chars.push(str.charCodeAt(i));
for( i in 0...length ) {
var c = get(i);
s.addChar(chars[c >> 4]);
s.addChar(chars[c & 15]);
}
return s.toString();
}
public inline function getData() : BytesData {
return ByteHelper.getData(this);
}
public static inline function alloc( length : Int ) : Bytes {
return new Bytes(ByteHelper.allocBuffer(length));
}
public static inline function ofString( s : String ) : Bytes {
var buffer = ByteHelper.ofString(s);
return new Bytes(buffer);
}
public static function ofData( b : BytesData ) : Bytes {
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 ByteHelper.fastGet(b, pos);
}
}
package haxe.io;
#if !nodejs
import js.html.compat.Uint8Array;
import js.html.compat.DataView;
#end
@:allow(haxe.io)
class ByteHelper {
static function sub( impl:ByteArrayImpl, pos : Int, len : Int ) : js.html.ArrayBuffer {
return impl.b.buffer.slice(pos+impl.b.byteOffset,pos+impl.b.byteOffset+len);
}
static function subByteArray( impl:ByteArrayImpl, pos : Int, len : Int ) : ByteArray {
return mkByteArray(sub(impl, pos, len));
}
static inline function mkByteArray (buffer:js.html.ArrayBuffer):ByteArray {
return ByteArray.fromBuffer(buffer);
}
static inline function getLength (impl:ByteArrayImpl):Int {
return impl.b.byteLength;
}
static inline function get( impl:ByteArrayImpl, pos : Int ) : Int {
return impl.b[pos];
}
static inline function set( impl:ByteArrayImpl, pos : Int, v : Int ) : Void {
impl.b[pos] = v & 0xFF; // the &0xFF is necessary for js.html.compat support
}
static inline function blit( impl:ByteArrayImpl, pos : Int, src : ByteArrayImpl, srcpos : Int, len : Int ) : Void {
if( srcpos == 0 && len == src.b.byteLength )
impl.b.set(src.b,pos);
else
impl.b.set(src.b.subarray(srcpos,srcpos+len),pos);
}
static inline function fill( impl: ByteArrayImpl, pos : Int, len : Int, value : Int ):Void {
for( i in 0...len )
set(impl, pos++, value);
}
inline static function initData(impl:ByteArrayImpl) : Void {
if( impl.data == null ) impl.data = new js.html.DataView(impl.b.buffer, impl.b.byteOffset, impl.b.byteLength);
}
static function compare( b:ByteArrayImpl, other : ByteArrayImpl ) : Int {
var b1 = b.b;
var b2 = other.b;
var len = (getLength(b) < getLength(other)) ? getLength(b) : getLength(other);
for( i in 0...len )
if( b1[i] != b2[i] )
return b1[i] - b2[i];
return getLength(b) - getLength(other);
}
static inline function getDouble( impl:ByteArrayImpl, pos : Int ) : Float {
initData(impl);
return impl.data.getFloat64(pos, true);
}
static inline function getFloat( impl:ByteArrayImpl, pos : Int ) : Float {
initData(impl);
return impl.data.getFloat32(pos, true);
}
static inline function setDouble( impl:ByteArrayImpl, pos : Int, v : Float ) : Void {
initData(impl);
impl.data.setFloat64(pos, v, true);
}
static inline function setFloat( impl:ByteArrayImpl, pos : Int, v : Float ) : Void {
initData(impl);
impl.data.setFloat32( pos, v, true);
}
static inline function getUInt16( impl:ByteArrayImpl, pos : Int ) : Int {
initData(impl);
return impl.data.getUint16(pos, true);
}
static inline function setUInt16( impl:ByteArrayImpl, pos : Int, v : Int ) : Void {
initData(impl);
impl.data.setUint16(pos, v, true);
}
static inline function getInt32( impl:ByteArrayImpl, pos : Int ) : Int {
initData(impl);
return impl.data.getInt32(pos, true);
}
static inline function getInt64( impl:ByteArrayImpl, pos : Int ) : haxe.Int64 {
return Int64.make(getInt32(impl, pos + 4),getInt32(impl, pos));
}
static inline function setInt32( impl:ByteArrayImpl, pos : Int, v : Int ) : Void {
initData(impl);
impl.data.setInt32(pos, v, true);
}
static inline function setInt64( impl:ByteArrayImpl, pos : Int, v : haxe.Int64 ) : Void {
setInt32(impl, pos, v.low);
setInt32(impl, pos + 4, v.high);
}
static function getString( impl:ByteArrayImpl, pos : Int, len : Int ) : String {
var s = "";
var b = impl.b;
var fcc = String.fromCharCode;
var i = pos;
var max = pos+len;
// utf8-decode and utf16-encode
while( i < max ) {
var c = b[i++];
if( c < 0x80 ) {
if( c == 0 ) break;
s += fcc(c);
} else if( c < 0xE0 )
s += fcc( ((c & 0x3F) << 6) | (b[i++] & 0x7F) );
else if( c < 0xF0 ) {
var c2 = b[i++];
s += fcc( ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | (b[i++] & 0x7F) );
} else {
var c2 = b[i++];
var c3 = b[i++];
var u = ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | (b[i++] & 0x7F);
// surrogate pair
s += fcc( (u >> 10) + 0xD7C0 );
s += fcc( (u & 0x3FF) | 0xDC00 );
}
}
return s;
}
static inline function toString(impl:ByteArrayImpl) : String {
return getString(impl, 0, getLength(impl));
}
static function ofString( s : String ) : js.html.ArrayBuffer {
var a = new Array();
// utf16-decode and utf8-encode
var i = 0;
while( i < s.length ) {
var c : Int = StringTools.fastCodeAt(s,i++);
// surrogate pair
if( 0xD800 <= c && c <= 0xDBFF )
c = (c - 0xD7C0 << 10) | (StringTools.fastCodeAt(s,i++) & 0x3FF);
if( c <= 0x7F )
a.push(c);
else if( c <= 0x7FF ) {
private typedef ByteArrayImpl = {
private var b : js.html.Uint8Array;
private var data : js.html.DataView;
}
abstract ByteArray(ByteArrayImpl) {
public var length(get,never) : Int;
inline function new (impl:ByteArrayImpl) {
this = impl;
}
public static inline function fromBuffer (buffer:js.html.ArrayBuffer) {
var arr = new js.html.Uint8Array(buffer);
var impl = {
b : arr,
data : null
}
untyped {
arr.bufferValue = buffer; // some impl does not return the same instance in .buffer
buffer.bytes = arr; // for fastGet of BytesData
buffer.hxByteArray = impl; // store the ByteArray instance, this way no new allocation is required when converting BytesData to ByteArray
}
return new ByteArray(impl);
}
public static inline function ofData (b:BytesData) {
var hb:ByteArray = untyped b.hxByteArray;
if (hb != null) return hb;
return fromBuffer(b);
}
public inline function getData () {
return ByteHelper.getData(this);
}
inline function raw ():ByteArrayImpl return this;
inline function get_length ():Int {
return ByteHelper.getLength(this);
}
public inline function get( pos : Int ) : Int {
return ByteHelper.get(this, pos);
}
public inline function set( pos : Int, v : Int ) : Void {
ByteHelper.set(this, pos, v);
}
public inline function blit( pos : Int, src : ByteArray, srcpos : Int, len : Int ) : Void {
return ByteHelper.blit(this, pos, src.raw(), srcpos, len);
}
public inline function fill( pos : Int, len : Int, value : Int ):Void {
ByteHelper.fill(this, pos, len, value);
}
public inline function sub( pos : Int, len : Int ) : ByteArray {
return ByteHelper.subByteArray(this, pos, len);
}
public inline function compare( other : ByteArray ) : Int {
return ByteHelper.compare(this, other.raw());
}
public inline function getDouble( pos : Int ) : Float {
return ByteHelper.getDouble(this, pos);
}
public inline function getFloat( pos : Int ) : Float {
return ByteHelper.getFloat(this, pos);
}
public inline function setDouble( pos : Int, v : Float ) : Void {
ByteHelper.setDouble(this, pos, v);
}
public inline function setFloat( pos : Int, v : Float ) : Void {
ByteHelper.setFloat(this, pos, v);
}
public inline function getUInt16( pos : Int ) : Int {
return ByteHelper.getUInt16(this, pos);
}
public inline function setUInt16( pos : Int, v : Int ) : Void {
ByteHelper.setUInt16(this, pos, v);
}
public inline function getInt32( pos : Int ) : Int {
return ByteHelper.getInt32(this, pos);
}
public inline function getInt64( pos : Int ) : haxe.Int64 {
return ByteHelper.getInt64(this, pos);
}
public inline function setInt32( pos : Int, v : Int ) : Void {
ByteHelper.setInt32(this, pos, v);
}
public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void {
ByteHelper.setInt64(this, pos, v);
}
public inline function getString( pos : Int, len : Int ) : String {
return ByteHelper.getString(this, pos, len);
}
public inline function toString() : String {
return ByteHelper.toString(this);
}
public static inline function alloc( length : Int ) : ByteArray {
var buffer = ByteHelper.allocBuffer(length);
return fromBuffer(buffer);
}
public static inline function ofString( s : String ) : ByteArray {
return fromBuffer(ByteHelper.ofString(s));
}
}
// the helper class for js
a.push( 0xC0 | (c >> 6) );
a.push( 0x80 | (c & 63) );
} else if( c <= 0xFFFF ) {
a.push( 0xE0 | (c >> 12) );
a.push( 0x80 | ((c >> 6) & 63) );
a.push( 0x80 | (c & 63) );
} else {
a.push( 0xF0 | (c >> 18) );
a.push( 0x80 | ((c >> 12) & 63) );
a.push( 0x80 | ((c >> 6) & 63) );
a.push( 0x80 | (c & 63) );
}
}
return new js.html.Uint8Array(a).buffer;
}
static inline function fastGet( data:BytesData, pos : Int ) : Int {
// this requires that we have wrapped it with haxe.io.Bytes beforehand
return untyped data.bytes[pos];
}
static inline function allocBuffer (length:Int) {
return new js.html.ArrayBuffer(length);
}
static inline function getData(impl:ByteArrayImpl) : BytesData {
return untyped impl.b.bufferValue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment