diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4500383d..05708915 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -5,6 +5,7 @@ Adarsh Palaskar Aditya Sapra AgPriyanshu18 <113460573+AgPriyanshu18@users.noreply.github.com> +Aleksandr <112382387+alextes90@users.noreply.github.com> Ali Salesi Aman Bhansali Amit Jimiwal @@ -69,8 +70,10 @@ Seyyed Parsa Neshaei Shashank Shekhar Singh Shivam <11shivam00@gmail.com> Shraddheya Shendre +Shubh Mehta <93862397+Shubh942@users.noreply.github.com> Shubham Mishra Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> +Soumajit Chatterjee <121816890+soumajit23@users.noreply.github.com> Spandan Barve Stephannie Jiménez Gacha Suraj kumar <125961509+kumarsuraj212003@users.noreply.github.com> @@ -83,4 +86,5 @@ Yernar Yergaziyev naveen nishant-s7 <97207366+nishant-s7@users.noreply.github.com> orimiles5 <97595296+orimiles5@users.noreply.github.com> +rainn <88160429+AmCodesLame@users.noreply.github.com> rei2hu diff --git a/complex64/README.md b/complex64/README.md index a0ea0042..090c6102 100644 --- a/complex64/README.md +++ b/complex64/README.md @@ -1512,6 +1512,35 @@ var str = arr.join( '/' ); // returns '1 + 1i/2 - 2i/3 + 3i' ``` + + +#### Complex64Array.prototype.keys() + +Returns an iterator for iterating over each index key in a typed array. + +```javascript +var arr = new Complex64Array( 2 ); + +arr.set( [ 1.0, -1.0 ], 0 ); +arr.set( [ 2.0, -2.0 ], 1 ); + +var iter = arr.keys(); + +var v = iter.next().value; +// returns 0 + +v = iter.next().value; +// returns 1 + +var bool = iter.next().done; +// returns true +``` + +The returned [iterator][mdn-iterator-protocol] protocol-compliant object has the following properties: + +- **next**: function which returns an [iterator][mdn-iterator-protocol] protocol-compliant object containing the next iterated value (if one exists) assigned to a `value` property and a `done` property having a `boolean` value indicating whether the [iterator][mdn-iterator-protocol] is finished. +- **return**: function which closes an [iterator][mdn-iterator-protocol] and returns a single (optional) argument in an [iterator][mdn-iterator-protocol] protocol-compliant object. + #### Complex64Array.prototype.lastIndexOf( searchElement\[, fromIndex] ) diff --git a/complex64/benchmark/benchmark.keys.js b/complex64/benchmark/benchmark.keys.js new file mode 100644 index 00000000..ff908934 --- /dev/null +++ b/complex64/benchmark/benchmark.keys.js @@ -0,0 +1,51 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var isIteratorLike = require( '@stdlib/assert/is-iterator-like' ); +var pkg = require( './../package.json' ).name; +var Complex64Array = require( './../lib' ); + + +// MAIN // + +bench( pkg+':keys:len=2', function benchmark( b ) { + var iter; + var arr; + var i; + + arr = new Complex64Array( [ 1.0, -1.0, 2.0, -2.0 ] ); + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + iter = arr.keys(); + if ( typeof iter !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( !isIteratorLike( iter ) ) { + b.fail( 'should return an iterator protocol-compliant object' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/complex64/benchmark/benchmark.keys.length.js b/complex64/benchmark/benchmark.keys.length.js new file mode 100644 index 00000000..ece6056b --- /dev/null +++ b/complex64/benchmark/benchmark.keys.length.js @@ -0,0 +1,103 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var pow = require( '@stdlib/math/base/special/pow' ); +var Complex64 = require( '@stdlib/complex/float32' ); +var isIteratorLike = require('@stdlib/assert/is-iterator-like'); +var pkg = require( './../package.json' ).name; +var Complex64Array = require( './../lib' ); + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} len - array length +* @returns {Function} benchmark function +*/ +function createBenchmark( len ) { + var arr; + var i; + + arr = []; + for ( i = 0; i < len; i++ ) { + arr.push( new Complex64( i, i ) ); + } + arr = new Complex64Array( arr ); + + return benchmark; + + /** + * Benchmark function. + * + * @private + * @param {Benchmark} b - benchmark instance + */ + function benchmark( b ) { + var iter; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + iter = arr.keys(); + if ( typeof iter !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( !isIteratorLike( iter ) ) { + b.fail( 'should return an iterator protocol-compliant object' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var len; + var min; + var max; + var f; + var i; + + min = 1; // 10^min + max = 6; // 10^max + + for ( i = min; i <= max; i++ ) { + len = pow( 10, i ); + f = createBenchmark( len ); + bench( pkg+':keys:len='+len, f ); + } +} + +main(); diff --git a/complex64/docs/types/index.d.ts b/complex64/docs/types/index.d.ts index 4c6e94c6..f42a1be5 100644 --- a/complex64/docs/types/index.d.ts +++ b/complex64/docs/types/index.d.ts @@ -802,6 +802,30 @@ declare class Complex64Array implements Complex64ArrayInterface { */ join( separator?: string ): string; + /** + * Returns an iterator for iterating over each index key in a typed array. + * + * @returns iterator + * + * @example + * var arr = new Complex64Array( 2 ); + * + * arr.set( [ 1.0, 1.0 ], 0 ); + * arr.set( [ 2.0, 2.0 ], 1 ); + * + * var iter = arr.keys(); + * + * var v = iter.next().value; + * // returns 0 + * + * v = iter.next().value; + * // returns 1 + * + * var bool = iter.next().done; + * // returns true + */ + keys(): TypedIterator; + /** * Returns the last index at which a given element can be found. * diff --git a/complex64/lib/main.js b/complex64/lib/main.js index 113c0fb5..6ffa2479 100644 --- a/complex64/lib/main.js +++ b/complex64/lib/main.js @@ -1535,6 +1535,107 @@ setReadOnly( Complex64Array.prototype, 'join', function join( separator ) { return out.join( sep ); }); +/** +* Returns an iterator for iterating over each index key in a typed array. +* +* @name keys +* @memberof Complex64Array.prototype +* @type {Function} +* @throws {TypeError} `this` must be a complex number array +* @returns {Iterator} iterator +* +* @example +* var arr = new Complex64Array( 2 ); +* +* arr.set( [ 1.0, 1.0 ], 0 ); +* arr.set( [ 2.0, 2.0 ], 1 ); +* +* var iter = arr.keys(); +* +* var v = iter.next().value; +* // returns 0 +* +* v = iter.next().value; +* // returns 1 +* +* var bool = iter.next().done; +* // returns true +*/ +setReadOnly( Complex64Array.prototype, 'keys', function keys() { + var self; + var iter; + var len; + var FLG; + var i; + if ( !isComplexArray( this ) ) { + throw new TypeError( 'invalid invocation. `this` is not a complex number array.' ); + } + self = this; + len = this._length; + + // Initialize an iteration index: + i = -1; + + // Create an iterator protocol-compliant object: + iter = {}; + setReadOnly( iter, 'next', next ); + setReadOnly( iter, 'return', end ); + + if ( ITERATOR_SYMBOL ) { + setReadOnly( iter, ITERATOR_SYMBOL, factory ); + } + return iter; + + /** + * Returns an iterator protocol-compliant object containing the next iterated value. + * + * @private + * @returns {Object} iterator protocol-compliant object + */ + function next() { + i += 1; + if ( FLG || i >= len ) { + return { + 'done': true + }; + } + return { + 'value': i, + 'done': false + }; + } + + /** + * Finishes an iterator. + * + * @private + * @param {*} [value] - value to return + * @returns {Object} iterator protocol-compliant object + */ + function end( value ) { + FLG = true; + if ( arguments.length ) { + return { + 'value': value, + 'done': true + }; + } + return { + 'done': true + }; + } + + /** + * Returns a new iterator. + * + * @private + * @returns {Iterator} iterator + */ + function factory() { + return self.keys(); + } +}); + /** * Returns the last index at which a given element can be found. * diff --git a/complex64/test/test.keys.js b/complex64/test/test.keys.js new file mode 100644 index 00000000..9fba9620 --- /dev/null +++ b/complex64/test/test.keys.js @@ -0,0 +1,261 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var proxyquire = require( 'proxyquire' ); +var hasOwnProp = require( '@stdlib/assert/has-own-property' ); +var isFunction = require( '@stdlib/assert/is-function' ); +var ITERATOR_SYMBOL = require( '@stdlib/symbol/iterator' ); +var Complex64Array = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof Complex64Array, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'attached to the prototype of the main export is a `keys` method', function test( t ) { + t.strictEqual( hasOwnProp( Complex64Array.prototype, 'keys' ), true, 'has property' ); + t.strictEqual( isFunction( Complex64Array.prototype.keys ), true, 'has method' ); + t.end(); +}); + +tape( 'the method throws an error if invoked with a `this` context which is not a complex number array instance', function test( t ) { + var values; + var arr; + var i; + + arr = new Complex64Array( 5 ); + + values = [ + '5', + 5, + NaN, + true, + false, + null, + void 0, + {}, + [], + function noop() {} + ]; + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + return arr.keys.call( value ); + }; + } +}); + +tape( 'the method returns an iterator protocol-compliant object', function test( t ) { + var expected; + var arr; + var it; + var i; + var r; + var e; + + arr = new Complex64Array( [ 1.0, -1.0, 2.0, -2.0 ] ); + expected = [ + { + 'value': 0, + 'done': false + }, + { + 'value': 1, + 'done': false + }, + { + 'done': true + } + ]; + it = arr.keys(); + + t.strictEqual( typeof it, 'object', 'returns an object' ); + t.strictEqual( typeof it.next, 'function', 'has next method' ); + + for ( i = 0; i < expected.length; i++ ) { + r = it.next(); + e = expected[ i ]; + if ( e.value === void 0 ) { + t.deepEqual( r, e, 'returns expected value' ); + } else { + t.strictEqual( r.value, e.value, 'returns expected value' ); + t.strictEqual( r.done, e.done, 'returns expected value' ); + } + } + + t.end(); +}); + +tape( 'the method returns an iterator which does not iterate over empty arrays', function test( t ) { + var expected; + var arr; + var it; + var i; + var v; + + arr = new Complex64Array( [] ); + expected = [ + { + 'done': true + }, + { + 'done': true + }, + { + 'done': true + } + ]; + it = arr.keys(); + + t.strictEqual( typeof it, 'object', 'returns an object' ); + t.strictEqual( typeof it.next, 'function', 'has next method' ); + + for ( i = 0; i < expected.length; i++ ) { + v = it.next(); + t.deepEqual( v, expected[ i ], 'returns expected value' ); + } + t.end(); +}); + +tape( 'the returned iterator has a `return` method for closing an iterator (no argument)', function test( t ) { + var arr; + var it; + var v; + + arr = new Complex64Array( [ 1.0, -1.0, 2.0, -2.0, 3.0, -3.0 ] ); + it = arr.keys(); + + v = it.next(); + t.strictEqual( v.value, 0, 'returns expected value' ); + t.strictEqual( v.done, false, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, 1, 'returns expected value' ); + t.strictEqual( v.done, false, 'returns expected value' ); + + v = it.return(); + t.strictEqual( v.value, void 0, 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, void 0, 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, void 0, 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + t.end(); +}); + +tape( 'the returned iterator has a `return` method for closing an iterator (argument)', function test( t ) { + var arr; + var it; + var v; + + arr = new Complex64Array( [ 1.0, -1.0, 2.0, -2.0, 3.0, -3.0 ] ); + it = arr.keys(); + + v = it.next(); + t.strictEqual( v.value, 0, 'returns expected value' ); + t.strictEqual( v.done, false, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, 1, 'returns expected value' ); + t.strictEqual( v.done, false, 'returns expected value' ); + + v = it.return( 'beep' ); + t.strictEqual( v.value, 'beep', 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, void 0, 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + v = it.next(); + t.strictEqual( v.value, void 0, 'returns expected value' ); + t.strictEqual( v.done, true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if an environment supports `Symbol.iterator`, the method returns an iterable', function test( t ) { + var Complex64Array; + var arr; + var buf; + var it1; + var it2; + var v1; + var v2; + var i; + + Complex64Array = proxyquire( './../lib/main.js', { + '@stdlib/symbol/iterator': '__ITERATOR_SYMBOL__' + }); + + buf = [ 1.0, -1.0, 2.0, -2.0, 3.0, -3.0, 4.0, -4.0 ]; + arr = new Complex64Array( buf ); + + it1 = arr.keys(); + t.strictEqual( typeof it1[ '__ITERATOR_SYMBOL__' ], 'function', 'has method' ); + t.strictEqual( it1[ '__ITERATOR_SYMBOL__' ].length, 0, 'has zero arity' ); + + it2 = it1[ '__ITERATOR_SYMBOL__' ](); + t.strictEqual( typeof it2, 'object', 'returns an object' ); + t.strictEqual( typeof it2.next, 'function', 'has `next` method' ); + t.strictEqual( typeof it2.return, 'function', 'has `return` method' ); + + for ( i = 0; i < arr.length; i++ ) { + v1 = it1.next().value; + v2 = it2.next().value; + t.strictEqual( v1, v2, 'returns expected value' ); + } + t.end(); +}); + +tape( 'if an environment does not support `Symbol.iterator`, the method does not return an "iterable"', function test( t ) { + var Complex64Array; + var arr; + var buf; + var it; + + Complex64Array = proxyquire( './../lib/main.js', { + '@stdlib/symbol/iterator': false + }); + + buf = [ 1.0, -1.0, 2.0, -2.0, 3.0, -3.0, 4.0, -4.0 ]; + arr = new Complex64Array( buf ); + + it = arr.keys(); + t.strictEqual( it[ ITERATOR_SYMBOL ], void 0, 'does not have property' ); + + t.end(); +});