multi-array-view
Version:
A small JavaScript library for efficient work with multidimensional arrays
123 lines (122 loc) • 5.53 kB
JavaScript
;
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
/**
* A JavaScript class for fast working with multi-dimensional array through
* using a flat strided array
*/
var MultiArrayView = /** @class */ (function () {
/**
* @param shape List of dimensions lengths
* @param Constructor The constructor of the array
* @param [offset=0] The offset to start the view
* @param [order] Method of data ordering
*/
function MultiArrayView(array, shape, offset, order) {
if (offset === void 0) { offset = 0; }
if (order === void 0) { order = MultiArrayView.C_ORDER; }
// Checking creating constructor
if (!(this instanceof MultiArrayView)) {
throw new TypeError("Constructor MultiArrayView requires 'new'");
}
// Validating arguments
if (!array ||
shape == null ||
shape.length === 0 ||
typeof offset !== 'number') {
throw new TypeError('invalid arguments');
}
this.shape = shape;
this.length = array.length;
this.array = array;
// List of multipliers for calculation an item index. Last multiplier
// always is 1
var strides = [1];
for (var i = shape.length - 1; i >= 0; i--) {
// If this is the first item, skip the iteration: the length of the
// first dimension is not required to calculate an item position
if (i === 0) {
break;
}
if (order === MultiArrayView.F_ORDER) {
// Row-major order
strides.push(strides[0] * shape[i]);
}
else {
// Column-major order (default)
strides.unshift(strides[0] * shape[i]);
}
}
// Since accessing an item with the help of a rest parameter creates an
// additional array, this method is too slow. For getting and setting items
// of an array, a function is generated with the specified number of
// arguments to maintain performance.
var indexCalculatingCode = (offset !== 0 ? offset + ' + ' : '') +
strides.map(function (item, i) { return "x".concat(i, " * ").concat(item); }).join(' + ');
this.set = new (Function.bind.apply(Function, __spreadArray(__spreadArray([void 0, 'value'], shape.map(function (_, i) { return 'x' + i; }), false), ["this.array[".concat(indexCalculatingCode, "] = value")], false)))();
this.get = new (Function.bind.apply(Function, __spreadArray(__spreadArray([void 0], shape.map(function (_, i) { return 'x' + i; }), false), ["return this.array[".concat(indexCalculatingCode, "]")], false)))();
this.getIndex = new (Function.bind.apply(Function, __spreadArray(__spreadArray([void 0], shape.map(function (_, i) { return 'x' + i; }), false), ["return ".concat(indexCalculatingCode)], false)))();
}
/**
* @param shape List of dimensions lengths
* @param Constructor The constructor of the array or array-like object
* @param [offset=0] The offset to start the view
* @param [order] Method of data ordering
*/
MultiArrayView.create = function (shape, Constructor, offset, order) {
if (Constructor === void 0) { Constructor = Array; }
if (offset === void 0) { offset = 0; }
if (order === void 0) { order = MultiArrayView.C_ORDER; }
// Validating arguments
if (shape == null ||
shape.length === 0 ||
Constructor == null ||
typeof offset !== 'number') {
throw new TypeError('invalid arguments');
}
// Calculation length of the source array
var length = shape.reduce(function (prev, next) { return prev * next; });
var array = new Constructor(offset + length);
return new MultiArrayView(array, shape, offset, order);
};
/**
* Creates the MultiArrayView wrapper around an array or array-like object
* @param array Array to apply to the MultiArrayView
* @param shape List of dimensions lengths
* @param [offset=0] The offset to start the view
* @param [order] Method of data ordering
*/
MultiArrayView.wrap = function (array, shape, offset, order) {
if (offset === void 0) { offset = 0; }
if (order === void 0) { order = MultiArrayView.C_ORDER; }
var calculatedLength = shape.reduce(function (a, b) { return a * b; });
// Checking array length
if (array.length < calculatedLength + offset) {
throw new TypeError('Impossible to create the MultiArrayView, because the sum of the length ' +
'of the array and the offset is greater than the production of ' +
'the shape.');
}
return new MultiArrayView(array, shape, offset, order);
};
/**
* Row-major order constant
*/
MultiArrayView.C_ORDER = 0;
/**
* Column-major order constant
*/
MultiArrayView.F_ORDER = 1;
/**
* Typescript importing fallback
*/
MultiArrayView.default = MultiArrayView;
return MultiArrayView;
}());
module.exports = MultiArrayView;