time-to-botec

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

main.js (31591B)


      1 /* eslint-disable no-restricted-syntax, max-lines */
      2 
      3 /**
      4 * @license Apache-2.0
      5 *
      6 * Copyright (c) 2018 The Stdlib Authors.
      7 *
      8 * Licensed under the Apache License, Version 2.0 (the "License");
      9 * you may not use this file except in compliance with the License.
     10 * You may obtain a copy of the License at
     11 *
     12 *    http://www.apache.org/licenses/LICENSE-2.0
     13 *
     14 * Unless required by applicable law or agreed to in writing, software
     15 * distributed under the License is distributed on an "AS IS" BASIS,
     16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17 * See the License for the specific language governing permissions and
     18 * limitations under the License.
     19 */
     20 
     21 'use strict';
     22 
     23 // MODULES //
     24 
     25 var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
     26 var isArrayLikeObject = require( '@stdlib/assert/is-array-like-object' );
     27 var isCollection = require( '@stdlib/assert/is-collection' );
     28 var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
     29 var isObject = require( '@stdlib/assert/is-object' );
     30 var isArray = require( '@stdlib/assert/is-array' );
     31 var isFunction = require( '@stdlib/assert/is-function' );
     32 var isComplexLike = require( '@stdlib/assert/is-complex-like' );
     33 var isEven = require( '@stdlib/math/base/assert/is-even' );
     34 var isInteger = require( '@stdlib/math/base/assert/is-integer' );
     35 var hasIteratorSymbolSupport = require( '@stdlib/assert/has-iterator-symbol-support' );
     36 var ITERATOR_SYMBOL = require( '@stdlib/symbol/iterator' );
     37 var defineProperty = require( '@stdlib/utils/define-property' );
     38 var Float32Array = require( './../../float32' );
     39 var Complex64 = require( '@stdlib/complex/float32' );
     40 var real = require( '@stdlib/complex/real' );
     41 var imag = require( '@stdlib/complex/imag' );
     42 var fromIterator = require( './from_iterator.js' );
     43 var fromIteratorMap = require( './from_iterator_map.js' );
     44 var fromArray = require( './from_array.js' );
     45 
     46 
     47 // VARIABLES //
     48 
     49 var BYTES_PER_ELEMENT = Float32Array.BYTES_PER_ELEMENT * 2;
     50 var HAS_ITERATOR_SYMBOL = hasIteratorSymbolSupport();
     51 
     52 
     53 // FUNCTIONS //
     54 
     55 /**
     56 * Returns a boolean indicating if a value is a complex typed array.
     57 *
     58 * @private
     59 * @param {*} value - value to test
     60 * @returns {boolean} boolean indicating if a value is a complex typed array
     61 */
     62 function isComplexArray( value ) {
     63 	return (
     64 		value instanceof Complex64Array ||
     65 		(
     66 			typeof value === 'object' &&
     67 			value !== null &&
     68 			(
     69 				value.constructor.name === 'Complex64Array' ||
     70 				value.constructor.name === 'Complex128Array'
     71 			) &&
     72 			typeof value._length === 'number' && // eslint-disable-line no-underscore-dangle
     73 
     74 			// NOTE: we don't perform a more rigorous test here for a typed array for performance reasons, as robustly checking for a typed array instance could require walking the prototype tree and performing relatively expensive constructor checks...
     75 			typeof value._buffer === 'object' // eslint-disable-line no-underscore-dangle
     76 		)
     77 	);
     78 }
     79 
     80 /**
     81 * Returns a boolean indicating if a value is a complex typed array constructor.
     82 *
     83 * @private
     84 * @param {*} value - value to test
     85 * @returns {boolean} boolean indicating if a value is a complex typed array constructor
     86 */
     87 function isComplexArrayConstructor( value ) {
     88 	return (
     89 		value === Complex64Array ||
     90 
     91 		// NOTE: weaker test in order to avoid a circular dependency with Complex128Array...
     92 		value.name === 'Complex128Array'
     93 	);
     94 }
     95 
     96 
     97 // MAIN //
     98 
     99 /**
    100 * 64-bit complex number array constructor.
    101 *
    102 * @constructor
    103 * @param {(NonNegativeInteger|TypedArray|ArrayLikeObject|ArrayBuffer|Iterable)} [arg] - length, typed array, array-like object, or buffer
    104 * @param {NonNegativeInteger} [byteOffset=0] - byte offset
    105 * @param {NonNegativeInteger} [length] - view length
    106 * @throws {RangeError} ArrayBuffer byte length must be a multiple of `8`
    107 * @throws {RangeError} array-like object and typed array input arguments must have a length which is a multiple of two
    108 * @throws {TypeError} if provided only a single argument, must provide a valid argument
    109 * @throws {TypeError} byte offset must be a nonnegative integer
    110 * @throws {RangeError} byte offset must be a multiple of `8`
    111 * @throws {TypeError} view length must be a positive multiple of `8`
    112 * @throws {RangeError} must provide sufficient memory to accommodate byte offset and view length requirements
    113 * @throws {TypeError} an iterator must return either a two element array containing real and imaginary components or a complex number
    114 * @returns {Complex64Array} complex number array
    115 *
    116 * @example
    117 * var arr = new Complex64Array();
    118 * // returns <Complex64Array>
    119 *
    120 * var len = arr.length;
    121 * // returns 0
    122 *
    123 * @example
    124 * var arr = new Complex64Array( 2 );
    125 * // returns <Complex64Array>
    126 *
    127 * var len = arr.length;
    128 * // returns 2
    129 *
    130 * @example
    131 * var arr = new Complex64Array( [ 1.0, -1.0 ] );
    132 * // returns <Complex64Array>
    133 *
    134 * var len = arr.length;
    135 * // returns 1
    136 *
    137 * @example
    138 * var ArrayBuffer = require( '@stdlib/array/buffer' );
    139 *
    140 * var buf = new ArrayBuffer( 16 );
    141 * var arr = new Complex64Array( buf );
    142 * // returns <Complex64Array>
    143 *
    144 * var len = arr.length;
    145 * // returns 2
    146 *
    147 * @example
    148 * var ArrayBuffer = require( '@stdlib/array/buffer' );
    149 *
    150 * var buf = new ArrayBuffer( 16 );
    151 * var arr = new Complex64Array( buf, 8 );
    152 * // returns <Complex64Array>
    153 *
    154 * var len = arr.length;
    155 * // returns 1
    156 *
    157 * @example
    158 * var ArrayBuffer = require( '@stdlib/array/buffer' );
    159 *
    160 * var buf = new ArrayBuffer( 32 );
    161 * var arr = new Complex64Array( buf, 8, 2 );
    162 * // returns <Complex64Array>
    163 *
    164 * var len = arr.length;
    165 * // returns 2
    166 */
    167 function Complex64Array() {
    168 	var byteOffset;
    169 	var nargs;
    170 	var buf;
    171 	var len;
    172 
    173 	nargs = arguments.length;
    174 	if ( !(this instanceof Complex64Array) ) {
    175 		if ( nargs === 0 ) {
    176 			return new Complex64Array();
    177 		}
    178 		if ( nargs === 1 ) {
    179 			return new Complex64Array( arguments[0] );
    180 		}
    181 		if ( nargs === 2 ) {
    182 			return new Complex64Array( arguments[0], arguments[1] );
    183 		}
    184 		return new Complex64Array( arguments[0], arguments[1], arguments[2] );
    185 	}
    186 	// Create the underlying data buffer...
    187 	if ( nargs === 0 ) {
    188 		buf = new Float32Array( 0 ); // backward-compatibility
    189 	} else if ( nargs === 1 ) {
    190 		if ( isNonNegativeInteger( arguments[0] ) ) {
    191 			buf = new Float32Array( arguments[0]*2 );
    192 		} else if ( isCollection( arguments[0] ) ) {
    193 			buf = arguments[ 0 ];
    194 			len = buf.length;
    195 
    196 			// If provided a "generic" array, peak at the first value, and, if the value is a complex number, try to process as an array of complex numbers, falling back to "normal" typed array initialization if we fail and ensuring consistency if the first value had not been a complex number...
    197 			if ( len && isArray( buf ) && isComplexLike( buf[0] ) ) {
    198 				buf = fromArray( new Float32Array( len*2 ), buf );
    199 				if ( buf === null ) {
    200 					// We failed and we are now forced to allocate a new array :-(
    201 					if ( !isEven( len ) ) {
    202 						throw new RangeError( 'invalid argument. Array-like object input arguments must have a length which is a multiple of two. Length: `'+len+'`.' );
    203 					}
    204 					// We failed, so fall back to directly setting values...
    205 					buf = new Float32Array( arguments[0] );
    206 				}
    207 			} else {
    208 				if ( !isEven( len ) ) {
    209 					throw new RangeError( 'invalid argument. Array-like object and typed array input arguments must have a length which is a multiple of two. Length: `'+len+'`.' );
    210 				}
    211 				buf = new Float32Array( buf );
    212 			}
    213 		} else if ( isArrayBuffer( arguments[0] ) ) {
    214 			buf = arguments[ 0 ];
    215 			if ( !isInteger( buf.byteLength/BYTES_PER_ELEMENT ) ) {
    216 				throw new RangeError( 'invalid argument. ArrayBuffer byte length must be a multiple of '+BYTES_PER_ELEMENT+'. Byte length: `'+buf.byteLength+'`.' );
    217 			}
    218 			buf = new Float32Array( buf );
    219 		} else if ( isObject( arguments[0] ) ) {
    220 			buf = arguments[ 0 ];
    221 			if ( HAS_ITERATOR_SYMBOL === false ) {
    222 				throw new TypeError( 'invalid argument. Environment lacks Symbol.iterator support. Must provide a length, ArrayBuffer, typed array, or array-like object. Value: `'+buf+'`.' );
    223 			}
    224 			if ( !isFunction( buf[ ITERATOR_SYMBOL ] ) ) {
    225 				throw new TypeError( 'invalid argument. Must provide a length, ArrayBuffer, typed array, array-like object, or an iterable. Value: `'+buf+'`.' );
    226 			}
    227 			buf = buf[ ITERATOR_SYMBOL ]();
    228 			if ( !isFunction( buf.next ) ) {
    229 				throw new TypeError( 'invalid argument. Must provide a length, ArrayBuffer, typed array, array-like object, or an iterable.' );
    230 			}
    231 			buf = fromIterator( buf );
    232 			if ( buf instanceof Error ) {
    233 				throw buf;
    234 			}
    235 			buf = new Float32Array( buf );
    236 		} else {
    237 			throw new TypeError( 'invalid argument. Must provide a length, ArrayBuffer, typed array, array-like object, or an iterable. Value: `'+arguments[0]+'`.' );
    238 		}
    239 	} else {
    240 		buf = arguments[ 0 ];
    241 		if ( !isArrayBuffer( buf ) ) {
    242 			throw new TypeError( 'invalid argument. First argument must be an array buffer. Value: `'+buf+'`.' );
    243 		}
    244 		byteOffset = arguments[ 1 ];
    245 		if ( !isNonNegativeInteger( byteOffset ) ) {
    246 			throw new TypeError( 'invalid argument. Byte offset must be a nonnegative integer. Value: `'+byteOffset+'`.' );
    247 		}
    248 		if ( !isInteger( byteOffset/BYTES_PER_ELEMENT ) ) {
    249 			throw new RangeError( 'invalid argument. Byte offset must be a multiple of '+BYTES_PER_ELEMENT+'. Value: `'+byteOffset+'`.' );
    250 		}
    251 		if ( nargs === 2 ) {
    252 			len = buf.byteLength - byteOffset;
    253 			if ( !isInteger( len/BYTES_PER_ELEMENT ) ) {
    254 				throw new RangeError( 'invalid arguments. ArrayBuffer view byte length must be a multiple of '+BYTES_PER_ELEMENT+'. View byte length: `'+len+'`.' );
    255 			}
    256 			buf = new Float32Array( buf, byteOffset );
    257 		} else {
    258 			len = arguments[ 2 ];
    259 			if ( !isNonNegativeInteger( len ) ) {
    260 				throw new TypeError( 'invalid argument. Length must be a nonnegative integer. Value: `'+len+'`.' );
    261 			}
    262 			if ( (len*BYTES_PER_ELEMENT) > (buf.byteLength-byteOffset) ) {
    263 				throw new RangeError( 'invalid arguments. ArrayBuffer has insufficient capacity. Either decrease the array length or provide a bigger buffer. Minimum capacity: `'+(len*BYTES_PER_ELEMENT)+'`.' );
    264 			}
    265 			buf = new Float32Array( buf, byteOffset, len*2 );
    266 		}
    267 	}
    268 	defineProperty( this, '_buffer', {
    269 		'configurable': false,
    270 		'enumerable': false,
    271 		'writable': false,
    272 		'value': buf
    273 	});
    274 	defineProperty( this, '_length', {
    275 		'configurable': false,
    276 		'enumerable': false,
    277 		'writable': false,
    278 		'value': buf.length / 2
    279 	});
    280 
    281 	return this;
    282 }
    283 
    284 /**
    285 * Size (in bytes) of each array element.
    286 *
    287 * @name BYTES_PER_ELEMENT
    288 * @memberof Complex64Array
    289 * @type {PositiveInteger}
    290 * @default 8
    291 *
    292 * @example
    293 * var nbytes = Complex64Array.BYTES_PER_ELEMENT;
    294 * // returns 8
    295 */
    296 defineProperty( Complex64Array, 'BYTES_PER_ELEMENT', {
    297 	'configurable': false,
    298 	'enumerable': false,
    299 	'writable': false,
    300 	'value': BYTES_PER_ELEMENT
    301 });
    302 
    303 /**
    304 * Constructor name.
    305 *
    306 * @name name
    307 * @memberof Complex64Array
    308 * @type {string}
    309 * @default 'Complex64Array'
    310 *
    311 * @example
    312 * var str = Complex64Array.name;
    313 * // returns 'Complex64Array'
    314 */
    315 defineProperty( Complex64Array, 'name', {
    316 	'configurable': false,
    317 	'enumerable': false,
    318 	'writable': false,
    319 	'value': 'Complex64Array'
    320 });
    321 
    322 /**
    323 * Creates a new 64-bit complex number array from an array-like object or an iterable.
    324 *
    325 * @name from
    326 * @memberof Complex64Array
    327 * @type {Function}
    328 * @param {(ArrayLikeObject|Iterable)} src - array-like object or iterable
    329 * @param {Function} [clbk] - callback to invoke for each source element
    330 * @param {*} [thisArg] - context
    331 * @throws {TypeError} `this` context must be a constructor
    332 * @throws {TypeError} `this` must be a complex number array
    333 * @throws {TypeError} first argument must be an array-like object or an iterable
    334 * @throws {TypeError} second argument must be a function
    335 * @throws {RangeError} array-like objects must have a length which is a multiple of two
    336 * @throws {TypeError} an iterator must return either a two element array containing real and imaginary components or a complex number
    337 * @throws {TypeError} when provided an iterator, a callback must return either a two element array containing real and imaginary components or a complex number
    338 * @returns {Complex64Array} 64-bit complex number array
    339 *
    340 * @example
    341 * var arr = Complex64Array.from( [ 1.0, -1.0 ] );
    342 * // returns <Complex64Array>
    343 *
    344 * var len = arr.length;
    345 * // returns 1
    346 *
    347 * @example
    348 * var Complex64 = require( '@stdlib/complex/float32' );
    349 *
    350 * var arr = Complex64Array.from( [ new Complex64( 1.0, 1.0 ) ] );
    351 * // returns <Complex64Array>
    352 *
    353 * var len = arr.length;
    354 * // returns 1
    355 *
    356 * @example
    357 * var Complex64 = require( '@stdlib/complex/float32' );
    358 * var real = require( '@stdlib/complex/real' );
    359 * var imag = require( '@stdlib/complex/imag' );
    360 *
    361 * function clbk( v ) {
    362 *     return new Complex64( real(v)*2.0, imag(v)*2.0 );
    363 * }
    364 *
    365 * var arr = Complex64Array.from( [ new Complex64( 1.0, 1.0 ) ], clbk );
    366 * // returns <Complex64Array>
    367 *
    368 * var len = arr.length;
    369 * // returns 1
    370 */
    371 defineProperty( Complex64Array, 'from', {
    372 	'configurable': false,
    373 	'enumerable': false,
    374 	'writable': false,
    375 	'value': function from( src ) {
    376 		var thisArg;
    377 		var nargs;
    378 		var clbk;
    379 		var out;
    380 		var buf;
    381 		var tmp;
    382 		var len;
    383 		var flg;
    384 		var v;
    385 		var i;
    386 		var j;
    387 		if ( !isFunction( this ) ) {
    388 			throw new TypeError( 'invalid invocation. `this` context must be a constructor.' );
    389 		}
    390 		if ( !isComplexArrayConstructor( this ) ) {
    391 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    392 		}
    393 		nargs = arguments.length;
    394 		if ( nargs > 1 ) {
    395 			clbk = arguments[ 1 ];
    396 			if ( !isFunction( clbk ) ) {
    397 				throw new TypeError( 'invalid argument. Second argument must be a function. Value: `'+clbk+'`.' );
    398 			}
    399 			if ( nargs > 2 ) {
    400 				thisArg = arguments[ 2 ];
    401 			}
    402 		}
    403 		if ( isCollection( src ) ) {
    404 			if ( clbk ) {
    405 				// Note: array contents affect how we iterate over a provided data source. If only complex numbers, we can extract real and imaginary components. Otherwise, we assume a strided array where real and imaginary components are interleaved. In the former case, we expect a callback to return real and imaginary components (possibly as a complex number). In the latter case, we expect a callback to return *either* a real or imaginary component.
    406 
    407 				// Detect whether we've been provided an array of complex numbers...
    408 				len = src.length;
    409 				for ( i = 0; i < len; i++ ) {
    410 					if ( !isComplexLike( src[ i ] ) ) {
    411 						flg = true;
    412 						break;
    413 					}
    414 				}
    415 				// If an array does not contain only complex numbers, then we assume interleaved real and imaginary components...
    416 				if ( flg ) {
    417 					if ( !isEven( len ) ) {
    418 						throw new RangeError( 'invalid argument. First argument must have a length which is a multiple of two. Length: `'+len+'`.' );
    419 					}
    420 					out = new this( len/2 );
    421 					buf = out._buffer; // eslint-disable-line no-underscore-dangle
    422 					for ( i = 0; i < len; i++ ) {
    423 						buf[ i ] = clbk.call( thisArg, src[ i ], i );
    424 					}
    425 				}
    426 				// If an array contains only complex numbers, then we need to extract real and imaginary components...
    427 				else {
    428 					out = new this( len );
    429 					buf = out._buffer; // eslint-disable-line no-underscore-dangle
    430 					j = 0;
    431 					for ( i = 0; i < len; i++ ) {
    432 						v = clbk.call( thisArg, src[ i ], i );
    433 						if ( isComplexLike( v ) ) {
    434 							buf[ j ] = real( v );
    435 							buf[ j+1 ] = imag( v );
    436 						} else if ( isArrayLikeObject( v ) && v.length >= 2 ) {
    437 							buf[ j ] = v[ 0 ];
    438 							buf[ j+1 ] = v[ 1 ];
    439 						} else {
    440 							throw new TypeError( 'invalid argument. Callback must return either a two-element array containing real and imaginary components or a complex number. Value: `'+v+'`.' );
    441 						}
    442 						j += 2; // stride
    443 					}
    444 				}
    445 			} else {
    446 				out = new this( src );
    447 			}
    448 		} else if ( isObject( src ) && HAS_ITERATOR_SYMBOL && isFunction( src[ ITERATOR_SYMBOL ] ) ) { // eslint-disable-line max-len
    449 			buf = src[ ITERATOR_SYMBOL ]();
    450 			if ( !isFunction( buf.next ) ) {
    451 				throw new TypeError( 'invalid argument. First argument must be an array-like object or an iterable.' );
    452 			}
    453 			if ( clbk ) {
    454 				tmp = fromIteratorMap( buf, clbk, thisArg );
    455 			} else {
    456 				tmp = fromIterator( buf );
    457 			}
    458 			if ( tmp instanceof Error ) {
    459 				throw tmp;
    460 			}
    461 			len = tmp.length / 2;
    462 			out = new this( len );
    463 			buf = out._buffer; // eslint-disable-line no-underscore-dangle
    464 			for ( i = 0; i < len; i++ ) {
    465 				buf[ i ] = tmp[ i ];
    466 			}
    467 		} else {
    468 			throw new TypeError( 'invalid argument. First argument must be an array-like object or an iterable. Value: `'+src+'`.' );
    469 		}
    470 		return out;
    471 	}
    472 });
    473 
    474 /**
    475 * Creates a new 64-bit complex number array from a variable number of arguments.
    476 *
    477 * @name of
    478 * @memberof Complex64Array
    479 * @type {Function}
    480 * @param {...*} element - array elements
    481 * @throws {TypeError} `this` context must be a constructor
    482 * @throws {TypeError} `this` must be a complex number array
    483 * @returns {Complex64Array} 64-bit complex number array
    484 *
    485 * @example
    486 * var arr = Complex64Array.of( 1.0, 1.0, 1.0, 1.0 );
    487 * // returns <Complex64Array>
    488 *
    489 * var len = arr.length;
    490 * // returns 2
    491 */
    492 defineProperty( Complex64Array, 'of', {
    493 	'configurable': false,
    494 	'enumerable': false,
    495 	'writable': false,
    496 	'value': function of() {
    497 		var args;
    498 		var i;
    499 		if ( !isFunction( this ) ) {
    500 			throw new TypeError( 'invalid invocation. `this` context must be a constructor.' );
    501 		}
    502 		if ( !isComplexArrayConstructor( this ) ) {
    503 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    504 		}
    505 		args = [];
    506 		for ( i = 0; i < arguments.length; i++ ) {
    507 			args.push( arguments[ i ] );
    508 		}
    509 		return new this( args );
    510 	}
    511 });
    512 
    513 /**
    514 * Pointer to the underlying data buffer.
    515 *
    516 * @name buffer
    517 * @memberof Complex64Array.prototype
    518 * @type {ArrayBuffer}
    519 *
    520 * @example
    521 * var arr = new Complex64Array( 10 );
    522 *
    523 * var buf = arr.buffer;
    524 * // returns <ArrayBuffer>
    525 */
    526 defineProperty( Complex64Array.prototype, 'buffer', {
    527 	'configurable': false,
    528 	'enumerable': false,
    529 	'get': function get() {
    530 		return this._buffer.buffer;
    531 	}
    532 });
    533 
    534 /**
    535 * Size (in bytes) of the array.
    536 *
    537 * @name byteLength
    538 * @memberof Complex64Array.prototype
    539 * @type {NonNegativeInteger}
    540 *
    541 * @example
    542 * var arr = new Complex64Array( 10 );
    543 *
    544 * var byteLength = arr.byteLength;
    545 * // returns 80
    546 */
    547 defineProperty( Complex64Array.prototype, 'byteLength', {
    548 	'configurable': false,
    549 	'enumerable': false,
    550 	'get': function get() {
    551 		return this._buffer.byteLength;
    552 	}
    553 });
    554 
    555 /**
    556 * Offset (in bytes) of the array from the start of its underlying `ArrayBuffer`.
    557 *
    558 * @name byteOffset
    559 * @memberof Complex64Array.prototype
    560 * @type {NonNegativeInteger}
    561 *
    562 * @example
    563 * var arr = new Complex64Array( 10 );
    564 *
    565 * var byteOffset = arr.byteOffset;
    566 * // returns 0
    567 */
    568 defineProperty( Complex64Array.prototype, 'byteOffset', {
    569 	'configurable': false,
    570 	'enumerable': false,
    571 	'get': function get() {
    572 		return this._buffer.byteOffset;
    573 	}
    574 });
    575 
    576 /**
    577 * Size (in bytes) of each array element.
    578 *
    579 * @name BYTES_PER_ELEMENT
    580 * @memberof Complex64Array.prototype
    581 * @type {PositiveInteger}
    582 * @default 8
    583 *
    584 * @example
    585 * var arr = new Complex64Array( 10 );
    586 *
    587 * var nbytes = arr.BYTES_PER_ELEMENT;
    588 * // returns 8
    589 */
    590 defineProperty( Complex64Array.prototype, 'BYTES_PER_ELEMENT', {
    591 	'configurable': false,
    592 	'enumerable': false,
    593 	'writable': false,
    594 	'value': Complex64Array.BYTES_PER_ELEMENT
    595 });
    596 
    597 /**
    598 * Copies a sequence of elements within the array to the position starting at `target`.
    599 *
    600 * @name copyWithin
    601 * @memberof Complex64Array.prototype
    602 * @type {Function}
    603 * @param {integer} target - index at which to start copying elements
    604 * @param {integer} start - source index at which to copy elements from
    605 * @param {integer} [end] - source index at which to stop copying elements from
    606 * @throws {TypeError} `this` must be a complex number array
    607 * @returns {Complex64Array} modified array
    608 *
    609 * @example
    610 * var Complex64 = require( '@stdlib/complex/float32' );
    611 * var real = require( '@stdlib/complex/real' );
    612 * var imag = require( '@stdlib/complex/imag' );
    613 *
    614 * var arr = new Complex64Array( 4 );
    615 *
    616 * // Set the array elements:
    617 * arr.set( new Complex64( 1.0, 1.0 ), 0 );
    618 * arr.set( new Complex64( 2.0, 2.0 ), 1 );
    619 * arr.set( new Complex64( 3.0, 3.0 ), 2 );
    620 * arr.set( new Complex64( 4.0, 4.0 ), 3 );
    621 *
    622 * // Copy the first two elements to the last two elements:
    623 * arr.copyWithin( 2, 0, 2 );
    624 *
    625 * // Get the last array element:
    626 * var z = arr.get( 3 );
    627 *
    628 * var re = real( z );
    629 * // returns 2.0
    630 *
    631 * var im = imag( z );
    632 * // returns 2.0
    633 */
    634 defineProperty( Complex64Array.prototype, 'copyWithin', {
    635 	'configurable': false,
    636 	'enumerable': false,
    637 	'writable': false,
    638 	'value': function copyWithin( target, start ) {
    639 		if ( !isComplexArray( this ) ) {
    640 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    641 		}
    642 		// FIXME: prefer a functional `copyWithin` implementation which addresses lack of universal browser support (e.g., IE11 and Safari) or ensure that typed arrays are polyfilled
    643 		if ( arguments.length === 2 ) {
    644 			this._buffer.copyWithin( target*2, start*2 );
    645 		} else {
    646 			this._buffer.copyWithin( target*2, start*2, arguments[2]*2 );
    647 		}
    648 		return this;
    649 	}
    650 });
    651 
    652 /**
    653 * Returns an iterator for iterating over array key-value pairs.
    654 *
    655 * @name entries
    656 * @memberof Complex64Array.prototype
    657 * @type {Function}
    658 * @throws {TypeError} `this` must be a complex number array
    659 * @returns {Iterator} iterator
    660 *
    661 * @example
    662 * var Complex64 = require( '@stdlib/complex/float32' );
    663 *
    664 * var arr = [
    665 *     new Complex64( 1.0, 1.0 ),
    666 *     new Complex64( 2.0, 2.0 ),
    667 *     new Complex64( 3.0, 3.0 )
    668 * ];
    669 * arr = new Complex64Array( arr );
    670 *
    671 * // Create an iterator:
    672 * var it = arr.entries();
    673 *
    674 * // Iterate over the key-value pairs...
    675 * var v = it.next().value;
    676 * // returns [ 0, <Complex64> ]
    677 *
    678 * v = it.next().value;
    679 * // returns [ 1, <Complex64> ]
    680 *
    681 * v = it.next().value;
    682 * // returns [ 2, <Complex64> ]
    683 *
    684 * var bool = it.next().done;
    685 * // returns true
    686 */
    687 defineProperty( Complex64Array.prototype, 'entries', {
    688 	'configurable': false,
    689 	'enumerable': false,
    690 	'writable': false,
    691 	'value': function entries() {
    692 		var buffer;
    693 		var self;
    694 		var iter;
    695 		var len;
    696 		var FLG;
    697 		var i;
    698 		var j;
    699 		if ( !isComplexArray( this ) ) {
    700 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    701 		}
    702 		self = this;
    703 		buffer = this._buffer;
    704 		len = this._length;
    705 
    706 		// Initialize the iteration indices:
    707 		i = -1;
    708 		j = -2;
    709 
    710 		// Create an iterator protocol-compliant object:
    711 		iter = {};
    712 		defineProperty( iter, 'next', {
    713 			'configurable': false,
    714 			'enumerable': false,
    715 			'writable': false,
    716 			'value': next
    717 		});
    718 		defineProperty( iter, 'return', {
    719 			'configurable': false,
    720 			'enumerable': false,
    721 			'writable': false,
    722 			'value': end
    723 		});
    724 		if ( ITERATOR_SYMBOL ) {
    725 			defineProperty( iter, ITERATOR_SYMBOL, {
    726 				'configurable': false,
    727 				'enumerable': false,
    728 				'writable': false,
    729 				'value': factory
    730 			});
    731 		}
    732 		return iter;
    733 
    734 		/**
    735 		* Returns an iterator protocol-compliant object containing the next iterated value.
    736 		*
    737 		* @private
    738 		* @returns {Object} iterator protocol-compliant object
    739 		*/
    740 		function next() {
    741 			var z;
    742 			i += 1;
    743 			if ( FLG || i >= len ) {
    744 				return {
    745 					'done': true
    746 				};
    747 			}
    748 			j += 2;
    749 			z = new Complex64( buffer[ j ], buffer[ j+1 ] );
    750 			return {
    751 				'value': [ i, z ],
    752 				'done': false
    753 			};
    754 		}
    755 
    756 		/**
    757 		* Finishes an iterator.
    758 		*
    759 		* @private
    760 		* @param {*} [value] - value to return
    761 		* @returns {Object} iterator protocol-compliant object
    762 		*/
    763 		function end( value ) {
    764 			FLG = true;
    765 			if ( arguments.length ) {
    766 				return {
    767 					'value': value,
    768 					'done': true
    769 				};
    770 			}
    771 			return {
    772 				'done': true
    773 			};
    774 		}
    775 
    776 		/**
    777 		* Returns a new iterator.
    778 		*
    779 		* @private
    780 		* @returns {Iterator} iterator
    781 		*/
    782 		function factory() {
    783 			return self.entries();
    784 		}
    785 	}
    786 });
    787 
    788 /**
    789 * Returns an array element.
    790 *
    791 * @name get
    792 * @memberof Complex64Array.prototype
    793 * @type {Function}
    794 * @param {ArrayLikeObject} [out] - output array
    795 * @param {NonNegativeInteger} i - element index
    796 * @throws {TypeError} `this` must be a complex number array
    797 * @throws {TypeError} index argument must be a nonnegative integer
    798 * @throws {TypeError} output argument must be an array-like object
    799 * @returns {(Complex64|ArrayLikeObject|void)} array element
    800 *
    801 * @example
    802 * var arr = new Complex64Array( 10 );
    803 *
    804 * var z = arr.get( 0 );
    805 * // returns <Complex64>
    806 *
    807 * arr.set( [ 1.0, -1.0 ], 0 );
    808 *
    809 * z = arr.get( [ 0.0, 0.0 ], 0 );
    810 * // returns [ 1.0, -1.0 ]
    811 *
    812 * z = arr.get( 100 );
    813 * // returns undefined
    814 */
    815 defineProperty( Complex64Array.prototype, 'get', {
    816 	'configurable': false,
    817 	'enumerable': false,
    818 	'writable': false,
    819 	'value': function get( i ) {
    820 		var idx;
    821 		var out;
    822 		var buf;
    823 
    824 		if ( !isComplexArray( this ) ) {
    825 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    826 		}
    827 		buf = this._buffer;
    828 		if ( arguments.length > 1 ) {
    829 			idx = arguments[ 1 ];
    830 			out = i;
    831 			if ( !isArrayLikeObject( out ) || out.length < 2 ) {
    832 				throw new TypeError( 'invalid argument. Output argument must be an array-like object. Value: `'+out+'`.' );
    833 			}
    834 		} else {
    835 			idx = i;
    836 		}
    837 		if ( !isNonNegativeInteger( idx ) ) {
    838 			throw new TypeError( 'invalid argument. Index argument must be a nonnegative integer. Value: `'+idx+'`.' );
    839 		}
    840 		if ( idx >= this._length ) {
    841 			return;
    842 		}
    843 		idx *= 2;
    844 		if ( out ) {
    845 			out[ 0 ] = buf[ idx ];
    846 			out[ 1 ] = buf[ idx+1 ];
    847 			return out;
    848 		}
    849 		return new Complex64( buf[ idx ], buf[ idx+1 ] );
    850 	}
    851 });
    852 
    853 /**
    854 * Number of array elements.
    855 *
    856 * @name length
    857 * @memberof Complex64Array.prototype
    858 * @type {NonNegativeInteger}
    859 *
    860 * @example
    861 * var arr = new Complex64Array( 10 );
    862 *
    863 * var len = arr.length;
    864 * // returns 10
    865 */
    866 defineProperty( Complex64Array.prototype, 'length', {
    867 	'configurable': false,
    868 	'enumerable': false,
    869 	'get': function get() {
    870 		return this._length;
    871 	}
    872 });
    873 
    874 /**
    875 * Sets an array element.
    876 *
    877 * ## Notes
    878 *
    879 * -   When provided a typed array, real or complex, we must check whether the source array shares the same buffer as the target array and whether the underlying memory overlaps. In particular, we are concerned with the following scenario:
    880 *
    881 *     ```text
    882 *     buf:                ---------------------
    883 *     src: ---------------------
    884 *     ```
    885 *
    886 *     In the above, as we copy values from `src`, we will overwrite values in the `src` view, resulting in duplicated values copied into the end of `buf`, which is not intended. Hence, to avoid overwriting source values, we must **copy** source values to a temporary array.
    887 *
    888 *     In the other overlapping scenario,
    889 *
    890 *     ```text
    891 *     buf: ---------------------
    892 *     src:                ---------------------
    893 *     ```
    894 *
    895 *     by the time we begin copying into the overlapping region, we are copying from the end of `src`, a non-overlapping region, which means we don't run the risk of copying copied values, rather than the original `src` values as intended.
    896 *
    897 *
    898 * @name set
    899 * @memberof Complex64Array.prototype
    900 * @type {Function}
    901 * @param {(Collection|Complex|ComplexArray)} value - value(s)
    902 * @param {NonNegativeInteger} [i=0] - element index at which to start writing values
    903 * @throws {TypeError} `this` must be a complex number array
    904 * @throws {TypeError} first argument must be either a complex number, an array-like object, or a complex number array
    905 * @throws {TypeError} index argument must be a nonnegative integer
    906 * @throws {RangeError} array-like objects must have a length which is a multiple of two
    907 * @throws {RangeError} index argument is out-of-bounds
    908 * @throws {RangeError} target array lacks sufficient storage to accommodate source values
    909 * @returns {void}
    910 *
    911 * @example
    912 * var real = require( '@stdlib/complex/real' );
    913 * var imag = require( '@stdlib/complex/imag' );
    914 *
    915 * var arr = new Complex64Array( 10 );
    916 *
    917 * var z = arr.get( 0 );
    918 * // returns <Complex64>
    919 *
    920 * var re = real( z );
    921 * // returns 0.0
    922 *
    923 * var im = imag( z );
    924 * // returns 0.0
    925 *
    926 * arr.set( [ 1.0, -1.0 ], 0 );
    927 *
    928 * z = arr.get( 0 );
    929 * // returns <Complex64>
    930 *
    931 * re = real( z );
    932 * // returns 1.0
    933 *
    934 * im = imag( z );
    935 * // returns -1.0
    936 */
    937 defineProperty( Complex64Array.prototype, 'set', {
    938 	'configurable': false,
    939 	'enumerable': false,
    940 	'writable': false,
    941 	'value': function set( value ) {
    942 		/* eslint-disable no-underscore-dangle */
    943 		var sbuf;
    944 		var idx;
    945 		var buf;
    946 		var tmp;
    947 		var flg;
    948 		var N;
    949 		var v;
    950 		var i;
    951 		var j;
    952 		if ( !isComplexArray( this ) ) {
    953 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    954 		}
    955 		buf = this._buffer;
    956 		if ( arguments.length > 1 ) {
    957 			idx = arguments[ 1 ];
    958 			if ( !isNonNegativeInteger( idx ) ) {
    959 				throw new TypeError( 'invalid argument. Index argument must be a nonnegative integer. Value: `'+idx+'`.' );
    960 			}
    961 		} else {
    962 			idx = 0;
    963 		}
    964 		if ( isComplexLike( value ) ) {
    965 			if ( idx >= this._length ) {
    966 				throw new RangeError( 'invalid argument. Index argument is out-of-bounds. Value: `'+idx+'`.' );
    967 			}
    968 			idx *= 2;
    969 			buf[ idx ] = real( value );
    970 			buf[ idx+1 ] = imag( value );
    971 			return;
    972 		}
    973 		if ( isComplexArray( value ) ) {
    974 			N = value._length;
    975 			if ( idx+N > this._length ) {
    976 				throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
    977 			}
    978 			sbuf = value._buffer;
    979 
    980 			// Check for overlapping memory...
    981 			j = buf.byteOffset + (idx*BYTES_PER_ELEMENT);
    982 			if (
    983 				sbuf.buffer === buf.buffer &&
    984 				(
    985 					sbuf.byteOffset < j &&
    986 					sbuf.byteOffset+sbuf.byteLength > j
    987 				)
    988 			) {
    989 				// We need to copy source values...
    990 				tmp = new Float32Array( sbuf.length );
    991 				for ( i = 0; i < sbuf.length; i++ ) {
    992 					tmp[ i ] = sbuf[ i ];
    993 				}
    994 				sbuf = tmp;
    995 			}
    996 			idx *= 2;
    997 			j = 0;
    998 			for ( i = 0; i < N; i++ ) {
    999 				buf[ idx ] = sbuf[ j ];
   1000 				buf[ idx+1 ] = sbuf[ j+1 ];
   1001 				idx += 2; // stride
   1002 				j += 2; // stride
   1003 			}
   1004 			return;
   1005 		}
   1006 		if ( isCollection( value ) ) {
   1007 			// Detect whether we've been provided an array of complex numbers...
   1008 			N = value.length;
   1009 			for ( i = 0; i < N; i++ ) {
   1010 				if ( !isComplexLike( value[ i ] ) ) {
   1011 					flg = true;
   1012 					break;
   1013 				}
   1014 			}
   1015 			// If an array does not contain only complex numbers, then we assume interleaved real and imaginary components...
   1016 			if ( flg ) {
   1017 				if ( !isEven( N ) ) {
   1018 					throw new RangeError( 'invalid argument. Array-like object arguments must have a length which is a multiple of two. Length: `'+N+'`.' );
   1019 				}
   1020 				if ( idx+(N/2) > this._length ) {
   1021 					throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
   1022 				}
   1023 				sbuf = value;
   1024 
   1025 				// Check for overlapping memory...
   1026 				j = buf.byteOffset + (idx*BYTES_PER_ELEMENT);
   1027 				if (
   1028 					sbuf.buffer === buf.buffer &&
   1029 					(
   1030 						sbuf.byteOffset < j &&
   1031 						sbuf.byteOffset+sbuf.byteLength > j
   1032 					)
   1033 				) {
   1034 					// We need to copy source values...
   1035 					tmp = new Float32Array( N );
   1036 					for ( i = 0; i < N; i++ ) {
   1037 						tmp[ i ] = sbuf[ i ];
   1038 					}
   1039 					sbuf = tmp;
   1040 				}
   1041 				idx *= 2;
   1042 				N /= 2;
   1043 				j = 0;
   1044 				for ( i = 0; i < N; i++ ) {
   1045 					buf[ idx ] = sbuf[ j ];
   1046 					buf[ idx+1 ] = sbuf[ j+1 ];
   1047 					idx += 2; // stride
   1048 					j += 2; // stride
   1049 				}
   1050 				return;
   1051 			}
   1052 			// If an array contains only complex numbers, then we need to extract real and imaginary components...
   1053 			if ( idx+N > this._length ) {
   1054 				throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
   1055 			}
   1056 			idx *= 2;
   1057 			for ( i = 0; i < N; i++ ) {
   1058 				v = value[ i ];
   1059 				buf[ idx ] = real( v );
   1060 				buf[ idx+1 ] = imag( v );
   1061 				idx += 2; // stride
   1062 			}
   1063 			return;
   1064 		}
   1065 		throw new TypeError( 'invalid argument. First argument must be either a complex number, an array-like object, or a complex number array. Value: `'+value+'`.' );
   1066 
   1067 		/* eslint-enable no-underscore-dangle */
   1068 	}
   1069 });
   1070 
   1071 
   1072 // EXPORTS //
   1073 
   1074 module.exports = Complex64Array;