time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

main.c (10058B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2020 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 #include "stdlib/strided/napi/addon_arguments.h"
     20 #include "stdlib/ndarray/base/napi/typedarray_type_to_dtype.h"
     21 #include "stdlib/ndarray/base/bytes_per_element.h"
     22 #include "stdlib/math/base/assert/is_finite.h"
     23 #include "stdlib/math/base/special/floor.h"
     24 #include <node_api.h>
     25 #include <assert.h>
     26 #include <stdbool.h>
     27 #include <stdint.h>
     28 #include <stdlib.h>
     29 
     30 /**
     31 * Validates, extracts, and transforms (to native C types) function arguments provided to a strided array N-API add-on interface.
     32 *
     33 * ## Notes
     34 *
     35 * -   The function assumes the following argument order:
     36 *
     37 *     ```text
     38 *     [ N, ia1, is1, ia2, is2, ..., oa1, os1, oa2, os2, ... ]
     39 *     ```
     40 *
     41 *     where
     42 *
     43 *     -   `N` is the number of elements over which to iterate
     44 *     -   `ia#` is an input strided array
     45 *     -   `is#` is a corresponding input strided array stride (in units of elements)
     46 *     -   `oa#` is an output strided array
     47 *     -   `os#` is a corresponding output strided array stride (in units of elements)
     48 *
     49 * -   The function may return one of the following JavaScript errors:
     50 *
     51 *     -   `TypeError`: first argument must be an integer
     52 *     -   `TypeError`: input array stride argument must be an integer
     53 *     -   `TypeError`: output array stride argument must be an integer
     54 *     -   `TypeError`: input array argument must be a typed array
     55 *     -   `TypeError`: output array argument must be a typed array
     56 *     -   `RangeError`: input array argument must have sufficient elements based on the associated stride and the number of indexed elements
     57 *     -   `RangeError`: output array argument must have sufficient elements based on the associated stride and the number of indexed elements
     58 *
     59 * @param env      environment under which the function is invoked
     60 * @param argv     strided function arguments
     61 * @param nargs    total number of expected arguments
     62 * @param nin      number of input strided array arguments
     63 * @param arrays   destination array for storing pointers to both input and output strided byte arrays
     64 * @param shape    destination array for storing the array shape (dimensions)
     65 * @param strides  destination array for storing array strides (in bytes) for each strided array
     66 * @param types    destination array for storing strided array argument data types
     67 * @param err      pointer for storing a JavaScript error
     68 * @return         status code indicating success or failure (returns `napi_ok` if success)
     69 *
     70 * @example
     71 * #include "stdlib/strided/napi/addon_arguments.h"
     72 * #include <node_api.h>
     73 * #include <stdint.h>
     74 * #include <assert.h>
     75 *
     76 * // Add-on function...
     77 * napi_value addon( napi_env env, napi_callback_info info ) {
     78 *     napi_status status;
     79 *
     80 *     // ...
     81 *
     82 *     int64_t nargs = 7;
     83 *     int64_t nin = 2;
     84 *
     85 *     // Get callback arguments:
     86 *     size_t argc = 7;
     87 *     napi_value argv[ 7 ];
     88 *     status = napi_get_cb_info( env, info, &argc, argv, nullptr, nullptr );
     89 *     assert( status == napi_ok );
     90 *
     91 *     // ...
     92 *
     93 *     // Process the provided arguments:
     94 *     uint8_t *arrays[ 3 ];
     95 *     int64_t strides[ 3 ];
     96 *     int64_t shape[ 1 ];
     97 *     int32_t types[ 3 ];
     98 *
     99 *     napi_value err;
    100 *     status = stdlib_strided_napi_addon_arguments( env, argv, nargs, nin, arrays, shape, strides, types, &err );
    101 *     assert( status == napi_ok );
    102 *
    103 *     // ...
    104 *
    105 * }
    106 */
    107 napi_status stdlib_strided_napi_addon_arguments( const napi_env env, const napi_value *argv, const int64_t nargs, const int64_t nin, uint8_t *arrays[], int64_t *shape, int64_t *strides, int32_t *types, napi_value *err ) {
    108 	napi_status status;
    109 	int64_t i;
    110 	int64_t j;
    111 
    112 	// Reset the output error:
    113 	*err = NULL;
    114 
    115 	// Compute the index of the first output strided array argument:
    116 	int64_t iout = ( nin*2 ) + 1;
    117 
    118 	// The first argument is always the number of elements over which to iterate...
    119 	napi_valuetype vtype0;
    120 	status = napi_typeof( env, argv[ 0 ], &vtype0 );
    121 	assert( status == napi_ok );
    122 	if ( vtype0 != napi_number ) {
    123 		napi_value msg;
    124 		status = napi_create_string_utf8( env, "invalid argument. First argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    125 		assert( status == napi_ok );
    126 
    127 		napi_value code;
    128 		status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    129 		assert( status == napi_ok );
    130 
    131 		napi_value error;
    132 		status = napi_create_type_error( env, code, msg, &error );
    133 		assert( status == napi_ok );
    134 
    135 		*err = error;
    136 		return napi_ok;
    137 	}
    138 	// Retrieve the number of indexed elements...
    139 	double N;
    140 	status = napi_get_value_double( env, argv[ 0 ], &N );
    141 	assert( status == napi_ok );
    142 	if ( !stdlib_base_is_finite( N ) || stdlib_base_floor( N ) != N ) {
    143 		napi_value msg;
    144 		status = napi_create_string_utf8( env, "invalid argument. First argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    145 		assert( status == napi_ok );
    146 
    147 		napi_value code;
    148 		status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    149 		assert( status == napi_ok );
    150 
    151 		napi_value error;
    152 		status = napi_create_type_error( env, code, msg, &error );
    153 		assert( status == napi_ok );
    154 
    155 		*err = error;
    156 		return napi_ok;
    157 	}
    158 	shape[ 0 ] = (int64_t)N;
    159 
    160 	// Strides for both input and output strided arrays are every other argument beginning from the third argument...
    161 	for ( i = 2; i < nargs; i += 2 ) {
    162 		// Check that we were provided a number...
    163 		napi_valuetype vtype;
    164 		status = napi_typeof( env, argv[ i ], &vtype );
    165 		assert( status == napi_ok );
    166 		if ( vtype != napi_number ) {
    167 			napi_value msg;
    168 			if ( i < iout ) {
    169 				status = napi_create_string_utf8( env, "invalid argument. Input array stride argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    170 			} else {
    171 				status = napi_create_string_utf8( env, "invalid argument. Output array stride argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    172 			}
    173 			assert( status == napi_ok );
    174 
    175 			napi_value code;
    176 			status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    177 			assert( status == napi_ok );
    178 
    179 			napi_value error;
    180 			status = napi_create_type_error( env, code, msg, &error );
    181 			assert( status == napi_ok );
    182 
    183 			*err = error;
    184 			return napi_ok;
    185 		}
    186 		// Get the stride...
    187 		double stride;
    188 		status = napi_get_value_double( env, argv[ i ], &stride );
    189 		assert( status == napi_ok );
    190 		if ( !stdlib_base_is_finite( stride ) || stdlib_base_floor( stride ) != stride ) {
    191 			napi_value msg;
    192 			if ( i < iout ) {
    193 				status = napi_create_string_utf8( env, "invalid argument. Input array stride argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    194 			} else {
    195 				status = napi_create_string_utf8( env, "invalid argument. Output array stride argument must be an integer.", NAPI_AUTO_LENGTH, &msg );
    196 			}
    197 			assert( status == napi_ok );
    198 
    199 			napi_value code;
    200 			status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    201 			assert( status == napi_ok );
    202 
    203 			napi_value error;
    204 			status = napi_create_type_error( env, code, msg, &error );
    205 			assert( status == napi_ok );
    206 
    207 			*err = error;
    208 			return napi_ok;
    209 		}
    210 		// Set output data...
    211 		j = ( i-2 ) / 2;
    212 		strides[ j ] = (int64_t)stride;
    213 	}
    214 	// Input and output strided arrays are every other argument beginning from the second argument...
    215 	for ( i = 1; i < nargs; i += 2 ) {
    216 		// Check that we were provided a typed array...
    217 		bool res;
    218 		status = napi_is_typedarray( env, argv[ i ], &res );
    219 		assert( status == napi_ok );
    220 		if ( res == false ) {
    221 			napi_value msg;
    222 			if ( i < iout ) {
    223 				status = napi_create_string_utf8( env, "invalid argument. Input array argument must be a typed array.", NAPI_AUTO_LENGTH, &msg );
    224 			} else {
    225 				status = napi_create_string_utf8( env, "invalid argument. Output array argument must be a typed array.", NAPI_AUTO_LENGTH, &msg );
    226 			}
    227 			assert( status == napi_ok );
    228 
    229 			napi_value code;
    230 			status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    231 			assert( status == napi_ok );
    232 
    233 			napi_value error;
    234 			status = napi_create_type_error( env, code, msg, &error );
    235 			assert( status == napi_ok );
    236 
    237 			*err = error;
    238 			return napi_ok;
    239 		}
    240 		// Get the typed array data...
    241 		napi_typedarray_type vtype;
    242 		size_t len;
    243 		void *TypedArray;
    244 		status = napi_get_typedarray_info( env, argv[ i ], &vtype, &len, &TypedArray, NULL, NULL );
    245 		assert( status == napi_ok );
    246 
    247 		// Check that the provided array has sufficient elements...
    248 		j = ( i-1 ) / 2;
    249 		if ( (shape[0]-1)*llabs(strides[j]) >= (int64_t)len ) {
    250 			napi_value msg;
    251 			if ( i < iout ) {
    252 				status = napi_create_string_utf8( env, "invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.", NAPI_AUTO_LENGTH, &msg );
    253 			} else {
    254 				status = napi_create_string_utf8( env, "invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.", NAPI_AUTO_LENGTH, &msg );
    255 			}
    256 			assert( status == napi_ok );
    257 
    258 			napi_value code;
    259 			status = napi_create_string_utf8( env, "ERR_STRIDED_INVALID_ARGUMENT", NAPI_AUTO_LENGTH, &code );
    260 			assert( status == napi_ok );
    261 
    262 			napi_value error;
    263 			status = napi_create_range_error( env, code, msg, &error );
    264 			assert( status == napi_ok );
    265 
    266 			*err = error;
    267 			return napi_ok;
    268 		}
    269 		// Set output data...
    270 		arrays[ j ] = (uint8_t *)TypedArray;
    271 		types[ j ] = stdlib_ndarray_napi_typedarray_type_to_dtype( vtype );
    272 		strides[ j ] *= stdlib_ndarray_bytes_per_element( types[ j ] );
    273 	}
    274 	return napi_ok;
    275 }