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;