time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

main.js (10877B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2018 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 /* eslint-disable no-invalid-this */
     20 
     21 'use strict';
     22 
     23 // MODULES //
     24 
     25 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' );
     26 var isCollection = require( '@stdlib/assert/is-collection' );
     27 var isNonNegativeIntegerArray = require( '@stdlib/assert/is-nonnegative-integer-array' ).primitives;
     28 var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
     29 var isIntegerArray = require( '@stdlib/assert/is-integer-array' ).primitives;
     30 var isFunction = require( '@stdlib/assert/is-function' );
     31 var isOrder = require( './../../base/assert/is-order' );
     32 var isDataType = require( './../../base/assert/is-data-type' );
     33 var isBufferLengthCompatible = require( './../../base/assert/is-buffer-length-compatible' );
     34 var parent = require( './../../base/ctor' ); // eslint-disable-line stdlib/no-redeclare
     35 var inherit = require( '@stdlib/utils/inherit' );
     36 var defaults = require( './defaults.json' );
     37 var iget = require( './iget.js' );
     38 var iset = require( './iset.js' );
     39 var get = require( './get.js' );
     40 var set = require( './set.js' );
     41 var copy = require( './copy_array.js' );
     42 var validate = require( './validate.js' );
     43 
     44 
     45 // VARIABLES //
     46 
     47 /*
     48 * See the following references:
     49 *
     50 * -  https://stackoverflow.com/questions/22747068/is-there-a-max-number-of-arguments-javascript-functions-can-accept
     51 * -  https://bugs.webkit.org/show_bug.cgi?id=80797
     52 * -  https://github.com/numpy/numpy/issues/5744
     53 *
     54 * Note that the maximum number of function arguments can vary from engine to engine. Here, we choose something of a lowest common denominator which may **not** be valid everywhere.
     55 */
     56 var MAX_DIMS = 32767|0;
     57 
     58 
     59 // MAIN //
     60 
     61 /**
     62 * ndarray constructor.
     63 *
     64 * @constructor
     65 * @param {string} dtype - data type
     66 * @param {Collection} buffer - data buffer
     67 * @param {NonNegativeIntegerArray} shape - array shape
     68 * @param {IntegerArray} strides - array strides
     69 * @param {NonNegativeInteger} offset - index offset
     70 * @param {string} order - specifies whether an array is row-major (C-style) or column-major (Fortran-style)
     71 * @param {Options} [options] - function options
     72 * @param {string} [options.mode="throw"] - specifies how to handle indices which exceed array dimensions
     73 * @param {StringArray} [options.submode=["throw"]] - specifies how to handle subscripts which exceed array dimensions on a per dimension basis
     74 * @throws {TypeError} `dtype` argument must be a supported ndarray data type
     75 * @throws {TypeError} `buffer` argument must be an array-like object, typed-array-like, or a Buffer
     76 * @throws {TypeError} `buffer` argument `get` and `set` properties must be functions
     77 * @throws {TypeError} `shape` argument must be an array-like object containing nonnegative integers
     78 * @throws {Error} `shape` argument length must equal the number of dimensions
     79 * @throws {TypeError} `strides` argument must be an array-like object containing integers
     80 * @throws {Error} `strides` argument length must equal the number of dimensions (except for zero-dimensional arrays; in which case, the `strides` argument length must be equal to `1`)
     81 * @throws {Error} for zero-dimensional ndarrays, the `strides` argument must contain a single element equal to `0`
     82 * @throws {TypeError} `offset` argument must be a nonnegative integer
     83 * @throws {TypeError} `order` argument must be a supported ndarray order
     84 * @throws {Error} `buffer` argument must be compatible with specified meta data
     85 * @throws {TypeError} options argument must be an object
     86 * @throws {TypeError} must provide valid options
     87 * @throws {RangeError} too many dimensions
     88 * @returns {ndarray} ndarray instance
     89 *
     90 * @example
     91 * var buffer = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ];
     92 * var shape = [ 3, 2 ];
     93 * var strides = [ 2, 1 ];
     94 * var offset = 0;
     95 *
     96 * var out = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' );
     97 */
     98 function ndarray( dtype, buffer, shape, strides, offset, order, options ) {
     99 	var ndims;
    100 	var opts;
    101 	var err;
    102 	var sh;
    103 	var st;
    104 
    105 	if ( !(this instanceof ndarray) ) {
    106 		if ( arguments.length < 7 ) {
    107 			return new ndarray( dtype, buffer, shape, strides, offset, order );
    108 		}
    109 		return new ndarray( dtype, buffer, shape, strides, offset, order, options ); // eslint-disable-line max-len
    110 	}
    111 	if ( !isDataType( dtype ) ) {
    112 		throw new TypeError( 'invalid argument. `dtype` argument must be a supported ndarray data type. Value: `' + dtype + '`.' );
    113 	}
    114 	if ( !isCollection( buffer ) ) {
    115 		throw new TypeError( 'invalid argument. `buffer` argument must be an array-like object, typed-array-like, or a Buffer. Value: `' + buffer + '`.' );
    116 	} else if ( buffer.get && buffer.set && ( !isFunction( buffer.get ) || !isFunction( buffer.set ) ) ) { // eslint-disable-line max-len
    117 		throw new TypeError( 'invalid argument. `buffer` argument `get` and `set` properties must be functions. Value: `' + buffer + '`.' );
    118 	}
    119 	if ( !isNonNegativeIntegerArray( shape ) ) {
    120 		if ( !isCollection( shape) || shape.length > 0 ) {
    121 			throw new TypeError( 'invalid argument. `shape` argument must be an array-like object containing nonnegative integers. Value: `' + shape + '`.' );
    122 		}
    123 	}
    124 	ndims = shape.length;
    125 	if ( ndims > MAX_DIMS ) {
    126 		throw new RangeError( 'invalid argument. Number of dimensions must not exceed ' + MAX_DIMS + ' due to stack limits. Value: `' + ndims + '`.' );
    127 	}
    128 	if ( !isIntegerArray( strides ) ) {
    129 		throw new TypeError( 'invalid argument. `strides` argument must be an array-like object containing integers. Value: `' + strides + '`.' );
    130 	}
    131 	if ( ndims > 0 ) {
    132 		if ( strides.length !== ndims ) {
    133 			throw new RangeError( 'invalid argument. `strides` argument length must match the number of dimensions. Expected number of dimensions: ' + ndims + '. Strides length: ' + strides.length + '.' );
    134 		}
    135 	} else if ( strides.length !== 1 ) {
    136 		throw new RangeError( 'invalid argument. `strides` length must be equal to 1 when creating a zero-dimensional ndarray.' );
    137 	} else if ( strides[ 0 ] !== 0 ) {
    138 		throw new RangeError( 'invalid argument. `strides` argument must contain a single element equal to `0`. Value: `' + strides[ 0 ] + '`.' );
    139 	}
    140 	if ( !isNonNegativeInteger( offset ) ) {
    141 		throw new TypeError( 'invalid argument. `offset` argument must be a nonnegative integer. Value: `' + offset + '`.' );
    142 	}
    143 	if ( !isOrder( order ) ) {
    144 		throw new TypeError( 'invalid argument. `order` argument must be a supported order. Value: `' + order + '`.' );
    145 	}
    146 	if ( !isBufferLengthCompatible( buffer.length, shape, strides, offset ) ) {
    147 		throw new Error( 'invalid arguments. The input buffer is incompatible with the specified meta data. Ensure that the offset is valid with regard to the strides array and that the buffer has enough elements to satisfy the desired array shape.' );
    148 	}
    149 	opts = {};
    150 	opts.mode = defaults.mode;
    151 	if ( arguments.length > 6 ) {
    152 		err = validate( opts, options );
    153 		if ( err ) {
    154 			throw err;
    155 		}
    156 	}
    157 	this._mode = opts.mode;
    158 	if ( opts.submode === void 0 ) {
    159 		opts.submode = [ this._mode ];
    160 	}
    161 	this._submode = opts.submode;
    162 
    163 	// Copy `shape` and `strides` to prevent external mutation:
    164 	sh = copy( shape, ndims );
    165 	st = copy( strides, ndims || 1 );
    166 
    167 	// Call the parent constructor:
    168 	parent.call( this, dtype, buffer, sh, st, offset, order );
    169 
    170 	return this;
    171 
    172 	/* eslint-enable no-invalid-this */
    173 }
    174 
    175 // Inherit from the parent constructor:
    176 inherit( ndarray, parent );
    177 
    178 /**
    179 * Constructor name.
    180 *
    181 * @name name
    182 * @memberof ndarray
    183 * @type {string}
    184 * @default 'ndarray'
    185 *
    186 * @example
    187 * var str = ndarray.name;
    188 * // returns 'ndarray'
    189 */
    190 setReadOnly( ndarray, 'name', 'ndarray' );
    191 
    192 /**
    193 * Returns an array element.
    194 *
    195 * ## Notes
    196 *
    197 * -   The number of indices should **equal** the number of dimensions. Accordingly, for zero-dimensional arrays, no indices should be provided.
    198 *
    199 * @name get
    200 * @memberof ndarray.prototype
    201 * @type {Function}
    202 * @param {...integer} [idx] - indices
    203 * @returns {*} array element
    204 *
    205 * @example
    206 * var buffer = [ 1, 2, 3, 4, 5, 6 ];
    207 * var shape = [ 3, 2 ];
    208 * var strides = [ 2, 1 ];
    209 * var offset = 0;
    210 *
    211 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' );
    212 *
    213 * var v = x.get( 1, 1 );
    214 * // returns 4
    215 */
    216 setReadOnly( ndarray.prototype, 'get', get );
    217 
    218 /**
    219 * Returns an array element located at a specified linear index.
    220 *
    221 * ## Notes
    222 *
    223 * -   For zero-dimensional arrays, the input argument is ignored and, for clarity, should not be provided.
    224 *
    225 * @name iget
    226 * @memberof ndarray.prototype
    227 * @type {Function}
    228 * @param {integer} [idx] - linear index
    229 * @returns {*} array element
    230 *
    231 * @example
    232 * var buffer = [ 1, 2, 3, 4, 5, 6 ];
    233 * var shape = [ 3, 2 ];
    234 * var strides = [ 2, 1 ];
    235 * var offset = 0;
    236 *
    237 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' );
    238 *
    239 * var v = x.iget( 3 );
    240 * // returns 4
    241 */
    242 setReadOnly( ndarray.prototype, 'iget', iget );
    243 
    244 /**
    245 * Sets an array element.
    246 *
    247 * ## Notes
    248 *
    249 * -   The number of indices should **equal** the number of dimensions. Accordingly, for zero-dimensional arrays, no indices should be provided.
    250 *
    251 * @name set
    252 * @memberof ndarray.prototype
    253 * @type {Function}
    254 * @param {...integer} [idx] - indices
    255 * @param {*} v - value to set
    256 * @returns {ndarray} ndarray instance
    257 *
    258 * @example
    259 * var buffer = [ 1, 2, 3, 4, 5, 6 ];
    260 * var shape = [ 3, 2 ];
    261 * var strides = [ 2, 1 ];
    262 * var offset = 0;
    263 *
    264 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' );
    265 *
    266 * var v = x.get( 1, 1 );
    267 * // returns 4
    268 *
    269 * x.set( 1, 1, 10 );
    270 *
    271 * var b = x.data;
    272 * // returns [ 1, 2, 3, 10, 5, 6 ]
    273 *
    274 * v = x.get( 1, 1 );
    275 * // returns 10
    276 */
    277 setReadOnly( ndarray.prototype, 'set', set );
    278 
    279 /**
    280 * Sets an array element located at a specified linear index.
    281 *
    282 * ## Notes
    283 *
    284 * -   For zero-dimensional arrays, the first, and only, argument should be the value to set.
    285 *
    286 * @name iset
    287 * @memberof ndarray.prototype
    288 * @type {Function}
    289 * @param {integer} [idx] - linear index
    290 * @param {*} v - value to set
    291 * @returns {ndarray} ndarray instance
    292 *
    293 * @example
    294 * var buffer = [ 1, 2, 3, 4, 5, 6 ];
    295 * var shape = [ 3, 2 ];
    296 * var strides = [ 2, 1 ];
    297 * var offset = 0;
    298 *
    299 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' );
    300 *
    301 * var v = x.iget( 3 );
    302 * // returns 4
    303 *
    304 * x.iset( 3, 10 );
    305 *
    306 * var b = x.data;
    307 * // returns [ 1, 2, 3, 10, 5, 6 ]
    308 *
    309 * v = x.iget( 3 );
    310 * // returns 10
    311 */
    312 setReadOnly( ndarray.prototype, 'iset', iset );
    313 
    314 
    315 // EXPORTS //
    316 
    317 module.exports = ndarray;