UNPKG

@stdlib/strided

Version:
238 lines (221 loc) 8.64 kB
/** * @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. */ /* eslint-disable max-len */ 'use strict'; // MODULES // var isFunction = require( '@stdlib/assert/is-function' ); var isTypedArrayLike = require( '@stdlib/assert/is-typed-array-like' ); var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive; var resolve = require( './../../../base/dtype-resolve-enum' ); var reinterpretComplex64 = require( './../../../base/reinterpret-complex64' ); var reinterpretComplex128 = require( './../../../base/reinterpret-complex128' ); var reinterpretBoolean = require( './../../../base/reinterpret-boolean' ); var offsetView = require( './../../../base/offset-view' ); var minViewBufferIndex = require( './../../../base/min-view-buffer-index' ); var format = require( '@stdlib/string/format' ); // VARIABLES // var COMPLEX64 = resolve( 'complex64' ); var COMPLEX128 = resolve( 'complex128' ); var BOOLEAN = resolve( 'bool' ); // MAIN // /** * Returns a function which dispatches to a native add-on applying a binary function to two input strided arrays using alternative indexing semantics. * * ## Notes * * - The returned function has the following signature: * * ```text * f( N, dtypeX, x, strideX, offsetX, dtypeY, y, strideY, offsetY, dtypeZ, z, strideZ, offsetZ ) * ``` * * where * * - **N**: number of indexed elements. * - **dtypeX**: `x` data type. * - **x**: input array. * - **strideX**: `x` stride length. * - **offsetX**: starting `x` index. * - **dtypeY**: `y` data type. * - **y**: input array. * - **strideY**: `y` stride length. * - **offsetY**: starting `y` index. * - **dtypeZ**: `z` data type. * - **z**: output array. * - **strideZ**: `z` stride length. * - **offsetZ**: starting `z` index. * * - The add-on function should have the following signature: * * ```text * f( N, dtypeX, x, strideX, dtypeY, y, strideY, dtypeZ, z, strideZ ) * ``` * * where * * - **N**: number of indexed elements. * - **dtypeX**: `x` data type (enumeration constant). * - **x**: input array. * - **strideX**: `x` stride length. * - **dtypeY**: `y` data type (enumeration constant). * - **y**: input array. * - **strideY**: `y` stride length. * - **dtypeZ**: `z` data type (enumeration constant). * - **z**: output array. * - **strideZ**: `z` stride length. * * - The fallback function should have the following signature: * * ```text * f( N, dtypeX, x, strideX, offsetX, dtypeY, y, strideY, offsetY, dtypeZ, z, strideZ, offsetZ ) * ``` * * where * * - **N**: number of indexed elements. * - **dtypeX**: `x` data type. * - **x**: input array. * - **strideX**: `x` stride length. * - **offsetX**: starting `x` index. * - **dtypeY**: `y` data type. * - **y**: input array. * - **strideY**: `y` stride length. * - **offsetY**: starting `y` index. * - **dtypeZ**: `z` data type. * - **z**: output array. * - **strideZ**: `z` stride length. * - **offsetZ**: starting `z` index. * * @param {Function} addon - add-on interface * @param {Function} fallback - fallback function * @throws {TypeError} first argument must be a function * @throws {TypeError} second argument must be a function * @returns {Function} dispatch function * * @example * function addon( N, dtypeX, x, strideX, dtypeY, y, strideY, dtypeZ, z, strideZ ) { * // Call into native add-on... * } * * function fallback( N, dtypeX, x, strideX, offsetX, dtypeY, y, strideY, offsetY, dtypeZ, z, strideZ, offsetZ ) { * // Fallback JavaScript implementation... * } * * // Create a dispatch function: * var f = dispatch( addon, fallback ); * * // ... * * // Invoke the dispatch function with strided array arguments: * f( 2, 'generic', [ 1, 2 ], 1, 0, 'generic', [ 3, 4 ], 1, 0, 'generic', [ 0, 0 ], 1, 0 ); */ function dispatch( addon, fallback ) { if ( !isFunction( addon ) ) { throw new TypeError( format( 'invalid argument. First argument must be a function. Value: `%s`.', addon ) ); } if ( !isFunction( fallback ) ) { throw new TypeError( format( 'invalid argument. Second argument must be a function. Value: `%s`.', fallback ) ); } return dispatcher; /** * Dispatches to a native add-on. * * @private * @param {integer} N - number of indexed elements * @param {*} dtypeX - `x` data type * @param {Collection} x - input array * @param {integer} strideX - `x` stride length * @param {NonNegativeInteger} offsetX - starting `x` index * @param {*} dtypeY - `y` data type * @param {Collection} y - input array * @param {integer} strideY - `y` stride length * @param {NonNegativeInteger} offsetY - starting `y` index * @param {*} dtypeZ - `z` data type * @param {Collection} z - destination array * @param {integer} strideZ - `z` stride length * @param {NonNegativeInteger} offsetZ - starting `z` index * @throws {TypeError} fifth argument must be a nonnegative integer * @throws {TypeError} ninth argument must be a nonnegative integer * @throws {TypeError} thirteenth argument must be a nonnegative integer * @throws {TypeError} unable to resolve a strided array function supporting the provided array argument data types * @returns {Collection} `z` */ function dispatcher( N, dtypeX, x, strideX, offsetX, dtypeY, y, strideY, offsetY, dtypeZ, z, strideZ, offsetZ ) { // eslint-disable-line max-params var viewX; var viewY; var viewZ; // WARNING: we assume that, if we're provided something resembling a typed array, we're provided a typed array; however, this can lead to potential unintended errors as the native add-on may not work with non-typed array objects (e.g., generic arrays)... if ( !isTypedArrayLike( x ) || !isTypedArrayLike( y ) || !isTypedArrayLike( z ) ) { fallback( N, dtypeX, x, strideX, offsetX, dtypeY, y, strideY, offsetY, dtypeZ, z, strideZ, offsetZ ); return z; } dtypeX = resolve( dtypeX ); dtypeY = resolve( dtypeY ); dtypeZ = resolve( dtypeZ ); if ( dtypeX === null || dtypeY === null || dtypeZ === null ) { throw new TypeError( 'invalid arguments. Unable to resolve a strided array function supporting the provided array argument data types.' ); } if ( !isNonNegativeInteger( offsetX ) ) { throw new TypeError( format( 'invalid argument. First input array offset must be a nonnegative integer. Value: `%s`.', offsetX ) ); } if ( !isNonNegativeInteger( offsetY ) ) { throw new TypeError( format( 'invalid argument. Second input array offset must be a nonnegative integer. Value: `%s`.', offsetY ) ); } if ( !isNonNegativeInteger( offsetZ ) ) { throw new TypeError( format( 'invalid argument. Output array offset must be a nonnegative integer. Value: `%s`.', offsetZ ) ); } offsetX = minViewBufferIndex( N, strideX, offsetX ); offsetY = minViewBufferIndex( N, strideY, offsetY ); offsetZ = minViewBufferIndex( N, strideZ, offsetZ ); if ( dtypeX === COMPLEX64 ) { viewX = reinterpretComplex64( x, offsetX ); } else if ( dtypeX === COMPLEX128 ) { viewX = reinterpretComplex128( x, offsetX ); } else if ( dtypeX === BOOLEAN ) { viewX = reinterpretBoolean( x, offsetX ); } else { viewX = offsetView( x, offsetX ); } if ( dtypeY === COMPLEX64 ) { viewY = reinterpretComplex64( y, offsetY ); } else if ( dtypeY === COMPLEX128 ) { viewY = reinterpretComplex128( y, offsetY ); } else if ( dtypeY === BOOLEAN ) { viewY = reinterpretBoolean( y, offsetY ); } else { viewY = offsetView( y, offsetY ); } if ( dtypeZ === COMPLEX64 ) { viewZ = reinterpretComplex64( z, offsetZ ); } else if ( dtypeZ === COMPLEX128 ) { viewZ = reinterpretComplex128( z, offsetZ ); } else if ( dtypeZ === BOOLEAN ) { viewZ = reinterpretBoolean( z, offsetZ ); } else { viewZ = offsetView( z, offsetZ ); } addon( N, dtypeX, viewX, strideX, dtypeY, viewY, strideY, dtypeZ, viewZ, strideZ ); return z; } } // EXPORTS // module.exports = dispatch;