|
| 1 | +/** |
| 2 | +* @license Apache-2.0 |
| 3 | +* |
| 4 | +* Copyright (c) 2025 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 | +#ifndef STDLIB_NDARRAY_BASE_UNARY_ACCUMULATE_MACROS_2D_H |
| 20 | +#define STDLIB_NDARRAY_BASE_UNARY_ACCUMULATE_MACROS_2D_H |
| 21 | + |
| 22 | +#include "stdlib/ndarray/ctor.h" |
| 23 | +#include "stdlib/ndarray/orders.h" |
| 24 | +#include <stdint.h> |
| 25 | + |
| 26 | +/** |
| 27 | +* Macro containing the preamble for nested loops which operate on elements of a two-dimensional ndarray. |
| 28 | +* |
| 29 | +* ## Notes |
| 30 | +* |
| 31 | +* - Variable naming conventions: |
| 32 | +* |
| 33 | +* - `sx#`, `px#`, and `d@x#` where `#` corresponds to the ndarray argument number, starting at `1`. |
| 34 | +* - `S@`, `i@`, and `d@x#` where `@` corresponds to the loop number, with `0` being the innermost loop. |
| 35 | +* |
| 36 | +* @param tout output type |
| 37 | +* |
| 38 | +* @example |
| 39 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREMABLE( double ) { |
| 40 | +* // Innermost loop body... |
| 41 | +* } |
| 42 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( double ) |
| 43 | +*/ |
| 44 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) \ |
| 45 | + struct ndarray *x1 = arrays[ 0 ]; \ |
| 46 | + struct ndarray *x2 = arrays[ 1 ]; \ |
| 47 | + struct ndarray *x3 = arrays[ 2 ]; \ |
| 48 | + int64_t *shape = stdlib_ndarray_shape( x1 ); \ |
| 49 | + int64_t *sx1 = stdlib_ndarray_strides( x1 ); \ |
| 50 | + uint8_t *px1 = stdlib_ndarray_data( x1 ); \ |
| 51 | + uint8_t *px2 = stdlib_ndarray_data( x2 ); \ |
| 52 | + uint8_t *px3 = stdlib_ndarray_data( x3 ); \ |
| 53 | + int64_t d0x1; \ |
| 54 | + int64_t d1x1; \ |
| 55 | + int64_t S0; \ |
| 56 | + int64_t S1; \ |
| 57 | + int64_t i0; \ |
| 58 | + int64_t i1; \ |
| 59 | + tout acc; \ |
| 60 | + /* Extract loop variables for purposes of loop interchange: dimensions and loop offset (pointer) increments... */ \ |
| 61 | + if ( stdlib_ndarray_order( x1 ) == STDLIB_NDARRAY_ROW_MAJOR ) { \ |
| 62 | + /* For row-major ndarrays, the last dimensions have the fastest changing indices... */ \ |
| 63 | + S0 = shape[ 1 ]; \ |
| 64 | + S1 = shape[ 0 ]; \ |
| 65 | + d0x1 = sx1[ 1 ]; \ |
| 66 | + d1x1 = sx1[ 0 ] - ( S0*sx1[1] ); \ |
| 67 | + } else { \ |
| 68 | + /* For column-major ndarrays, the first dimensions have the fastest changing indices... */ \ |
| 69 | + S0 = shape[ 0 ]; \ |
| 70 | + S1 = shape[ 1 ]; \ |
| 71 | + d0x1 = sx1[ 0 ]; \ |
| 72 | + d1x1 = sx1[ 1 ] - ( S0*sx1[0] ); \ |
| 73 | + } \ |
| 74 | + /* Set the pointers to the first indexed elements... */ \ |
| 75 | + px1 += stdlib_ndarray_offset( x1 ); \ |
| 76 | + px2 += stdlib_ndarray_offset( x2 ); \ |
| 77 | + px3 += stdlib_ndarray_offset( x3 ); \ |
| 78 | + /* Initialize the accumulator: */ \ |
| 79 | + acc = (tout *)px2; \ |
| 80 | + /* Iterate over the ndarray dimensions... */ \ |
| 81 | + for ( i1 = 0; i1 < S1; i1++, px1 += d1x1 ) { \ |
| 82 | + for ( i0 = 0; i0 < S0; i0++, px1 += d0x1 ) |
| 83 | + |
| 84 | +/** |
| 85 | +* Macro containing the epilogue for nested loops which operate on elements of a two-dimensional ndarray. |
| 86 | +* |
| 87 | +* @param tout output type |
| 88 | +* |
| 89 | +* @example |
| 90 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREMABLE( double ) { |
| 91 | +* // Innermost loop body... |
| 92 | +* } |
| 93 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( double ) |
| 94 | +*/ |
| 95 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) \ |
| 96 | + } \ |
| 97 | + *(tout *)px3 = acc; \ |
| 98 | + |
| 99 | +/** |
| 100 | +* Macro for a two-dimensional ndarray loop which inlines an expression. |
| 101 | +* |
| 102 | +* ## Notes |
| 103 | +* |
| 104 | +* - Retrieves each input ndarray element according to type `tin` via the pointer `px1` as `in1`. |
| 105 | +* - Expects a provided expression to operate on `tin in1` and update `acc`. |
| 106 | +* |
| 107 | +* @param tin input type |
| 108 | +* @param tout output type |
| 109 | +* @param expr expression to inline |
| 110 | +* |
| 111 | +* @example |
| 112 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_INLINE( double, double, acc += in1 ) |
| 113 | +*/ |
| 114 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_INLINE( tin, tout, expr ) \ |
| 115 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) { \ |
| 116 | + const tin in1 = *(tin *)px1; \ |
| 117 | + expr; \ |
| 118 | + } \ |
| 119 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) |
| 120 | + |
| 121 | +/** |
| 122 | +* Macro for a two-dimensional ndarray loop which invokes a callback. |
| 123 | +* |
| 124 | +* ## Notes |
| 125 | +* |
| 126 | +* - Retrieves each input ndarray element according to type `tin` via the pointer `px1`. |
| 127 | +* - Explicitly casts each function `f` invocation result to `tout`. |
| 128 | +* |
| 129 | +* @param tin input type |
| 130 | +* @param tout output type |
| 131 | +* |
| 132 | +* @example |
| 133 | +* // e.g., dd_d |
| 134 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK( double, double ) |
| 135 | +*/ |
| 136 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK( tin, tout ) \ |
| 137 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) { \ |
| 138 | + const tin x = *(tin *)px1; \ |
| 139 | + acc = (tout)f( acc, x ); \ |
| 140 | + } \ |
| 141 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) |
| 142 | + |
| 143 | +/** |
| 144 | +* Macro for a two-dimensional loop which invokes a callback and does not cast the return callback's return value (e.g., a `struct`). |
| 145 | +* |
| 146 | +* ## Notes |
| 147 | +* |
| 148 | +* - Retrieves each input ndarray element according to type `tin` via a pointer `px1`. |
| 149 | +* |
| 150 | +* @param tin input type |
| 151 | +* @param tout output type |
| 152 | +* |
| 153 | +* @example |
| 154 | +* #include "stdlib/complex/float64/ctor.h" |
| 155 | +* |
| 156 | +* // e.g., zz_z |
| 157 | +* STDLIB_NDARRAY_UNARY_2D_LOOP_CLBK_RET_NOCAST( stdlib_complex128_t, stdlib_complex128_t ) |
| 158 | +*/ |
| 159 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK_RET_NOCAST( tin, tout ) \ |
| 160 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) { \ |
| 161 | + const tin x = *(tin *)px1; \ |
| 162 | + acc = f( acc, x ); \ |
| 163 | + } \ |
| 164 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) |
| 165 | + |
| 166 | +/** |
| 167 | +* Macro for a two-dimensional ndarray loop which invokes a callback requiring arguments be explicitly cast to a different type. |
| 168 | +* |
| 169 | +* ## Notes |
| 170 | +* |
| 171 | +* - Retrieves each ndarray element according to type `tin` via the pointer `px1`. |
| 172 | +* - Explicitly casts each function accumulator argument to `fin1`. |
| 173 | +* - Explicitly casts each function element argument to `fin2`. |
| 174 | +* - Explicitly casts each function `f` invocation result to `tout`. |
| 175 | +* |
| 176 | +* @param tin input type |
| 177 | +* @param tout output type |
| 178 | +* @param fin1 callback accumulator argument type |
| 179 | +* @param fin2 callback element argument type |
| 180 | +* |
| 181 | +* @example |
| 182 | +* // e.g., ff_f_as_dd_d |
| 183 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK_ARG_CAST( float, float, double, double ) |
| 184 | +*/ |
| 185 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK_ARG_CAST( tin, tout, fin1, fin2 ) \ |
| 186 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) { \ |
| 187 | + const tin x = *(tin *)px1; \ |
| 188 | + acc = (tout)f( (fin1)acc, (fin2)x ); \ |
| 189 | + } \ |
| 190 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) |
| 191 | + |
| 192 | +/** |
| 193 | +* Macro for a two-dimensional ndarray loop which invokes a callback requiring arguments be cast to a different type via casting functions. |
| 194 | +* |
| 195 | +* ## Notes |
| 196 | +* |
| 197 | +* - Retrieves each ndarray element according to type `tin` via a pointer `px1`. |
| 198 | +* - Explicitly casts each function accumulator argument via `cin1`. |
| 199 | +* - Explicitly casts each function element argument via `cin2`. |
| 200 | +* - Explicitly casts each function `f` invocation result via `cout`. |
| 201 | +* |
| 202 | +* @param tin input type |
| 203 | +* @param tout output type |
| 204 | +* @param cin1 input casting function for the accumulator argument |
| 205 | +* @param cin2 input casting function for the element argument |
| 206 | +* @param cout output casting function |
| 207 | +* |
| 208 | +* @example |
| 209 | +* #include "stdlib/complex/float32/ctor.h" |
| 210 | +* #include "stdlib/complex/float64/ctor.h" |
| 211 | +* |
| 212 | +* // e.g., fc_c_as_zz_z |
| 213 | +* STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK_ARG_CAST_FCN( float, stdlib_complex64_t, stdlib_complex128_from_complex64, stdlib_complex128_from_float32, stdlib_complex128_to_complex64 ) |
| 214 | +*/ |
| 215 | +#define STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_CLBK_ARG_CAST_FCN( tin, tout, cin1, cin2, cout ) \ |
| 216 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_PREAMBLE( tout ) { \ |
| 217 | + const tin x = *(tin *)px1; \ |
| 218 | + acc = cout( f( cin1( acc ), cin2( x ) ) ); \ |
| 219 | + } \ |
| 220 | + STDLIB_NDARRAY_UNARY_ACCUMULATE_2D_LOOP_EPILOGUE( tout ) |
| 221 | + |
| 222 | +#endif // !STDLIB_NDARRAY_BASE_UNARY_ACCUMULATE_MACROS_2D_H |
0 commit comments