/*
* @license Apache-2.0
*
* Copyright (c) 2021 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-lines, prefer-const */
///
import { ndarray } from '@stdlib/types/ndarray';
import ind2sub = require( './../../../ind2sub' );
import dispatch = require( './index' );
// FUNCTIONS //
/**
* Nullary callback.
*
* @returns input value
*/
function nullary(): any {
return 5.0;
}
/**
* Unary callback.
*
* @param x - input value
* @returns input value
*/
function unary( x: any ): any {
return x;
}
/**
* Binary callback.
*
* @param x - input value
* @param y - input value
* @returns output value
*/
function binary( x: number, y: number ): number {
return x + y;
}
/**
* Ternary callback.
*
* @param x - input value
* @param y - input value
* @param z - input value
* @returns output value
*/
function ternary( x: number, y: number, z: number ): number {
return x + y + z;
}
/**
* Quaternary callback.
*
* @param x - input value
* @param y - input value
* @param z - input value
* @param w - input value
* @returns output value
*/
function quaternary( x: number, y: number, z: number, w: number ): number {
return x + y + z + w;
}
/**
* Mock ndarray function.
*
* @param arrays - ndarrays
* @param fcn - callback
*/
function ndarrayFcn( arrays: Array, fcn: ( x: any ) => any ): void {
let xord;
let yord;
let opts;
let sub;
let sh;
let N;
let x;
let y;
let v;
let i;
x = arrays[ 0 ];
y = arrays[ 1 ];
sh = x.shape;
if ( sh.length === 0 ) {
return;
}
N = 1;
for ( i = 0; i < sh.length; i += 1 ) {
N *= sh[ i ];
}
xord = x.order;
yord = y.order;
opts = {
'order': xord
};
for ( i = 0; i < N; i += 1 ) {
// Convert a linear index to subscripts:
opts.order = xord;
sub = ind2sub( sh, i, opts );
// Retrieve an element from `x`:
v = x.get.apply( x, sub );
// Convert a linear index to subscripts:
opts.order = yord;
sub = ind2sub( sh, i, opts );
// Append the result of applying the callback:
sub[ sub.length ] = fcn( v ) as number;
// Assign the result to an element in `y`:
y.set.apply( y, sub );
}
}
/**
* Mock function to create an ndarray-like object.
*
* @returns ndarray-like object
*/
function array(): ndarray {
const obj: ndarray = {
'byteLength': 80,
'BYTES_PER_ELEMENT': 8,
'data': new Float64Array( 10 ),
'dtype': 'float64',
'flags': {
'ROW_MAJOR_CONTIGUOUS': true,
'COLUMN_MAJOR_CONTIGUOUS': false
},
'length': 10,
'ndims': 1,
'offset': 0,
'order': 'row-major',
'shape': [ 10 ],
'strides': [ 1 ],
'get': (): number => 0,
'set': (): ndarray => obj
};
return obj;
}
// TESTS //
// The function returns a dispatch function...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch( ndarrayFcn, types, data, 2, 1, 1 ); // $ExpectType Dispatcher
dispatch( [ ndarrayFcn ], types, data, 2, 1, 1 ); // $ExpectType Dispatcher
}
// The compiler throws an error if the function is provided a first argument which is not either an ndarray function or an array-like object containing ndarray functions...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch( '10', types, data, 2, 1, 1 ); // $ExpectError
dispatch( 10, types, data, 2, 1, 1 ); // $ExpectError
dispatch( true, types, data, 2, 1, 1 ); // $ExpectError
dispatch( false, types, data, 2, 1, 1 ); // $ExpectError
dispatch( null, types, data, 2, 1, 1 ); // $ExpectError
dispatch( undefined, types, data, 2, 1, 1 ); // $ExpectError
dispatch( [ '1' ], types, data, 2, 1, 1 ); // $ExpectError
dispatch( {}, types, data, 2, 1, 1 ); // $ExpectError
dispatch( ( x: number ): number => x, types, data, 2, 1, 1 ); // $ExpectError
}
// The compiler throws an error if the function is provided a second argument which is not an array-like object...
{
const data = [ unary ];
dispatch( ndarrayFcn, 10, data, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, true, data, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, false, data, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, null, data, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, undefined, data, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, {}, data, 2, 1, 1 ); // $ExpectError
}
// The compiler throws an error if the function is provided a third argument which is not an array-like object or null...
{
const types = [ 'float64', 'float64' ];
dispatch( ndarrayFcn, types, 10, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, true, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, false, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, undefined, 2, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, {}, 2, 1, 1 ); // $ExpectError
}
// The compiler throws an error if the function is provided a fourth argument which is not a number...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch( ndarrayFcn, types, data, '10', 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, true, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, false, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, null, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, undefined, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, [ '1' ], 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, {}, 1, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, ( x: number ): number => x, 1, 1 ); // $ExpectError
}
// The compiler throws an error if the function is provided a fifth argument which is not a number...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch( ndarrayFcn, types, data, 2, '10', 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, true, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, false, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, null, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, undefined, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, [ '1' ], 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, {}, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, ( x: number ): number => x, 1 ); // $ExpectError
}
// The compiler throws an error if the function is provided a sixth argument which is not a number...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch( ndarrayFcn, types, data, 2, 1, '10' ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, true ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, false ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, null ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, undefined ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, [ '1' ] ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, {} ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, ( x: number ): number => x ); // $ExpectError
}
// The compiler throws an error if the function is provided an unsupported number of arguments...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
dispatch(); // $ExpectError
dispatch( ndarrayFcn ); // $ExpectError
dispatch( ndarrayFcn, types ); // $ExpectError
dispatch( ndarrayFcn, types, data ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1 ); // $ExpectError
dispatch( ndarrayFcn, types, data, 2, 1, 1, 0 ); // $ExpectError
}
// The function returns a dispatch function...
{
const x = array();
const y = array();
const z = array();
const w = array();
const u = array();
const t1 = [ 'float64' ];
const d1 = [ nullary ];
const f1 = dispatch( ndarrayFcn, t1, d1, 1, 1, 0 );
f1( x ); // $ExpectType void | ndarray
const t2 = [ 'float64', 'float64' ];
const d2 = [ unary ];
const f2 = dispatch( ndarrayFcn, t2, d2, 2, 1, 1 );
f2( x, y ); // $ExpectType void | ndarray
const t3 = [ 'float64', 'float64', 'float64' ];
const d3 = [ binary ];
const f3 = dispatch( ndarrayFcn, t3, d3, 3, 2, 1 );
f3( x, y, z ); // $ExpectType void | ndarray
const t4 = [ 'float64', 'float64', 'float64', 'float64' ];
const d4 = [ ternary ];
const f4 = dispatch( ndarrayFcn, t4, d4, 4, 3, 1 );
f4( x, y, z, w ); // $ExpectType void | ndarray
const t5 = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const d5 = [ quaternary ];
const f5 = dispatch( ndarrayFcn, t5, d5, 5, 4, 1 );
f5( x, y, z, w, u ); // $ExpectType void | ndarray
}
// The compiler throws an error if the returned function is provided a first argument which is not an ndarray (1 ndarray)...
{
const types = [ 'float64' ];
const data = [ nullary ];
const f = dispatch( ndarrayFcn, types, data, 1, 0, 1 );
f( '10' ); // $ExpectError
f( 10 ); // $ExpectError
f( true ); // $ExpectError
f( false ); // $ExpectError
f( null ); // $ExpectError
f( undefined ); // $ExpectError
f( [ '1' ] ); // $ExpectError
f( {} ); // $ExpectError
f( ( x: number ): number => x ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a first argument which is not an ndarray (2 ndarrays)...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
const y = array();
const f = dispatch( ndarrayFcn, types, data, 2, 1, 1 );
f( 10, y ); // $ExpectError
f( '10', y ); // $ExpectError
f( true, y ); // $ExpectError
f( false, y ); // $ExpectError
f( null, y ); // $ExpectError
f( undefined, y ); // $ExpectError
f( [ '1' ], y ); // $ExpectError
f( {}, y ); // $ExpectError
f( ( x: number ): number => x, y ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a second argument which is not an ndarray (2 ndarrays)...
{
const types = [ 'float64', 'float64' ];
const data = [ unary ];
const x = array();
const f = dispatch( ndarrayFcn, types, data, 2, 1, 1 );
f( x, 10 ); // $ExpectError
f( x, '10' ); // $ExpectError
f( x, true ); // $ExpectError
f( x, false ); // $ExpectError
f( x, null ); // $ExpectError
f( x, undefined ); // $ExpectError
f( x, [ '1' ] ); // $ExpectError
f( x, {} ); // $ExpectError
f( x, ( x: number ): number => x ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a first argument which is not an ndarray (3 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64' ];
const data = [ binary ];
const y = array();
const z = array();
const f = dispatch( ndarrayFcn, types, data, 3, 2, 1 );
f( 10, y, z ); // $ExpectError
f( '10', y, z ); // $ExpectError
f( true, y, z ); // $ExpectError
f( false, y, z ); // $ExpectError
f( null, y, z ); // $ExpectError
f( undefined, y, z ); // $ExpectError
f( [ '1' ], y, z ); // $ExpectError
f( {}, y, z ); // $ExpectError
f( ( x: number ): number => x, y, z ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a second argument which is not an ndarray (3 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64' ];
const data = [ binary ];
const x = array();
const z = array();
const f = dispatch( ndarrayFcn, types, data, 3, 2, 1 );
f( x, 10, z ); // $ExpectError
f( x, '10', z ); // $ExpectError
f( x, true, z ); // $ExpectError
f( x, false, z ); // $ExpectError
f( x, null, z ); // $ExpectError
f( x, undefined, z ); // $ExpectError
f( x, [ '1' ], z ); // $ExpectError
f( x, {}, z ); // $ExpectError
f( x, ( x: number ): number => x, z ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a third argument which is not an ndarray (3 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64' ];
const data = [ binary ];
const x = array();
const y = array();
const f = dispatch( ndarrayFcn, types, data, 3, 2, 1 );
f( x, y, '10' ); // $ExpectError
f( x, y, true ); // $ExpectError
f( x, y, false ); // $ExpectError
f( x, y, null ); // $ExpectError
f( x, y, undefined ); // $ExpectError
f( x, y, [ '1' ] ); // $ExpectError
f( x, y, {} ); // $ExpectError
f( x, y, ( x: number ): number => x ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a first argument which is not an ndarray (4 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64' ];
const data = [ ternary ];
const y = array();
const z = array();
const w = array();
const f = dispatch( ndarrayFcn, types, data, 4, 3, 1 );
f( 10, y, z, w ); // $ExpectError
f( '10', y, z, w ); // $ExpectError
f( true, y, z, w ); // $ExpectError
f( false, y, z, w ); // $ExpectError
f( null, y, z, w ); // $ExpectError
f( undefined, y, z, w ); // $ExpectError
f( [ '1' ], y, z, w ); // $ExpectError
f( {}, y, z, w ); // $ExpectError
f( ( x: number ): number => x, y, z, w ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a second argument which is not an ndarray (4 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64' ];
const data = [ ternary ];
const x = array();
const z = array();
const w = array();
const f = dispatch( ndarrayFcn, types, data, 4, 3, 1 );
f( x, 10, z, w ); // $ExpectError
f( x, '10', z, w ); // $ExpectError
f( x, true, z, w ); // $ExpectError
f( x, false, z, w ); // $ExpectError
f( x, null, z, w ); // $ExpectError
f( x, undefined, z, w ); // $ExpectError
f( x, [ '1' ], z, w ); // $ExpectError
f( x, {}, z, w ); // $ExpectError
f( x, ( x: number ): number => x, z, w ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a third argument which is not an ndarray (4 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64' ];
const data = [ ternary ];
const x = array();
const y = array();
const w = array();
const f = dispatch( ndarrayFcn, types, data, 4, 3, 1 );
f( x, y, 10, w ); // $ExpectError
f( x, y, '10', w ); // $ExpectError
f( x, y, true, w ); // $ExpectError
f( x, y, false, w ); // $ExpectError
f( x, y, null, w ); // $ExpectError
f( x, y, undefined, w ); // $ExpectError
f( x, y, [ '1' ], w ); // $ExpectError
f( x, y, {}, w ); // $ExpectError
f( x, y, ( x: number ): number => x, w ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a fourth argument which is not an ndarray (4 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64' ];
const data = [ ternary ];
const x = array();
const y = array();
const z = array();
const f = dispatch( ndarrayFcn, types, data, 4, 3, 1 );
f( x, y, z, 10 ); // $ExpectError
f( x, y, z, '10' ); // $ExpectError
f( x, y, z, true ); // $ExpectError
f( x, y, z, false ); // $ExpectError
f( x, y, z, null ); // $ExpectError
f( x, y, z, undefined ); // $ExpectError
f( x, y, z, [ '1' ] ); // $ExpectError
f( x, y, z, {} ); // $ExpectError
f( x, y, z, ( x: number ): number => x ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a first argument which is not an ndarray (5 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const data = [ quaternary ];
const y = array();
const z = array();
const w = array();
const u = array();
const f = dispatch( ndarrayFcn, types, data, 5, 4, 1 );
f( 10, y, z, w, u ); // $ExpectError
f( '10', y, z, w, u ); // $ExpectError
f( true, y, z, w, u ); // $ExpectError
f( false, y, z, w, u ); // $ExpectError
f( null, y, z, w, u ); // $ExpectError
f( undefined, y, z, w, u ); // $ExpectError
f( [ '1' ], y, z, w, u ); // $ExpectError
f( {}, y, z, w, u ); // $ExpectError
f( ( x: number ): number => x, y, z, w, u ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a second argument which is not an ndarray (5 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const data = [ quaternary ];
const x = array();
const z = array();
const w = array();
const u = array();
const f = dispatch( ndarrayFcn, types, data, 5, 4, 1 );
f( x, 10, z, w, u ); // $ExpectError
f( x, '10', z, w, u ); // $ExpectError
f( x, true, z, w, u ); // $ExpectError
f( x, false, z, w, u ); // $ExpectError
f( x, null, z, w, u ); // $ExpectError
f( x, undefined, z, w, u ); // $ExpectError
f( x, [ '1' ], z, w, u ); // $ExpectError
f( x, {}, z, w, u ); // $ExpectError
f( x, ( x: number ): number => x, z, w, u ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a third argument which is not an ndarray (5 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const data = [ quaternary ];
const x = array();
const y = array();
const w = array();
const u = array();
const f = dispatch( ndarrayFcn, types, data, 5, 4, 1 );
f( x, y, 10, w, u ); // $ExpectError
f( x, y, '10', w, u ); // $ExpectError
f( x, y, true, w, u ); // $ExpectError
f( x, y, false, w, u ); // $ExpectError
f( x, y, null, w, u ); // $ExpectError
f( x, y, undefined, w, u ); // $ExpectError
f( x, y, [ '1' ], w, u ); // $ExpectError
f( x, y, {}, w, u ); // $ExpectError
f( x, y, ( x: number ): number => x, w, u ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a fourth argument which is not an ndarray (5 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const data = [ quaternary ];
const x = array();
const y = array();
const z = array();
const u = array();
const f = dispatch( ndarrayFcn, types, data, 5, 4, 1 );
f( x, y, z, 10, u ); // $ExpectError
f( x, y, z, '10', u ); // $ExpectError
f( x, y, z, true, u ); // $ExpectError
f( x, y, z, false, u ); // $ExpectError
f( x, y, z, null, u ); // $ExpectError
f( x, y, z, undefined, u ); // $ExpectError
f( x, y, z, [ '1' ], u ); // $ExpectError
f( x, y, z, {}, u ); // $ExpectError
f( x, y, z, ( x: number ): number => x, u ); // $ExpectError
}
// The compiler throws an error if the returned function is provided a fifth argument which is not an ndarray (5 ndarrays)...
{
const types = [ 'float64', 'float64', 'float64', 'float64', 'float64' ];
const data = [ quaternary ];
const x = array();
const y = array();
const z = array();
const w = array();
const f = dispatch( ndarrayFcn, types, data, 5, 4, 1 );
f( x, y, z, w, 10 ); // $ExpectError
f( x, y, z, w, '10' ); // $ExpectError
f( x, y, z, w, true ); // $ExpectError
f( x, y, z, w, false ); // $ExpectError
f( x, y, z, w, null ); // $ExpectError
f( x, y, z, w, undefined ); // $ExpectError
f( x, y, z, w, [ '1' ] ); // $ExpectError
f( x, y, z, w, {} ); // $ExpectError
f( x, y, z, w, ( x: number ): number => x ); // $ExpectError
}