UNPKG

@fictivekin/growable-uint8-array

Version:

A wrapper around Uint8Array that simplifies buffer management when appending data (growing the array)

322 lines (254 loc) 8.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = GrowableUint8Array; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } var MAX_SIGNED_INT_VALUE = Math.pow(2, 32) - 1; function toUint32(x) { return x >>> 0; } function isArrayIndex(propName) { if (_typeof(propName) === 'symbol') { return false; } var uint32Prop = toUint32(propName); return String(uint32Prop) === propName && uint32Prop !== MAX_SIGNED_INT_VALUE; } var proxyHandler = { has: function has(target, key) { if (isArrayIndex(key)) { var uint32Prop = toUint32(key); return uint32Prop < target.length; } return Reflect.has(target, key); }, get: function get(target, property, receiver) { if (isArrayIndex(property)) { if (property in receiver) { return target.buf[property]; } return undefined; } return Reflect.get(target, property, receiver); }, set: function set(target, property, value, receiver) { if (isArrayIndex(property)) { if (property in receiver) { target.buf[property] = value; } return true; } return Reflect.set(target, property, value, receiver); }, ownKeys: function ownKeys(target) { var keys = new Set(Reflect.ownKeys(target.unwrap()).concat(Reflect.ownKeys(target))); keys["delete"]('buf'); keys["delete"]('bytesUsed'); keys["delete"]('_expansionRate'); return Array.from(keys); }, getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, prop) { if (isArrayIndex(prop)) { var uint32Prop = toUint32(prop); if (uint32Prop < target.length) { var descriptor = Reflect.getOwnPropertyDescriptor(target.buf, uint32Prop); /* This descriptor is not really configurable, but Proxy invariants require that it be marked as such since `target` does not have the corresponding property. This has implications for deleteProperty */ descriptor.configurable = true; return descriptor; } } return Reflect.getOwnPropertyDescriptor(target, prop); }, defineProperty: function defineProperty(target, key, descriptor) { if (isArrayIndex(key)) { var uint32Prop = toUint32(key); if (uint32Prop < target.length) { return Reflect.defineProperty(target.buf, key, descriptor); } throw new TypeError('Invalid typed array index'); } return Reflect.defineProperty(target, key, descriptor); }, deleteProperty: function deleteProperty(target, prop) { if (isArrayIndex(prop)) { return true; } return Reflect.deleteProperty(target, prop); } }; /** Create a new GrowableUint8Array * @param {Uint8Array} buf: Initial view * @param {number} expansionRate: How much to grow buffer */ function GrowableUint8Array() { var buf = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var expansionRate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2; if (buf) { if (buf instanceof GrowableUint8Array) { return new GrowableUint8Array(buf.unwrap(true), expansionRate || buf.expansionRate); } if (!(buf instanceof Uint8Array)) { throw new Error('Can only wrap Uint8Array instances'); } this.buf = buf; this.bytesUsed = this.buf.length; } else { this.buf = new Uint8Array(parseInt(2 * Math.pow(expansionRate, 4))); this.bytesUsed = 0; } this.expansionRate = expansionRate; } /** Creates a new GrowableUint8Array from an array-like or iterable object. See also Array.from(). */ GrowableUint8Array.from = function from() { return new GrowableUint8Array(Uint8Array.from.apply(Uint8Array, arguments)); }; /** Creates a new GrowableUint8Array with a variable number of arguments. See also Array.of(). */ GrowableUint8Array.of = function of() { return new GrowableUint8Array(Uint8Array.of.apply(Uint8Array, arguments)); }; GrowableUint8Array.prototype.accessProxy = function accessProxy() { return new Proxy(this, proxyHandler); }; /** Extend a GrowableUint8Array with new data * @param {Uint8Array} buf: new data to add * @return {GrowableUint8Array} new GrowableUint8Array */ GrowableUint8Array.prototype.extend = function extend(buf) { if (buf.length + this.length > this.buf.byteLength) { var oldBuf = this.buf; var newSize = Math.max(parseInt(this.buf.buffer.byteLength * this.expansionRate), buf.length + this.length + 1); this.buf = new Uint8Array(newSize); this.set(oldBuf); } this.set(buf, this.length); this.bytesUsed += buf.length; return this; }; /* Return a DataView of the underlying buffer, starting at the specified offset * @return {DataView} */ GrowableUint8Array.prototype.dataView = function dataView() { var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return new DataView(this.buf.buffer, offset, this.length - offset); }; Object.defineProperty(GrowableUint8Array.prototype, 'length', { get: function get() { return this.bytesUsed; }, set: function set(_val) {} }); Object.defineProperty(GrowableUint8Array.prototype, 'expansionRate', { get: function get() { return this._expansionRate; }, set: function set(val) { if (val <= 1) { throw new RangeError('expansionRate must be greater than 1'); } this._expansionRate = val; } }); /* Returns the underlying Uint8Array buffer. * @param {boolean} copy Pass `true` to return a copy of the buffer. * @return {Uint8Array} */ GrowableUint8Array.prototype.unwrap = function unwrap() { var copy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var unwrapped = this.buf.subarray(0, this.length); if (copy) { return unwrapped.slice(); } return unwrapped; }; /* Functions which simply pass their argument through to the underlying Uint8Array. */ var _PASSTHROUGH_FNS = [Symbol.iterator, 'entries', 'every', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'reduce', 'reduceRight', 'some', 'values']; var _loop = function _loop() { var fName = _PASSTHROUGH_FNS2[_i]; GrowableUint8Array.prototype[fName] = function () { var _this$unwrap2; return (_this$unwrap2 = this.unwrap())[fName].apply(_this$unwrap2, arguments); }; }; for (var _i = 0, _PASSTHROUGH_FNS2 = _PASSTHROUGH_FNS; _i < _PASSTHROUGH_FNS2.length; _i++) { _loop(); } /* Functions which use the underlying Uint8Array function, but return an instance of GrowableUint8Array */ var _WRAP_FNS = ['copyWithin', 'filter', 'map', 'reverse', 'slice', 'sort']; var _loop2 = function _loop2() { var fName = _WRAP_FNS2[_i2]; GrowableUint8Array.prototype[fName] = function () { var _this$unwrap3; return new GrowableUint8Array((_this$unwrap3 = this.unwrap())[fName].apply(_this$unwrap3, arguments), this.expansionRate); }; }; for (var _i2 = 0, _WRAP_FNS2 = _WRAP_FNS; _i2 < _WRAP_FNS2.length; _i2++) { _loop2(); } GrowableUint8Array.prototype.fill = function fill() { var _this$unwrap; (_this$unwrap = this.unwrap()).fill.apply(_this$unwrap, arguments); return this; }; GrowableUint8Array.prototype.set = function set(array) { var _this$buf; if (array instanceof GrowableUint8Array) { array = array.unwrap(); } for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } return (_this$buf = this.buf).set.apply(_this$buf, [array].concat(args)); }; /* Get the element at a specific index * @param {number} index index of element. * @return {number} */ GrowableUint8Array.prototype.getElement = function getElement(index) { if (index < this.length) { return this.buf[index]; } return undefined; }; /* Set the element at a specific index to a value * @param {number} index index of element. * @param {number} value value to set * @return {number} */ GrowableUint8Array.prototype.setElement = function setElement(index, value) { if (index < this.length) { return this.buf[index] = value; } return value; }; var inspect = Symbol["for"]('nodejs.util.inspect.custom'); GrowableUint8Array.prototype[inspect] = function inspect() { var _require; for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return (_require = require('util')).inspect.apply(_require, [this.unwrap()].concat(args)).replace('Uint8Array', 'GrowableUint8Array'); };