From a0ba090515dfdfe617e1179ddb7581db24fec44b Mon Sep 17 00:00:00 2001
From: Aayush Khanna <96649223+aayush0325@users.noreply.github.com>
Date: Mon, 2 Dec 2024 08:02:50 +0530
Subject: [PATCH] feat: add `with` method to `array/fixed-endian-factory`

PR-URL: https://github.com/stdlib-js/stdlib/pull/3291
Closes: https://github.com/stdlib-js/stdlib/issues/3162

Co-authored-by: Philipp Burckhardt <pburckhardt@outlook.com>
Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com>
Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
---
 .../array/fixed-endian-factory/README.md      |  19 ++
 .../benchmark/benchmark.with.js               |  61 +++++
 .../benchmark/benchmark.with.length.js        | 106 +++++++++
 .../array/fixed-endian-factory/lib/main.js    |  47 +++-
 .../fixed-endian-factory/test/test.with.js    | 220 ++++++++++++++++++
 5 files changed, 450 insertions(+), 3 deletions(-)
 create mode 100644 lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.js
 create mode 100644 lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.length.js
 create mode 100644 lib/node_modules/@stdlib/array/fixed-endian-factory/test/test.with.js

diff --git a/lib/node_modules/@stdlib/array/fixed-endian-factory/README.md b/lib/node_modules/@stdlib/array/fixed-endian-factory/README.md
index c1824d76f4f2..7ceb1b56cf40 100644
--- a/lib/node_modules/@stdlib/array/fixed-endian-factory/README.md
+++ b/lib/node_modules/@stdlib/array/fixed-endian-factory/README.md
@@ -908,6 +908,25 @@ var str = arr.join( 0 );
 // returns '10203'
 ```
 
+<a name="method-with"></a>
+
+#### TypedArrayFE.prototype.with( index, value )
+
+Returns a new typed array with the element at a provided index replaced with a provided value.
+
+```javascript
+var Float64ArrayFE = fixedEndianFactory( 'float64' );
+
+var arr = new Float64ArrayFE( 'little-endian', [ 1.0, 2.0, 3.0 ] );
+// returns <Float64ArrayFE>
+
+var out = arr.with( 0, 0.0 );
+// returns <Float64ArrayFE>
+
+var v = out.get( 0 );
+// returns 0.0
+```
+  
 </section>
 
 <!-- /.usage -->
diff --git a/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.js b/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.js
new file mode 100644
index 000000000000..cc7eb40df681
--- /dev/null
+++ b/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.js
@@ -0,0 +1,61 @@
+/**
+* @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 pkg = require( './../package.json' ).name;
+var factory = require( './../lib' );
+
+
+// VARIABLES //
+
+var Float64ArrayFE = factory( 'float64' );
+
+
+// MAIN //
+
+bench( pkg+':with', function benchmark( b ) {
+	var values;
+	var out;
+	var arr;
+	var i;
+
+	values = [
+		1.0,
+		2.0,
+		3.0
+	];
+	arr = new Float64ArrayFE( 'little-endian', [ 1.0, 2.0, 2.0, 1.0 ] );
+
+	b.tic();
+	for ( i = 0; i < b.iterations; i++ ) {
+		out = arr.with( i % arr.length, values[ i % values.length ] );
+		if ( typeof out !== 'object' ) {
+			b.fail( 'should return an object' );
+		}
+	}
+	b.toc();
+	if ( !( out instanceof Float64ArrayFE ) ) {
+		b.fail( 'should return a typed array' );
+	}
+	b.pass( 'benchmark finished' );
+	b.end();
+});
diff --git a/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.length.js b/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.length.js
new file mode 100644
index 000000000000..75c472455519
--- /dev/null
+++ b/lib/node_modules/@stdlib/array/fixed-endian-factory/benchmark/benchmark.with.length.js
@@ -0,0 +1,106 @@
+/**
+* @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 zeroTo = require( '@stdlib/array/zero-to' );
+var pkg = require( './../package.json' ).name;
+var factory = require( './../lib' );
+
+
+// VARIABLES //
+
+var Float64ArrayFE = factory( 'float64' );
+
+
+// FUNCTIONS //
+
+/**
+* Creates a benchmark function.
+*
+* @private
+* @param {PositiveInteger} len - array length
+* @returns {Function} benchmark function
+*/
+function createBenchmark( len ) {
+	var arr = new Float64ArrayFE( 'little-endian', zeroTo( len ) );
+	return benchmark;
+
+	/**
+	* Benchmark function.
+	*
+	* @private
+	* @param {Benchmark} b - benchmark instance
+	*/
+	function benchmark( b ) {
+		var values;
+		var out;
+		var i;
+
+		values = [
+			1.0,
+			2.0,
+			3.0
+		];
+
+		b.tic();
+		for ( i = 0; i < b.iterations; i++ ) {
+			out = arr.with( i % arr.length, values[ i % values.length ] );
+			if ( typeof out !== 'object' ) {
+				b.fail( 'should return an object' );
+			}
+		}
+		b.toc();
+		if ( !( out instanceof Float64ArrayFE ) ) {
+			b.fail( 'should return a typed array' );
+		}
+		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+':with:len='+len, f );
+	}
+}
+
+main();
diff --git a/lib/node_modules/@stdlib/array/fixed-endian-factory/lib/main.js b/lib/node_modules/@stdlib/array/fixed-endian-factory/lib/main.js
index a8dbe8ea235b..9938162ff704 100644
--- a/lib/node_modules/@stdlib/array/fixed-endian-factory/lib/main.js
+++ b/lib/node_modules/@stdlib/array/fixed-endian-factory/lib/main.js
@@ -24,6 +24,7 @@
 
 var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
 var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
+var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
 var isCollection = require( '@stdlib/assert/is-collection' );
 var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
 var isObject = require( '@stdlib/assert/is-object' );
@@ -1059,22 +1060,62 @@ function factory( dtype ) { // eslint-disable-line max-lines-per-function, stdli
 		if ( !isTypedArray( this ) ) {
 			throw new TypeError( format( 'invalid invocation. `this` is not %s %s.', CHAR2ARTICLE[ dtype[0] ], CTOR_NAME ) );
 		}
-
 		if ( arguments.length > 0 ) {
 			sep = String( separator );
 		} else {
 			sep = ',';
 		}
-
 		out = [];
 		buf = this._buffer;
 		for ( i = 0; i < this._length; i++ ) {
 			out.push( buf[ GETTER ]( i * BYTES_PER_ELEMENT, this._isLE ) );
 		}
-
 		return out.join( sep );
 	});
 
+	/**
+	* Returns a new typed array with the element at a provided index replaced with a provided value.
+	*
+	* @name with
+	* @memberof TypedArray.prototype
+	* @type {Function}
+	* @param {integer} index - element index
+	* @param {number} value - new value
+	* @throws {TypeError} `this` must be a typed array instance
+	* @throws {TypeError} first argument must be an integer
+	* @throws {RangeError} index argument is out-of-bounds
+	* @throws {TypeError} second argument must be a number
+	* @returns {TypedArray} new typed array
+	*/
+	setReadOnly( TypedArray.prototype, 'with', function copyWith( index, value ) {
+		var outbuf;
+		var buf;
+		var out;
+		var len;
+
+		if ( !isTypedArray( this ) ) {
+			throw new TypeError( format( 'invalid invocation. `this` is not %s %s.', CHAR2ARTICLE[ dtype[0] ], CTOR_NAME ) );
+		}
+		if ( !isInteger( index ) ) {
+			throw new TypeError( format( 'invalid argument. First argument must be an integer. Value: `%s`.', index ) );
+		}
+		len = this._length;
+		buf = this._buffer;
+		if ( index < 0 ) {
+			index += len;
+		}
+		if ( index < 0 || index >= len ) {
+			throw new RangeError( format( 'invalid argument. Index argument is out-of-bounds. Value: `%s`.', index ) );
+		}
+		if ( !isNumber( value ) ) {
+			throw new TypeError( format( 'invalid argument. Second argument must be a number. Value: `%s`.', value ) );
+		}
+		out = new this.constructor( flag2byteOrder( this._isLE ), buf.buffer );
+		outbuf = out._buffer;  // eslint-disable-line no-underscore-dangle
+		outbuf[ SETTER ]( index * BYTES_PER_ELEMENT, value, this._isLE );
+		return out;
+	});
+
 	return TypedArray;
 
 	/**
diff --git a/lib/node_modules/@stdlib/array/fixed-endian-factory/test/test.with.js b/lib/node_modules/@stdlib/array/fixed-endian-factory/test/test.with.js
new file mode 100644
index 000000000000..93a36b03d62e
--- /dev/null
+++ b/lib/node_modules/@stdlib/array/fixed-endian-factory/test/test.with.js
@@ -0,0 +1,220 @@
+/**
+* @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 hasOwnProp = require( '@stdlib/assert/has-own-property' );
+var isFunction = require( '@stdlib/assert/is-function' );
+var factory = require( './../lib' );
+
+
+// TESTS //
+
+tape( 'main export is a function', function test( t ) {
+	t.ok( true, __filename );
+	t.strictEqual( typeof factory, 'function', 'main export is a function' );
+	t.end();
+});
+
+tape( 'the function returns a function', function test( t ) {
+	var ctor = factory( 'float64' );
+	t.strictEqual( isFunction( ctor ), true, 'returns expected value' );
+	t.end();
+});
+
+tape( 'attached to the prototype of the returned function is a `with` method', function test( t ) {
+	var ctor = factory( 'float64' );
+	t.strictEqual( hasOwnProp( ctor.prototype, 'with' ), true, 'returns expected value' );
+	t.strictEqual( isFunction( ctor.prototype.with ), true, 'returns expected value' );
+	t.end();
+});
+
+tape( 'the method throws an error if invoked with a `this` context which is not a typed array instance', function test( t ) {
+	var values;
+	var ctor;
+	var arr;
+	var i;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+
+	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.with.call( value, 0, 0.0 );
+		};
+	}
+});
+
+tape( 'the method throws an error if provided a first argument which is not an integer', function test( t ) {
+	var values;
+	var ctor;
+	var arr;
+	var i;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+
+	values = [
+		'5',
+		3.14,
+		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.with( value, 0.0 );
+		};
+	}
+});
+
+tape( 'the method throws an error if provided a first argument which is not in bounds', function test( t ) {
+	var values;
+	var ctor;
+	var arr;
+	var i;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+
+	values = [
+		-6,
+		-9,
+		10,
+		20
+	];
+
+	for ( i = 0; i < values.length; i++ ) {
+		t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] );
+	}
+	t.end();
+
+	function badValue( value ) {
+		return function badValue() {
+			return arr.with( value, 0.0 );
+		};
+	}
+});
+
+tape( 'the method throws an error if provided a second argument which is not a number', function test( t ) {
+	var values;
+	var ctor;
+	var arr;
+	var i;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+
+	values = [
+		'5',
+		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.with( 0, value );
+		};
+	}
+});
+
+tape( 'the method does not change the array length', function test( t ) {
+	var ctor;
+	var arr;
+	var out;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+	out = arr.with( 0, 4.0 );
+
+	t.strictEqual( out.length, 5, 'returns expected value' );
+	t.end();
+});
+
+tape( 'the method returns a new boolean array with the element at a provided index replaced with a provided value', function test( t ) {
+	var expected;
+	var actual;
+	var ctor;
+	var arr;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+	expected = new ctor( 'little-endian', [ 0.0, 2.0, 3.0, 4.0, 5.0 ] );
+	actual = arr.with( 0, 0.0 );
+	t.strictEqual( actual instanceof ctor, true, 'returns expected value' );
+	t.deepEqual( actual, expected, 'returns expected value' );
+	t.notEqual( actual, arr, 'returns new instance' );
+	t.end();
+});
+
+tape( 'the method supports negative indices', function test( t ) {
+	var expected;
+	var actual;
+	var ctor;
+	var arr;
+
+	ctor = factory( 'float64' );
+	arr = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );
+	expected = new ctor( 'little-endian', [ 1.0, 2.0, 3.0, 4.0, 0.0 ] );
+	actual = arr.with( -5, 0.0 );
+	t.strictEqual( actual instanceof ctor, true, 'returns expected value' );
+	t.deepEqual( actual, expected, 'returns expected value' );
+	t.notEqual( actual, arr, 'returns new instance' );
+	t.end();
+});