main.c (5264B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2021 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/ndarray/base/napi/addon_arguments.h" 20 #include "stdlib/ndarray/ctor.h" 21 #include <node_api.h> 22 #include <assert.h> 23 #include <stdbool.h> 24 #include <stdint.h> 25 #include <stdlib.h> 26 27 /** 28 * Validates, extracts, and transforms (to native C types) function arguments provided to an ndarray Node-API add-on interface. 29 * 30 * ## Notes 31 * 32 * - The function assumes the following argument order: 33 * 34 * ```text 35 * [ ib1, im1, ib2, im2, ..., ob1, om1, ob2, om2, ... ] 36 * ``` 37 * 38 * where 39 * 40 * - `ib#` is a data buffer for an input ndarray 41 * - `im#` is meta data for an input ndarray 42 * - `ob#` is a data buffer for an output ndarray 43 * - `om#` is meta data for an output ndarray 44 * 45 * - The function may return one of the following JavaScript errors: 46 * 47 * - `Error`: unable to allocate memory when processing input ndarray 48 * - `Error`: unable to allocate memory when processing output ndarray 49 * 50 * @param env environment under which the function is invoked 51 * @param argv ndarray function arguments 52 * @param nargs total number of expected arguments 53 * @param nin number of input ndarrays 54 * @param arrays destination array for storing pointers to both input and output ndarrays 55 * @param err pointer for storing a JavaScript error 56 * @return status code indicating success or failure (returns `napi_ok` if success) 57 * 58 * @example 59 * #include "stdlib/ndarray/base/napi/addon_arguments.h" 60 * #include "stdlib/ndarray/ctor.h" 61 * #include <node_api.h> 62 * #include <stdint.h> 63 * #include <assert.h> 64 * 65 * // Add-on function... 66 * napi_value addon( napi_env env, napi_callback_info info ) { 67 * napi_status status; 68 * 69 * // ... 70 * 71 * int64_t nargs = 6; 72 * int64_t nin = 2; 73 * 74 * // Get callback arguments: 75 * size_t argc = 6; 76 * napi_value argv[ 6 ]; 77 * status = napi_get_cb_info( env, info, &argc, argv, nullptr, nullptr ); 78 * assert( status == napi_ok ); 79 * 80 * // ... 81 * 82 * // Process the provided arguments: 83 * struct ndarray *arrays[ 3 ]; 84 * 85 * napi_value err; 86 * status = stdlib_ndarray_napi_addon_arguments( env, argv, nargs, nin, arrays, &err ); 87 * assert( status == napi_ok ); 88 * 89 * // ... 90 * 91 * } 92 */ 93 napi_status stdlib_ndarray_napi_addon_arguments( const napi_env env, const napi_value *argv, const int64_t nargs, const int64_t nin, struct ndarray *arrays[], napi_value *err ) { 94 napi_status status; 95 96 // Reset the output error: 97 *err = NULL; 98 99 // Compute the index of the first output array argument: 100 int64_t iout = nin * 2; 101 102 // For each ndarray, we expect 2 arguments: the data buffer and the array meta data... 103 for ( int64_t i = 0; i < nargs; i += 2 ) { 104 // Retrieve the ndarray data buffer: 105 uint8_t *data; 106 status = napi_get_typedarray_info( env, argv[ i ], NULL, NULL, (void *)&data, NULL, NULL ); 107 assert( status == napi_ok ); 108 109 // Retrieve the ndarray meta data: 110 uint8_t *meta; 111 size_t byteoffset; 112 status = napi_get_dataview_info( env, argv[ i+1 ], NULL, (void *)&meta, NULL, &byteoffset ); 113 assert( status == napi_ok ); 114 115 // Retrieve ndarray properties... 116 uint8_t *ptr = meta + byteoffset + 1; // +1 as the first byte is the endianness, which we ignore based on the assumption that the endianness is the same for both C and JavaScript 117 int16_t dtype = *(int16_t *)ptr; 118 119 ptr += 2; 120 int64_t ndims = *(int64_t *)ptr; 121 122 ptr += 8; 123 int64_t *shape = (int64_t *)ptr; 124 125 ptr += ndims * 8; 126 int64_t *strides = (int64_t *)ptr; 127 128 ptr += ndims * 8; 129 int64_t offset = *(int64_t *)ptr; 130 131 ptr += 8; 132 int8_t order = *(int8_t *)ptr; 133 134 ptr += 1; 135 int8_t imode = *(int8_t *)ptr; 136 137 ptr += 1; 138 int64_t nsubmodes = *(int64_t *)ptr; 139 140 ptr += 8; 141 int8_t *submodes = (int8_t *)ptr; 142 143 // Allocate a new ndarray: 144 struct ndarray *arr = stdlib_ndarray_allocate( dtype, data, ndims, shape, strides, offset, order, imode, nsubmodes, submodes ); 145 if ( arr == NULL ) { 146 napi_value msg; 147 if ( i < iout ) { 148 status = napi_create_string_utf8( env, "runtime exception. Unable to allocate memory when processing an input ndarray.", NAPI_AUTO_LENGTH, &msg ); 149 } else { 150 status = napi_create_string_utf8( env, "runtime exception. Unable to allocate memory when processing an output ndarray.", NAPI_AUTO_LENGTH, &msg ); 151 } 152 assert( status == napi_ok ); 153 154 napi_value code; 155 status = napi_create_string_utf8( env, "ERR_MEMORY_ALLOCATION_FAILED", NAPI_AUTO_LENGTH, &code ); 156 assert( status == napi_ok ); 157 158 napi_value error; 159 status = napi_create_error( env, code, msg, &error ); 160 assert( status == napi_ok ); 161 162 *err = error; 163 return napi_ok; 164 } 165 // Set the output data: 166 arrays[ i/2 ] = arr; 167 } 168 return napi_ok; 169 }