time-to-botec

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

main.js (27201B)


      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-restricted-syntax */
     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 Float64Array = require( './../../float64' );
     39 var Complex128 = require( '@stdlib/complex/float64' );
     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 = Float64Array.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 Complex128Array ||
     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 === Complex128Array ||
     90 
     91 		// NOTE: weaker test in order to avoid a circular dependency with Complex64Array...
     92 		value.name === 'Complex64Array'
     93 	);
     94 }
     95 
     96 
     97 // MAIN //
     98 
     99 /**
    100 * 128-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 `16`
    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 `16`
    111 * @throws {TypeError} view length must be a positive multiple of `16`
    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 {Complex128Array} complex number array
    115 *
    116 * @example
    117 * var arr = new Complex128Array();
    118 * // returns <Complex128Array>
    119 *
    120 * var len = arr.length;
    121 * // returns 0
    122 *
    123 * @example
    124 * var arr = new Complex128Array( 2 );
    125 * // returns <Complex128Array>
    126 *
    127 * var len = arr.length;
    128 * // returns 2
    129 *
    130 * @example
    131 * var arr = new Complex128Array( [ 1.0, -1.0 ] );
    132 * // returns <Complex128Array>
    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( 32 );
    141 * var arr = new Complex128Array( buf );
    142 * // returns <Complex128Array>
    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( 32 );
    151 * var arr = new Complex128Array( buf, 16 );
    152 * // returns <Complex128Array>
    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( 64 );
    161 * var arr = new Complex128Array( buf, 16, 2 );
    162 * // returns <Complex128Array>
    163 *
    164 * var len = arr.length;
    165 * // returns 2
    166 */
    167 function Complex128Array() {
    168 	var byteOffset;
    169 	var nargs;
    170 	var buf;
    171 	var len;
    172 
    173 	nargs = arguments.length;
    174 	if ( !(this instanceof Complex128Array) ) {
    175 		if ( nargs === 0 ) {
    176 			return new Complex128Array();
    177 		}
    178 		if ( nargs === 1 ) {
    179 			return new Complex128Array( arguments[0] );
    180 		}
    181 		if ( nargs === 2 ) {
    182 			return new Complex128Array( arguments[0], arguments[1] );
    183 		}
    184 		return new Complex128Array( arguments[0], arguments[1], arguments[2] );
    185 	}
    186 	// Create the underlying data buffer...
    187 	if ( nargs === 0 ) {
    188 		buf = new Float64Array( 0 ); // backward-compatibility
    189 	} else if ( nargs === 1 ) {
    190 		if ( isNonNegativeInteger( arguments[0] ) ) {
    191 			buf = new Float64Array( 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 Float64Array( 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 Float64Array( 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 Float64Array( 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 Float64Array( 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 Float64Array( 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 Float64Array( 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 Float64Array( 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 Complex128Array
    289 * @type {PositiveInteger}
    290 * @default 16
    291 *
    292 * @example
    293 * var nbytes = Complex128Array.BYTES_PER_ELEMENT;
    294 * // returns 16
    295 */
    296 defineProperty( Complex128Array, '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 Complex128Array
    308 * @type {string}
    309 * @default 'Complex128Array'
    310 *
    311 * @example
    312 * var name = Complex128Array.name;
    313 * // returns 'Complex128Array'
    314 */
    315 defineProperty( Complex128Array, 'name', {
    316 	'configurable': false,
    317 	'enumerable': false,
    318 	'writable': false,
    319 	'value': 'Complex128Array'
    320 });
    321 
    322 /**
    323 * Creates a new 128-bit complex number array from an array-like object or an iterable.
    324 *
    325 * @name from
    326 * @memberof Complex128Array
    327 * @type {Function}
    328 * @param {(ArrayLikeObject|Object)} 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 {Complex128Array} 128-bit complex number array
    339 *
    340 * @example
    341 * var arr = Complex128Array.from( [ 1.0, -1.0 ] );
    342 * // returns <Complex128Array>
    343 *
    344 * var len = arr.length;
    345 * // returns 1
    346 *
    347 * @example
    348 * var Complex128 = require( '@stdlib/complex/float64' );
    349 *
    350 * var arr = Complex128Array.from( [ new Complex128( 1.0, 1.0 ) ] );
    351 * // returns <Complex128Array>
    352 *
    353 * var len = arr.length;
    354 * // returns 1
    355 *
    356 * @example
    357 * var Complex128 = require( '@stdlib/complex/float64' );
    358 * var real = require( '@stdlib/complex/real' );
    359 * var imag = require( '@stdlib/complex/imag' );
    360 *
    361 * function clbk( v ) {
    362 *     return new Complex128( real(v)*2.0, imag(v)*2.0 );
    363 * }
    364 *
    365 * var arr = Complex128Array.from( [ new Complex128( 1.0, 1.0 ) ], clbk );
    366 * // returns <Complex128Array>
    367 *
    368 * var len = arr.length;
    369 * // returns 1
    370 */
    371 defineProperty( Complex128Array, '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 ) ) {
    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 128-bit complex number array from a variable number of arguments.
    476 *
    477 * @name of
    478 * @memberof Complex128Array
    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 {Complex128Array} 128-bit complex number array
    484 *
    485 * @example
    486 * var arr = Complex128Array.of( 1.0, 1.0, 1.0, 1.0 );
    487 * // returns <Complex128Array>
    488 *
    489 * var len = arr.length;
    490 * // returns 2
    491 */
    492 defineProperty( Complex128Array, '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 Complex128Array.prototype
    518 * @type {ArrayBuffer}
    519 *
    520 * @example
    521 * var arr = new Complex128Array( 10 );
    522 *
    523 * var buf = arr.buffer;
    524 * // returns <ArrayBuffer>
    525 */
    526 defineProperty( Complex128Array.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 Complex128Array.prototype
    539 * @type {NonNegativeInteger}
    540 *
    541 * @example
    542 * var arr = new Complex128Array( 10 );
    543 *
    544 * var byteLength = arr.byteLength;
    545 * // returns 160
    546 */
    547 defineProperty( Complex128Array.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 Complex128Array.prototype
    560 * @type {NonNegativeInteger}
    561 *
    562 * @example
    563 * var arr = new Complex128Array( 10 );
    564 *
    565 * var byteOffset = arr.byteOffset;
    566 * // returns 0
    567 */
    568 defineProperty( Complex128Array.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 Complex128Array.prototype
    581 * @type {PositiveInteger}
    582 * @default 16
    583 *
    584 * @example
    585 * var arr = new Complex128Array( 10 );
    586 *
    587 * var nbytes = arr.BYTES_PER_ELEMENT;
    588 * // returns 16
    589 */
    590 defineProperty( Complex128Array.prototype, 'BYTES_PER_ELEMENT', {
    591 	'configurable': false,
    592 	'enumerable': false,
    593 	'writable': false,
    594 	'value': Complex128Array.BYTES_PER_ELEMENT
    595 });
    596 
    597 /**
    598 * Returns an array element.
    599 *
    600 * @name get
    601 * @memberof Complex128Array.prototype
    602 * @type {Function}
    603 * @param {ArrayLikeObject} [out] - output array
    604 * @param {NonNegativeInteger} i - element index
    605 * @throws {TypeError} `this` must be a complex number array
    606 * @throws {TypeError} index argument must be a nonnegative integer
    607 * @throws {TypeError} output argument must be an array-like object
    608 * @returns {(Complex128|ArrayLikeObject|void)} array element
    609 *
    610 * @example
    611 * var arr = new Complex128Array( 10 );
    612 *
    613 * var z = arr.get( 0 );
    614 * // returns <Complex128>
    615 *
    616 * arr.set( [ 1.0, -1.0 ], 0 );
    617 *
    618 * z = arr.get( [ 0.0, 0.0 ], 0 );
    619 * // returns [ 1.0, -1.0 ]
    620 *
    621 * z = arr.get( 100 );
    622 * // returns undefined
    623 */
    624 defineProperty( Complex128Array.prototype, 'get', {
    625 	'configurable': false,
    626 	'enumerable': false,
    627 	'writable': false,
    628 	'value': function get( i ) {
    629 		var idx;
    630 		var out;
    631 		var buf;
    632 
    633 		if ( !isComplexArray( this ) ) {
    634 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    635 		}
    636 		buf = this._buffer;
    637 		if ( arguments.length > 1 ) {
    638 			idx = arguments[ 1 ];
    639 			out = i;
    640 			if ( !isArrayLikeObject( out ) || out.length < 2 ) {
    641 				throw new TypeError( 'invalid argument. Output argument must be an array-like object. Value: `'+out+'`.' );
    642 			}
    643 		} else {
    644 			idx = i;
    645 		}
    646 		if ( !isNonNegativeInteger( idx ) ) {
    647 			throw new TypeError( 'invalid argument. Index argument must be a nonnegative integer. Value: `'+idx+'`.' );
    648 		}
    649 		if ( idx >= this._length ) {
    650 			return;
    651 		}
    652 		idx *= 2;
    653 		if ( out ) {
    654 			out[ 0 ] = buf[ idx ];
    655 			out[ 1 ] = buf[ idx+1 ];
    656 			return out;
    657 		}
    658 		return new Complex128( buf[ idx ], buf[ idx+1 ] );
    659 	}
    660 });
    661 
    662 /**
    663 * Number of array elements.
    664 *
    665 * @name length
    666 * @memberof Complex128Array.prototype
    667 * @type {NonNegativeInteger}
    668 *
    669 * @example
    670 * var arr = new Complex128Array( 10 );
    671 *
    672 * var len = arr.length;
    673 * // returns 10
    674 */
    675 defineProperty( Complex128Array.prototype, 'length', {
    676 	'configurable': false,
    677 	'enumerable': false,
    678 	'get': function get() {
    679 		return this._length;
    680 	}
    681 });
    682 
    683 /**
    684 * Sets an array element.
    685 *
    686 * ## Notes
    687 *
    688 * -   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:
    689 *
    690 *     ```text
    691 *     buf:                ---------------------
    692 *     src: ---------------------
    693 *     ```
    694 *
    695 *     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.
    696 *
    697 *     In the other overlapping scenario,
    698 *
    699 *     ```text
    700 *     buf: ---------------------
    701 *     src:                ---------------------
    702 *     ```
    703 *
    704 *     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.
    705 *
    706 *
    707 * @name set
    708 * @memberof Complex128Array.prototype
    709 * @type {Function}
    710 * @param {(Collection|Complex|ComplexArray)} value - value(s)
    711 * @param {NonNegativeInteger} [i=0] - element index at which to start writing values
    712 * @throws {TypeError} `this` must be a complex number array
    713 * @throws {TypeError} first argument must be either a complex number, an array-like object, or a complex number array
    714 * @throws {TypeError} index argument must be a nonnegative integer
    715 * @throws {RangeError} array-like objects must have a length which is a multiple of two
    716 * @throws {RangeError} index argument is out-of-bounds
    717 * @throws {RangeError} target array lacks sufficient storage to accommodate source values
    718 * @returns {void}
    719 *
    720 * @example
    721 * var real = require( '@stdlib/complex/real' );
    722 * var imag = require( '@stdlib/complex/imag' );
    723 *
    724 * var arr = new Complex128Array( 10 );
    725 *
    726 * var z = arr.get( 0 );
    727 * // returns <Complex128>
    728 *
    729 * var re = real( z );
    730 * // returns 0.0
    731 *
    732 * var im = imag( z );
    733 * // returns 0.0
    734 *
    735 * arr.set( [ 1.0, -1.0 ], 0 );
    736 *
    737 * z = arr.get( 0 );
    738 * // returns <Complex128>
    739 *
    740 * re = real( z );
    741 * // returns 1.0
    742 *
    743 * im = imag( z );
    744 * // returns -1.0
    745 */
    746 defineProperty( Complex128Array.prototype, 'set', {
    747 	'configurable': false,
    748 	'enumerable': false,
    749 	'writable': false,
    750 	'value': function set( value ) {
    751 		/* eslint-disable no-underscore-dangle */
    752 		var dbuf;
    753 		var idx;
    754 		var buf;
    755 		var tmp;
    756 		var flg;
    757 		var N;
    758 		var v;
    759 		var i;
    760 		var j;
    761 		if ( !isComplexArray( this ) ) {
    762 			throw new TypeError( 'invalid invocation. `this` is not a complex number array.' );
    763 		}
    764 		buf = this._buffer;
    765 		if ( arguments.length > 1 ) {
    766 			idx = arguments[ 1 ];
    767 			if ( !isNonNegativeInteger( idx ) ) {
    768 				throw new TypeError( 'invalid argument. Index argument must be a nonnegative integer. Value: `'+idx+'`.' );
    769 			}
    770 		} else {
    771 			idx = 0;
    772 		}
    773 		if ( isComplexLike( value ) ) {
    774 			if ( idx >= this._length ) {
    775 				throw new RangeError( 'invalid argument. Index argument is out-of-bounds. Value: `'+idx+'`.' );
    776 			}
    777 			idx *= 2;
    778 			buf[ idx ] = real( value );
    779 			buf[ idx+1 ] = imag( value );
    780 			return;
    781 		}
    782 		if ( isComplexArray( value ) ) {
    783 			N = value._length;
    784 			if ( idx+N > this._length ) {
    785 				throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
    786 			}
    787 			dbuf = value._buffer;
    788 
    789 			// Check for overlapping memory...
    790 			j = buf.byteOffset + (idx*BYTES_PER_ELEMENT);
    791 			if (
    792 				dbuf.buffer === buf.buffer &&
    793 				(
    794 					dbuf.byteOffset < j &&
    795 					dbuf.byteOffset+dbuf.byteLength > j
    796 				)
    797 			) {
    798 				// We need to copy source values...
    799 				tmp = new Float64Array( dbuf.length );
    800 				for ( i = 0; i < dbuf.length; i++ ) {
    801 					tmp[ i ] = dbuf[ i ];
    802 				}
    803 				dbuf = tmp;
    804 			}
    805 			idx *= 2;
    806 			j = 0;
    807 			for ( i = 0; i < N; i++ ) {
    808 				buf[ idx ] = dbuf[ j ];
    809 				buf[ idx+1 ] = dbuf[ j+1 ];
    810 				idx += 2; // stride
    811 				j += 2; // stride
    812 			}
    813 			return;
    814 		}
    815 		if ( isCollection( value ) ) {
    816 			// Detect whether we've been provided an array of complex numbers...
    817 			N = value.length;
    818 			for ( i = 0; i < N; i++ ) {
    819 				if ( !isComplexLike( value[ i ] ) ) {
    820 					flg = true;
    821 					break;
    822 				}
    823 			}
    824 			// If an array does not contain only complex numbers, then we assume interleaved real and imaginary components...
    825 			if ( flg ) {
    826 				if ( !isEven( N ) ) {
    827 					throw new RangeError( 'invalid argument. Array-like object arguments must have a length which is a multiple of two. Length: `'+N+'`.' );
    828 				}
    829 				if ( idx+(N/2) > this._length ) {
    830 					throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
    831 				}
    832 				dbuf = value;
    833 
    834 				// Check for overlapping memory...
    835 				j = buf.byteOffset + (idx*BYTES_PER_ELEMENT);
    836 				if (
    837 					dbuf.buffer === buf.buffer &&
    838 					(
    839 						dbuf.byteOffset < j &&
    840 						dbuf.byteOffset+dbuf.byteLength > j
    841 					)
    842 				) {
    843 					// We need to copy source values...
    844 					tmp = new Float64Array( N );
    845 					for ( i = 0; i < N; i++ ) {
    846 						tmp[ i ] = dbuf[ i ];
    847 					}
    848 					dbuf = tmp;
    849 				}
    850 				idx *= 2;
    851 				N /= 2;
    852 				j = 0;
    853 				for ( i = 0; i < N; i++ ) {
    854 					buf[ idx ] = dbuf[ j ];
    855 					buf[ idx+1 ] = dbuf[ j+1 ];
    856 					idx += 2; // stride
    857 					j += 2; // stride
    858 				}
    859 				return;
    860 			}
    861 			// If an array contains only complex numbers, then we need to extract real and imaginary components...
    862 			if ( idx+N > this._length ) {
    863 				throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
    864 			}
    865 			idx *= 2;
    866 			for ( i = 0; i < N; i++ ) {
    867 				v = value[ i ];
    868 				buf[ idx ] = real( v );
    869 				buf[ idx+1 ] = imag( v );
    870 				idx += 2; // stride
    871 			}
    872 			return;
    873 		}
    874 		throw new TypeError( 'invalid argument. First argument must be either a complex number, an array-like object, or a complex number array. Value: `'+value+'`.' );
    875 
    876 		/* eslint-enable no-underscore-dangle */
    877 	}
    878 });
    879 
    880 
    881 // EXPORTS //
    882 
    883 module.exports = Complex128Array;