UNPKG

@stdlib/array

Version:
360 lines (333 loc) 10 kB
/** * @license Apache-2.0 * * Copyright (c) 2024 The Stdlib Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable max-len, no-restricted-syntax, no-invalid-this */ 'use strict'; // MODULES // var isCollection = require( '@stdlib/assert/is-collection' ); var isObject = require( '@stdlib/assert/is-object' ); var isFunction = require( '@stdlib/assert/is-function' ); var hasIteratorSymbolSupport = require( '@stdlib/assert/has-iterator-symbol-support' ); var ITERATOR_SYMBOL = require( '@stdlib/symbol/iterator' ); var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); var getter = require( './../../base/getter' ); var accessorGetter = require( './../../base/accessor-getter' ); var inherits = require( '@stdlib/utils/inherit' ); var fixedEndianFactory = require( './../../fixed-endian-factory' ); var bytesPerElement = require( '@stdlib/ndarray/base/bytes-per-element' ); var capitalize = require( '@stdlib/string/base/capitalize' ); var format = require( '@stdlib/string/format' ); var fromIterator = require( './from_iterator.js' ); var fromIteratorMap = require( './from_iterator_map.js' ); // VARIABLES // var HAS_ITERATOR_SYMBOL = hasIteratorSymbolSupport(); var BYTE_ORDER = 'little-endian'; var DTYPE2SET = { 'float64': 'setFloat64', 'float32': 'setFloat32', 'int32': 'setInt32', 'int16': 'setInt16', 'uint32': 'setUint32', 'uint16': 'setUint16' }; var CHAR2ARTICLE = { 'c': 'a', 'f': 'a', 'i': 'an', 'u': 'a', 'b': 'a' }; // FUNCTIONS // /** * Converts a data type string to a constructor name. * * @private * @param {string} dtype - data type * @returns {string} constructor name * * @example * var n = dtype2ctor( 'float64' ); * // returns 'Float64ArrayLE' * * @example * var n = dtype2ctor( 'int32' ); * // returns 'Int32ArrayLE' */ function dtype2ctor( dtype ) { return capitalize( dtype ) + 'ArrayLE'; } // MAIN // /** * Returns a typed array constructor for creating typed arrays stored in little-endian byte order. * * @param {string} dtype - typed array data type * @throws {TypeError} first argument must be a supported data type * @returns {Function} typed array constructor * * @example * var Float64ArrayLE = factory( 'float64' ); * * var arr = new Float64ArrayLE(); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 0 * * @example * var Float64ArrayLE = factory( 'float64' ); * * var arr = new Float64ArrayLE( 2 ); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 2 * * @example * var Float64ArrayLE = factory( 'float64' ); * * var arr = new Float64ArrayLE( [ 1.0, 2.0 ] ); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 2 * * @example * var ArrayBuffer = require( '@stdlib/array/buffer' ); * * var Float64ArrayLE = factory( 'float64' ); * * var buf = new ArrayBuffer( 16 ); * var arr = new Float64ArrayLE( buf ); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 2 * * @example * var ArrayBuffer = require( '@stdlib/array/buffer' ); * * var Float64ArrayLE = factory( 'float64' ); * * var buf = new ArrayBuffer( 16 ); * var arr = new Float64ArrayLE( buf, 8 ); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 1 * * @example * var ArrayBuffer = require( '@stdlib/array/buffer' ); * * var Float64ArrayLE = factory( 'float64' ); * * var buf = new ArrayBuffer( 32 ); * var arr = new Float64ArrayLE( buf, 8, 2 ); * // returns <Float64ArrayLE> * * var len = arr.length; * // returns 2 */ function factory( dtype ) { var BYTES_PER_ELEMENT; var CTOR_NAME; var SETTER; var parent; // Defer `dtype` validation to `fixedEndianFactory`: parent = fixedEndianFactory( dtype ); BYTES_PER_ELEMENT = bytesPerElement( dtype ); CTOR_NAME = dtype2ctor( dtype ); SETTER = DTYPE2SET[ dtype ]; /** * Typed array constructor which returns a typed array representing an array of values in little-endian byte order. * * @private * @constructor * @param {(NonNegativeInteger|Collection|ArrayBuffer|Iterable)} [arg] - length, typed array, array-like object, buffer, or an iterable * @param {NonNegativeInteger} [byteOffset=0] - byte offset * @param {NonNegativeInteger} [length] - view length * @throws {TypeError} if provided only one argument, the argument must be a valid argument * @throws {TypeError} byte offset must be a nonnegative integer * @throws {RangeError} must provide sufficient memory to accommodate byte offset and view length requirements * @returns {TypedArray} typed array instance */ function TypedArray() { var nargs = arguments.length; if ( !(this instanceof TypedArray) ) { if ( nargs === 0 ) { return new TypedArray(); } if ( nargs === 1 ) { return new TypedArray( arguments[0] ); } if ( nargs === 2 ) { return new TypedArray( arguments[0], arguments[1] ); } return new TypedArray( arguments[0], arguments[1], arguments[2] ); } if ( nargs === 0 ) { parent.call( this, BYTE_ORDER ); } else if ( nargs === 1 ) { parent.call( this, BYTE_ORDER, arguments[0] ); } else if ( nargs === 2 ) { parent.call( this, BYTE_ORDER, arguments[0], arguments[1] ); } else if ( nargs === 3 ) { parent.call( this, BYTE_ORDER, arguments[0], arguments[1], arguments[2] ); } return this; } /** * Size (in bytes) of each array element. * * @private * @name BYTES_PER_ELEMENT * @memberof TypedArray * @readonly * @type {PositiveInteger} */ setReadOnly( TypedArray, 'BYTES_PER_ELEMENT', BYTES_PER_ELEMENT ); /** * Constructor name. * * @private * @name name * @memberof TypedArray * @readonly * @type {string} */ setReadOnly( TypedArray, 'name', CTOR_NAME ); /** * Creates a new typed array from an array-like object or an iterable. * * @private * @name from * @memberof TypedArray * @type {Function} * @param {(Collection|Iterable)} src - array-like object or iterable * @param {Function} [clbk] - callback to invoke for each source element * @param {*} [thisArg] - context * @throws {TypeError} `this` context must be a constructor * @throws {TypeError} `this` must be a typed array constructor * @throws {TypeError} first argument must be an array-like object or an iterable * @throws {TypeError} second argument must be a function * @returns {TypedArray} typed array instance */ setReadOnly( TypedArray, 'from', function from( src ) { var thisArg; var nargs; var clbk; var out; var buf; var tmp; var get; var len; var i; if ( !isFunction( this ) ) { throw new TypeError( 'invalid invocation. `this` context must be a constructor.' ); } if ( !isTypedArrayConstructor( this ) ) { throw new TypeError( format( 'invalid invocation. `this` is not %s %s.', CHAR2ARTICLE[ dtype[0] ], CTOR_NAME ) ); } nargs = arguments.length; if ( nargs > 1 ) { clbk = arguments[ 1 ]; if ( !isFunction( clbk ) ) { throw new TypeError( format( 'invalid argument. Second argument must be a function. Value: `%s`.', clbk ) ); } if ( nargs > 2 ) { thisArg = arguments[ 2 ]; } } if ( isCollection( src ) ) { if ( clbk ) { len = src.length; if ( src.get && src.set ) { get = accessorGetter( 'default' ); } else { get = getter( 'default' ); } out = new this( len ); buf = out._buffer; // eslint-disable-line no-underscore-dangle for ( i = 0; i < len; i++ ) { buf[ SETTER ]( i*BYTES_PER_ELEMENT, clbk.call( thisArg, get( src, i ), i ), true ); } return out; } return new this( src ); } if ( isObject( src ) && HAS_ITERATOR_SYMBOL && isFunction( src[ ITERATOR_SYMBOL ] ) ) { buf = src[ ITERATOR_SYMBOL ](); if ( !isFunction( buf.next ) ) { throw new TypeError( format( 'invalid argument. First argument must be an array-like object or an iterable. Value: `%s`.', src ) ); } if ( clbk ) { tmp = fromIteratorMap( buf, clbk, thisArg ); } else { tmp = fromIterator( buf ); } len = tmp.length; out = new this( len ); buf = out._buffer; // eslint-disable-line no-underscore-dangle for ( i = 0; i < len; i++ ) { buf[ SETTER ]( i*BYTES_PER_ELEMENT, tmp[ i ], true ); } return out; } throw new TypeError( format( 'invalid argument. First argument must be an array-like object or an iterable. Value: `%s`.', src ) ); }); /** * Creates a new typed array from a variable number of arguments. * * @private * @name of * @memberof TypedArray * @type {Function} * @param {...*} element - array elements * @throws {TypeError} `this` context must be a constructor * @throws {TypeError} `this` must be a typed array constructor * @returns {TypedArray} typed array instance */ setReadOnly( TypedArray, 'of', function of() { var args; var i; if ( !isFunction( this ) ) { throw new TypeError( 'invalid invocation. `this` context must be a constructor.' ); } if ( !isTypedArrayConstructor( this ) ) { throw new TypeError( format( 'invalid invocation. `this` is not %s %s.', CHAR2ARTICLE[ dtype[0] ], CTOR_NAME ) ); } args = []; for ( i = 0; i < arguments.length; i++ ) { args.push( arguments[ i ] ); } return new this( args ); }); // Inherit from the parent constructor: inherits( TypedArray, parent ); return TypedArray; /** * Returns a boolean indicating if a value is a typed array constructor. * * @private * @param {*} value - value to test * @returns {boolean} boolean indicating if a value is a typed array constructor */ function isTypedArrayConstructor( value ) { return ( value === TypedArray ); } } // EXPORTS // module.exports = factory;