o1 = (function() { // Float8 const exponentSize = 5; const mantissaSize = 10; const bias = Math.pow(2, exponentSize - 1) - 1; // http://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript#8796597 function decodeFloat16 (binary) { var exponent = (binary & 0x7C00) >> 10; fraction = binary & 0x03FF; return (binary >> 15 ? -1 : 1) * ( exponent ? ( exponent === 0x1F ? fraction ? NaN : Infinity : Math.pow(2, exponent - 15) * (1 + fraction / 0x400) ) : 6.103515625e-5 * (fraction / 0x400) ); }; function encodeFloat16(floating) { let abs = Math.floor(Math.abs(floating)); let frac = Math.abs(floating) - abs; let fraction = []; let sign = Math.sign(floating) < 0; // Compute the integral let integral = new Number(abs).toString(2).split('').map((a) => a == 1); if (integral.length === 1 && integral[0] === false) integral = []; // Compute the fraction while (fraction.length < 16) { frac *= 2; fraction.push(frac >= 1); if (frac >= 1) { frac--; } if (frac == 0) { break; } } // Compute the exponent let exponent = 0; while (integral.length > 1) { fraction = [integral.pop(), ...fraction]; exponent++; } while (integral.length < 1 || !integral[integral.length-1] && fraction.length > 0) { integral = [...integral, fraction.shift()]; exponent--; } exponent += bias; // Math.pow(2, 5 - 1) - 1, the bias // To array of bools exponent = new Number(exponent).toString(2).split('').map((a) => a == 1); // Pad the exponent with zeros while (exponent.length < exponentSize) { exponent = [false, ...exponent]; } // Pad the fraction with zeros while (fraction.length < mantissaSize) { fraction.push(false); } fraction = fraction.slice(0, mantissaSize); let result = [sign, ...exponent, ...fraction]; return parseInt(result.reduce((a,b) => a + (b ? '1' : '0'), ''), 2); } let o1 = {}; o1.encodeFloat16 = encodeFloat16; o1.decodeFloat16 = decodeFloat16; o1.IncompleteBufferError = class extends Error {}; function newCall(Cls) { return new (Function.prototype.bind.apply(Cls, arguments)); } o1.BinaryElement = class { constructor(value) { this.value = value; } loadFromBytes(buffers, offset) { if (buffers instanceof ArrayBuffer) { buffers = [buffers]; } else if (! buffers instanceof Array) { throw new TypeError("Expecting buffer or array of buffers"); } // Find correct buffer let currentBufferIndex = 0; while (offset >= buffers[currentBufferIndex].byteLength) { offset -= buffers[currentBufferIndex].byteLength; currentBufferIndex++; if (buffers[currentBufferIndex] === undefined) throw new o1.IncompleteBufferError(); } let buffer = buffers[currentBufferIndex]; let view = new DataView(buffer, offset); let bytes = new ArrayBuffer(this.size()); let bytesView = new DataView(bytes); let offsetBetweenBuffers = 0; for (let byteIndex = 0; byteIndex < this.size(); byteIndex++) { if (byteIndex - offsetBetweenBuffers >= view.byteLength) { // Change view currentBufferIndex++; let newBuffer = buffers[currentBufferIndex]; if (newBuffer === undefined) { throw new o1.IncompleteBufferError(); } view = new DataView(newBuffer); offsetBetweenBuffers = byteIndex; } bytesView.setUint8(byteIndex, view.getUint8(byteIndex - offsetBetweenBuffers)); } this.readFromView(bytesView); } } o1.Uint8 = class extends o1.BinaryElement { constructor(value) { super(value); } size() { return 1; } writeToView(view, offset = 0) { view.setUint8(offset, this.value); } readFromView(view, offset) { return this.value = view.getUint8(offset); } } o1.Uint32 = class extends o1.BinaryElement { constructor(value) { super(value); } size() { return 4; } writeToView(view, offset = 0) { view.setUint32(offset, this.value); } readFromView(view, offset) { return this.value = view.getUint32(offset); } } o1.Float16 = class extends o1.BinaryElement { constructor(value) { super(value); } size() { return 2; } writeToView(view, offset = 0) { view.setUint16(offset, encodeFloat16(this.value)); } readFromView(view, offset) { let uint16 = view.getUint16(offset); this.value = decodeFloat16(uint16); } } o1.Float32 = class extends o1.BinaryElement { constructor(value) { super(value); } size() { return 4; } writeToView(view, offset = 0) { view.setFloat32(offset, this.value); } readFromView(view, offset) { return this.value = view.getFloat32(offset); } } o1.BufferWriter = class { constructor(size) { this.buffer = new ArrayBuffer(size); this.offset = 0; } write(element) { element.writeToView(new DataView(this.buffer, this.offset)); this.offset += element.size(); } } o1.BufferReader = class { constructor(buffers) { if (buffers instanceof ArrayBuffer) { this.buffers = [buffers]; } else if (buffers instanceof Array) { this.buffers = buffers; } else { throw new TypeError("Expexting buffer or array of buffers"); } this.offset = 0; this.array = []; } decodeElement(type) { let elt = newCall(type); elt.loadFromBytes(this.buffers, this.offset); this.offset += elt.size(); this.array.push(elt); return elt; } } o1.decodeElement = function(buffer, offset, type) { let elt = newCall(type); elt.loadFromBytes(buffer, offset); return elt; } o1.encodeArray = function(array) { let size = array.map((a) => a.size()).reduce((a,b) => a+b, 0); let writer = new o1.BufferWriter(size); for (let elt of array) { writer.write(elt); } return writer.buffer; } o1.decodeArray = function(buffer, types) { let reader = new o1.BufferReader(buffer); for (let i = 0; i < types.length; i++) { reader.decodeElement(types[i]); } return reader.array; } return o1; })(); if (typeof module !== 'undefined' && module.exports) { module.exports = o1; }