OMCompiler/SimulationRuntime/c/util/base_array.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file belongs to the OpenModelica Run-Time System | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), c/o Linköpings | ||
| 5 | * universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden. All rights | ||
| 6 | * reserved. | ||
| 7 | * | ||
| 8 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE | ||
| 9 | * AGPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. ANY | ||
| 10 | * USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S | ||
| 11 | * ACCEPTANCE OF THE BSD NEW LICENSE OR THE OSMC PUBLIC LICENSE OR THE AGPL | ||
| 12 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 13 | * | ||
| 14 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) Public License | ||
| 15 | * (OSMC-PL) are obtained from OSMC, either from the above address, from the URLs: | ||
| 16 | * http://www.openmodelica.org or https://github.com/OpenModelica/ or | ||
| 17 | * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica distribution. GNU | ||
| 18 | * AGPL version 3 is obtained from: https://www.gnu.org/licenses/licenses.html#GPL. The BSD NEW | ||
| 19 | * License is obtained from: http://www.opensource.org/licenses/BSD-3-Clause. | ||
| 20 | * | ||
| 21 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY | ||
| 23 | * SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF | ||
| 24 | * OSMC-PL. | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | |||
| 29 | #include "base_array.h" | ||
| 30 | #if defined(OMC_METAMODELICA_RUNTIME) | ||
| 31 | /* The string vocabulary of this runtime; util/omc_string.h stands down here. */ | ||
| 32 | #include "../meta/meta_modelica_string.h" | ||
| 33 | #endif | ||
| 34 | #include "index_spec.h" | ||
| 35 | #include "../gc/omc_gc.h" | ||
| 36 | #include "omc_string.h" | ||
| 37 | #include "omc_error.h" | ||
| 38 | |||
| 39 | #include <stdlib.h> | ||
| 40 | #include <stdio.h> | ||
| 41 | #include <assert.h> | ||
| 42 | #include <stdarg.h> | ||
| 43 | |||
| 44 | |||
| 45 | /** | ||
| 46 | * @brief Calculate flat index for 2D array element access. | ||
| 47 | * | ||
| 48 | * Converts 2D subscripts (i, j) to a flat 1D index using row-major order. | ||
| 49 | * | ||
| 50 | * @param dim Pointer to dimension sizes array (at least 2 elements). | ||
| 51 | * @param i Row index (0-based). | ||
| 52 | * @param j Column index (0-based). | ||
| 53 | * | ||
| 54 | * @return Flat 1D index for row-major storage. | ||
| 55 | * | ||
| 56 | * @note Uses row-major (C-style) array layout: index = i * dim[1] + j | ||
| 57 | */ | ||
| 58 | 75247 | _index_t getIndex_2D(_index_t * dim, int i, int j) { | |
| 59 | 75247 | return i * dim[1] + j; | |
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * @brief Calculate flat index for 3D array element access. | ||
| 64 | * | ||
| 65 | * Converts 3D subscripts (i, j, k) to a flat 1D index using row-major order. | ||
| 66 | * | ||
| 67 | * @param dim Pointer to dimension sizes array (at least 3 elements). | ||
| 68 | * @param i First dimension index (0-based). | ||
| 69 | * @param j Second dimension index (0-based). | ||
| 70 | * @param k Third dimension index (0-based). | ||
| 71 | * | ||
| 72 | * @return Flat 1D index for row-major storage. | ||
| 73 | * | ||
| 74 | * @note Uses row-major array layout: index = (i * dim[1] + j) * dim[2] + k | ||
| 75 | */ | ||
| 76 | 1061 | _index_t getIndex_3D(_index_t * dim, int i, int j, int k) { | |
| 77 | 1061 | return (i * dim[1] + j) * dim[2] + k; | |
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * @brief Calculate flat index for 4D array element access. | ||
| 82 | * | ||
| 83 | * Converts 4D subscripts (i, j, k, l) to a flat 1D index using row-major order. | ||
| 84 | * | ||
| 85 | * @param dim Pointer to dimension sizes array (at least 4 elements). | ||
| 86 | * @param i First dimension index (0-based). | ||
| 87 | * @param j Second dimension index (0-based). | ||
| 88 | * @param k Third dimension index (0-based). | ||
| 89 | * @param l Fourth dimension index (0-based). | ||
| 90 | * | ||
| 91 | * @return Flat 1D index for row-major storage. | ||
| 92 | */ | ||
| 93 | ✗ | _index_t getIndex_4D(_index_t * dim, int i, int j, int k, int l) { | |
| 94 | ✗ | return ((i * dim[1] + j) * dim[2] + k) * dim[3] + l; | |
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * @brief Calculate flat index for 5D array element access. | ||
| 99 | * | ||
| 100 | * Converts 5D subscripts (i, j, k, l, m) to a flat 1D index using row-major | ||
| 101 | * order. | ||
| 102 | * | ||
| 103 | * @param dim Pointer to dimension sizes array (at least 5 elements). | ||
| 104 | * @param i First dimension index (0-based). | ||
| 105 | * @param j Second dimension index (0-based). | ||
| 106 | * @param k Third dimension index (0-based). | ||
| 107 | * @param l Fourth dimension index (0-based). | ||
| 108 | * @param m Fifth dimension index (0-based). | ||
| 109 | * | ||
| 110 | * @return Flat 1D index for row-major storage. | ||
| 111 | */ | ||
| 112 | ✗ | _index_t getIndex_5D(_index_t * dim, int i, int j, int k, int l, int m) { | |
| 113 | ✗ | return (((i * dim[1] + j) * dim[2] + k) * dim[3] + l) * dim[4] + m; | |
| 114 | } | ||
| 115 | |||
| 116 | /** | ||
| 117 | * @brief Calculate total number of elements in an array. | ||
| 118 | * | ||
| 119 | * Computes the product of all dimension sizes to get the total element count. | ||
| 120 | * | ||
| 121 | * @param a The base array structure. | ||
| 122 | * | ||
| 123 | * @return Total number of elements in the array. | ||
| 124 | */ | ||
| 125 | 39735226 | _index_t base_array_nr_of_elements(const base_array_t a) | |
| 126 | { | ||
| 127 | int i; | ||
| 128 | _index_t nr_of_elements = 1; | ||
| 129 |
2/2✓ Branch 0 taken 40262787 times.
✓ Branch 1 taken 39735226 times.
|
79998013 | for(i = 0; i < a.ndims; ++i) { |
| 130 | 40262787 | nr_of_elements *= a.dim_size[i]; | |
| 131 | } | ||
| 132 | 39735226 | return nr_of_elements; | |
| 133 | } | ||
| 134 | |||
| 135 | /** | ||
| 136 | * @brief Get the size of a specific dimension in an array. | ||
| 137 | * | ||
| 138 | * Returns the size of the i-th dimension (1-based indexing). | ||
| 139 | * | ||
| 140 | * @param a The base array structure. | ||
| 141 | * @param i Dimension index (1-based: 1 to ndims). | ||
| 142 | * | ||
| 143 | * @return Size of the specified dimension, or 0 if dimension index is out of bounds | ||
| 144 | * or any prior dimension has size 0. | ||
| 145 | * | ||
| 146 | * @attention Uses 1-based indexing for dimensions (Modelica convention). | ||
| 147 | */ | ||
| 148 | 39896380 | _index_t size_of_dimension_base_array(const base_array_t a, int i) | |
| 149 | { | ||
| 150 | /* assert(base_array_ok(&a)); */ | ||
| 151 |
2/4✓ Branch 0 taken 39896380 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39896380 times.
|
39896380 | if ((i > 0) && (i <= a.ndims)) { |
| 152 | 39896380 | return a.dim_size[i-1]; | |
| 153 | } | ||
| 154 | /* This is a weird work-around to return 0 if the dimension is out of bounds and a dimension is 0 | ||
| 155 | * The reason is that we lose the dimensions in the DAE.ARRAY after a 0-dimension | ||
| 156 | * Note: We return size(arr,2)=0 if arr has dimensions [0,2], and not the expected 2 | ||
| 157 | */ | ||
| 158 | ✗ | for (i=0; i<a.ndims; i++) { | |
| 159 | ✗ | if (a.dim_size[i] == 0) { | |
| 160 | return 0; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | ✗ | fprintf(stderr, "size_of_dimension_base_array failed for i=%d, ndims=%d (ndims out of bounds)\n", i, a.ndims); | |
| 164 | ✗ | abort(); | |
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * @brief Initialize a base array structure with existing data and dimension information. | ||
| 169 | * | ||
| 170 | * Sets all fields in a base_array structure: data pointer, number of dimensions | ||
| 171 | * (ndims), and dimension sizes. The dimension sizes are extracted from a variable | ||
| 172 | * argument list passed as a va_list. | ||
| 173 | * | ||
| 174 | * @param dest Pointer to the base_array structure to initialize. | ||
| 175 | * @param data Pointer to the pre-allocated data buffer for array elements. | ||
| 176 | * @param ndims Number of dimensions. | ||
| 177 | * @param ap Variable argument list containing ndims dimension size values | ||
| 178 | * (each of type _index_t). | ||
| 179 | * | ||
| 180 | * @pre data pointer should be valid (typically allocated via malloc or gc). | ||
| 181 | * @pre ap must contain exactly ndims dimension size arguments of type _index_t. | ||
| 182 | * | ||
| 183 | * @note This is the low-level initialization function. Type-specific wrappers | ||
| 184 | * like real_array_create() typically call this function internally. | ||
| 185 | * | ||
| 186 | * @attention Sets dest->flexible to 0. The caller is responsible for ensuring | ||
| 187 | * the data buffer is large enough to hold all array elements. | ||
| 188 | */ | ||
| 189 | 19715007 | void base_array_create(base_array_t *dest, void *data, int ndims, va_list ap) | |
| 190 | { | ||
| 191 | int i; | ||
| 192 | |||
| 193 | 19715007 | dest->data = data; | |
| 194 | 19715007 | dest->ndims = ndims; | |
| 195 | |||
| 196 | 19715007 | dest->dim_size = size_alloc(ndims); | |
| 197 | |||
| 198 |
2/2✓ Branch 0 taken 19860851 times.
✓ Branch 1 taken 19715007 times.
|
39575858 | for(i = 0; i < ndims; ++i) { |
| 199 | 19860851 | dest->dim_size[i] = va_arg(ap, _index_t); | |
| 200 | } | ||
| 201 | |||
| 202 | 19715007 | dest->flexible = 0; | |
| 203 | 19715007 | dest->owns_data = 0; | |
| 204 | 19715007 | } | |
| 205 | |||
| 206 | /** | ||
| 207 | * @brief Validate that a base_array structure is well-formed. | ||
| 208 | * | ||
| 209 | * Performs comprehensive validity checks on all fields of the base_array structure. | ||
| 210 | * | ||
| 211 | * @param a Pointer to the base_array to validate. | ||
| 212 | * | ||
| 213 | * @return 1 if array is valid, 0 otherwise. Prints error messages to stderr for each | ||
| 214 | * validation failure. | ||
| 215 | * | ||
| 216 | * @attention This function performs diagnostic output to stderr. Failures indicate | ||
| 217 | * critical structural problems with the array. | ||
| 218 | */ | ||
| 219 | 41910102 | int base_array_ok(const base_array_t *a) | |
| 220 | { | ||
| 221 | int i; | ||
| 222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41910102 times.
|
41910102 | if(a == NULL) { |
| 223 | ✗ | fprintf(stderr, "base_array.c: array is NULL!\n"); fflush(stderr); | |
| 224 | ✗ | return 0; | |
| 225 | } | ||
| 226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41910102 times.
|
41910102 | if(a->ndims < 0) { |
| 227 | ✗ | fprintf(stderr, "base_array.c: the number of array dimensions are < 0!\n"); fflush(stderr); | |
| 228 | ✗ | return 0; | |
| 229 | } | ||
| 230 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41910102 times.
|
41910102 | if(a->dim_size == NULL) { |
| 231 | ✗ | fprintf(stderr, "base_array.c: array dimensions sizes are NULL!\n"); fflush(stderr); | |
| 232 | ✗ | return 0; | |
| 233 | } | ||
| 234 |
2/2✓ Branch 0 taken 42846593 times.
✓ Branch 1 taken 41910102 times.
|
84756695 | for(i = 0; i < a->ndims; ++i) { |
| 235 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42846593 times.
|
42846593 | if(a->dim_size[i] < 0) { |
| 236 | ✗ | fprintf(stderr, "base_array.c: array dimension size for dimension %d is %d < 0!\n", i, (int) a->dim_size[i]); fflush(stderr); | |
| 237 | ✗ | return 0; | |
| 238 | } | ||
| 239 | } | ||
| 240 | return 1; | ||
| 241 | } | ||
| 242 | |||
| 243 | /** | ||
| 244 | * @brief Verify that multiple arrays have identical dimensions. | ||
| 245 | * | ||
| 246 | * Helper function for operations like concatenation. Asserts that all provided | ||
| 247 | * arrays have the same number of dimensions and matching dimension sizes. | ||
| 248 | * | ||
| 249 | * @param elts Array of base_array pointers to check. | ||
| 250 | * @param n Number of arrays in the elts array. | ||
| 251 | * | ||
| 252 | * @pre All pointers in elts must be valid and non-NULL. | ||
| 253 | * | ||
| 254 | * @note This function uses assertions and will abort if validation fails. | ||
| 255 | * | ||
| 256 | * @attention Used internally by array allocation and concatenation functions. | ||
| 257 | */ | ||
| 258 | 170189 | void check_base_array_dim_sizes(const base_array_t *elts, int n) | |
| 259 | { | ||
| 260 | int i, curdim; | ||
| 261 | 170189 | int ndims = elts[0].ndims; | |
| 262 |
2/2✓ Branch 0 taken 274004 times.
✓ Branch 1 taken 170189 times.
|
444193 | for(i = 1; i < n; ++i) { |
| 263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 274004 times.
|
274004 | assert(elts[i].ndims == ndims && "Not same number of dimensions"); |
| 264 | } | ||
| 265 |
2/2✓ Branch 0 taken 170189 times.
✓ Branch 1 taken 170189 times.
|
340378 | for(curdim = 0; curdim < ndims; ++curdim) { |
| 266 | 170189 | int dimsize = elts[0].dim_size[curdim]; | |
| 267 |
2/2✓ Branch 0 taken 274004 times.
✓ Branch 1 taken 170189 times.
|
444193 | for(i = 1; i < n; ++i) { |
| 268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 274004 times.
|
274004 | assert(dimsize == elts[i].dim_size[curdim] |
| 269 | && "Dimensions size not same"); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | 170189 | } | |
| 273 | |||
| 274 | /** | ||
| 275 | * @brief Verify that multiple arrays have identical dimensions except one. | ||
| 276 | * | ||
| 277 | * Helper function for concatenation operations. Asserts that all provided arrays | ||
| 278 | * have the same number of dimensions and matching dimension sizes for all dimensions | ||
| 279 | * except dimension k (1-based). | ||
| 280 | * | ||
| 281 | * @param k Dimension to exclude from comparison (1-based indexing). | ||
| 282 | * @param elts Array of base_array pointers to check. | ||
| 283 | * @param n Number of arrays in the elts array. | ||
| 284 | * | ||
| 285 | * @pre All pointers in elts must be valid and non-NULL. | ||
| 286 | * | ||
| 287 | * @note This function uses assertions and will abort if validation fails. | ||
| 288 | * @note Dimension k is allowed to differ in size across arrays. | ||
| 289 | * | ||
| 290 | * @attention Used internally by array concatenation functions like cat_alloc_real_array(). | ||
| 291 | */ | ||
| 292 | ✗ | void check_base_array_dim_sizes_except(int k, const base_array_t *elts, int n) | |
| 293 | { | ||
| 294 | int i, curdim, dimsize; | ||
| 295 | ✗ | int k_loc = k - 1; | |
| 296 | ✗ | int ndims = elts[0].ndims; | |
| 297 | ✗ | for(i = 1; i < n; ++i) { | |
| 298 | ✗ | assert(elts[i].ndims == ndims && "Not same number of dimensions"); | |
| 299 | } | ||
| 300 | ✗ | for(curdim = 0; curdim < ndims; ++curdim) { | |
| 301 | ✗ | if(curdim != k_loc) { | |
| 302 | assert(elts); | ||
| 303 | ✗ | assert(elts[0].dim_size[curdim]); | |
| 304 | ✗ | dimsize = elts[0].dim_size[curdim]; | |
| 305 | |||
| 306 | ✗ | for(i = 1; i < n; ++i) { | |
| 307 | ✗ | assert(dimsize == elts[i].dim_size[curdim] | |
| 308 | && "Dimensions size not same"); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | } | ||
| 312 | ✗ | } | |
| 313 | |||
| 314 | /** | ||
| 315 | * @brief Compare the shapes (dimensions) of two arrays for equality. | ||
| 316 | * | ||
| 317 | * Checks if two arrays have the same number of dimensions and all matching | ||
| 318 | * dimension sizes. | ||
| 319 | * | ||
| 320 | * @param a First array to compare. | ||
| 321 | * @param b Second array to compare. | ||
| 322 | * | ||
| 323 | * @return 1 if arrays have identical shapes, 0 otherwise. Prints diagnostic | ||
| 324 | * messages to stderr if shapes differ. | ||
| 325 | */ | ||
| 326 | 513 | int base_array_shape_eq(const base_array_t *a, const base_array_t *b) | |
| 327 | { | ||
| 328 | int i; | ||
| 329 | |||
| 330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 513 times.
|
513 | if(a->ndims != b->ndims) { |
| 331 | ✗ | fprintf(stderr, "a->ndims != b->ndims, %d != %d\n", a->ndims, b->ndims); | |
| 332 | ✗ | return 0; | |
| 333 | } | ||
| 334 | |||
| 335 |
2/2✓ Branch 0 taken 513 times.
✓ Branch 1 taken 513 times.
|
1026 | for(i = 0; i < a->ndims; ++i) { |
| 336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 513 times.
|
513 | if(a->dim_size[i] != b->dim_size[i]) { |
| 337 | ✗ | fprintf(stderr, "a->dim_size[%d] != b->dim_size[%d], %d != %d\n", | |
| 338 | i, i, (int) a->dim_size[i], (int) b->dim_size[i]); | ||
| 339 | ✗ | return 0; | |
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | return 1; | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * @brief Check if an array contains exactly one element. | ||
| 348 | * | ||
| 349 | * Verifies that all dimensions have size 1, indicating a single-element array | ||
| 350 | * (equivalent to a scalar in array form). | ||
| 351 | * | ||
| 352 | * @param a The array to check. | ||
| 353 | * | ||
| 354 | * @return 1 if array has exactly one element (all dims = 1), 0 otherwise. | ||
| 355 | */ | ||
| 356 | ✗ | int base_array_one_element_ok(const base_array_t *a) | |
| 357 | { | ||
| 358 | int i; | ||
| 359 | |||
| 360 | ✗ | for(i = 0; i < a->ndims; ++i) { | |
| 361 | ✗ | if(a->dim_size[i] != 1) { | |
| 362 | return 0; | ||
| 363 | } | ||
| 364 | } | ||
| 365 | return 1; | ||
| 366 | } | ||
| 367 | |||
| 368 | /** | ||
| 369 | * @brief Validate that an index specification fits a base array. | ||
| 370 | * | ||
| 371 | * Checks that an index_spec_t structure is compatible with a base_array structure, | ||
| 372 | * verifying that dimensions agree and all indices are within valid bounds. | ||
| 373 | * | ||
| 374 | * @param s Index specification to validate. | ||
| 375 | * @param a Base array to validate against. | ||
| 376 | * | ||
| 377 | * @return 1 if index spec fits the array, 0 otherwise. Prints diagnostic error | ||
| 378 | * messages to stderr if validation fails. | ||
| 379 | * | ||
| 380 | * @attention Used to validate array indexing operations before execution. | ||
| 381 | */ | ||
| 382 | 275384 | int index_spec_fit_base_array(const index_spec_t *s, const base_array_t *a) | |
| 383 | { | ||
| 384 | int i, j; | ||
| 385 | |||
| 386 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 275384 times.
|
275384 | if(s->ndims != a->ndims) { |
| 387 | ✗ | fprintf(stderr, "index spec dimensions and array dimensions do not agree %d != %d\n", | |
| 388 | ✗ | (int)s->ndims, (int)a->ndims); fflush(stderr); | |
| 389 | ✗ | return 0; | |
| 390 | } | ||
| 391 |
2/2✓ Branch 0 taken 414766 times.
✓ Branch 1 taken 275384 times.
|
690150 | for(i = 0; i < s->ndims; ++i) { |
| 392 |
2/2✓ Branch 0 taken 138879 times.
✓ Branch 1 taken 275887 times.
|
414766 | if(s->index_type[i] == 'S') { |
| 393 |
1/2✓ Branch 0 taken 138879 times.
✗ Branch 1 not taken.
|
138879 | if (s->index[i] != NULL) |
| 394 | { | ||
| 395 |
2/4✓ Branch 0 taken 138879 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 138879 times.
|
138879 | if((s->index[i][0] < 0) || (s->index[i][0] > a->dim_size[i])) { |
| 396 | ✗ | fprintf(stderr, | |
| 397 | "scalar s->index[%d][0] == %d incorrect, a->dim_size[%d] == %d\n", | ||
| 398 | ✗ | i, (int) s->index[i][0], i, (int) a->dim_size[i]); fflush(stderr); | |
| 399 | ✗ | return 0; | |
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 |
2/2✓ Branch 0 taken 273598 times.
✓ Branch 1 taken 141168 times.
|
414766 | if(s->index[i] != NULL) |
| 405 | { | ||
| 406 |
2/2✓ Branch 0 taken 767535 times.
✓ Branch 1 taken 273598 times.
|
1041133 | for(j = 0; j < s->dim_size[i]; ++j) { |
| 407 |
2/4✓ Branch 0 taken 767535 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 767535 times.
|
767535 | if((s->index[i][j] <= 0) || (s->index[i][j] > a->dim_size[i])) { |
| 408 | ✗ | fprintf(stderr, | |
| 409 | "array s->index[%d][%d] == %d incorrect, a->dim_size[%d] == %d\n", | ||
| 410 | ✗ | i, j, (int) s->index[i][j], i, (int) a->dim_size[i]); fflush(stderr); | |
| 411 | ✗ | return 0; | |
| 412 | } | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | return 1; | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * @brief Number of elements an index specification selects. | ||
| 422 | * | ||
| 423 | * @param s Index specification, fitting a. | ||
| 424 | * @param a Array that s indexes. | ||
| 425 | * @return The product of the sizes of the dimensions s keeps. | ||
| 426 | */ | ||
| 427 | 24016 | _index_t index_spec_nr_of_elements(const index_spec_t *s, const base_array_t *a) | |
| 428 | { | ||
| 429 | int i; | ||
| 430 | _index_t n = 1; | ||
| 431 | |||
| 432 |
2/2✓ Branch 0 taken 48032 times.
✓ Branch 1 taken 24016 times.
|
72048 | for(i = 0; i < s->ndims; ++i) { |
| 433 |
3/3✓ Branch 0 taken 8882 times.
✓ Branch 1 taken 15637 times.
✓ Branch 2 taken 23513 times.
|
48032 | switch(s->index_type[i]) { |
| 434 | 8882 | case 'W': n *= a->dim_size[i]; break; | |
| 435 | 15637 | case 'A': n *= s->dim_size[i]; break; | |
| 436 | default: break; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | 24016 | return n; | |
| 440 | } | ||
| 441 | |||
| 442 | /** | ||
| 443 | * @brief Initialize a 1D base array with existing data. | ||
| 444 | * | ||
| 445 | * Convenience function for creating a simple 1D array structure with pre-allocated data. | ||
| 446 | * | ||
| 447 | * @param dest Pointer to the base_array structure to initialize. | ||
| 448 | * @param n Size of the 1D array (number of elements). | ||
| 449 | * @param data Pointer to the pre-allocated data buffer. | ||
| 450 | */ | ||
| 451 | 24323743 | void simple_alloc_1d_base_array(base_array_t *dest, int n, void *data) | |
| 452 | { | ||
| 453 | 24323743 | dest->ndims = 1; | |
| 454 | 24323743 | dest->dim_size = size_alloc(1); | |
| 455 | 24323743 | dest->dim_size[0] = n; | |
| 456 | 24323743 | dest->data = data; | |
| 457 | 24323743 | dest->flexible = 0; | |
| 458 | 24323743 | dest->owns_data = 1; | |
| 459 | 24323743 | } | |
| 460 | |||
| 461 | /** | ||
| 462 | * @brief Initialize a 2D base array with existing data. | ||
| 463 | * | ||
| 464 | * Convenience function for creating a simple 2D array structure with pre-allocated data. | ||
| 465 | * | ||
| 466 | * @param dest Pointer to the base_array structure to initialize. | ||
| 467 | * @param r Number of rows. | ||
| 468 | * @param c Number of columns. | ||
| 469 | * @param data Pointer to the pre-allocated data buffer. | ||
| 470 | */ | ||
| 471 | 3557 | void simple_alloc_2d_base_array(base_array_t *dest, int r, int c, void *data) | |
| 472 | { | ||
| 473 | 3557 | dest->ndims = 2; | |
| 474 | 3557 | dest->dim_size = size_alloc(2); | |
| 475 | 3557 | dest->dim_size[0] = r; | |
| 476 | 3557 | dest->dim_size[1] = c; | |
| 477 | 3557 | dest->data = data; | |
| 478 | 3557 | dest->flexible = 0; | |
| 479 | 3557 | dest->owns_data = 1; | |
| 480 | 3557 | } | |
| 481 | |||
| 482 | /** | ||
| 483 | * @brief Allocate and initialize a base array structure with variable dimensions. | ||
| 484 | * | ||
| 485 | * Initializes a base_array structure by setting the number of dimensions and | ||
| 486 | * allocating space for dimension sizes. The dimension sizes are extracted from | ||
| 487 | * a variable argument list. Computes the total number of elements needed. | ||
| 488 | * | ||
| 489 | * @param dest Pointer to the base_array structure to initialize. | ||
| 490 | * @param ndims Number of dimensions. | ||
| 491 | * @param ap Variable argument list containing ndims dimension size values | ||
| 492 | * (each of type _index_t). | ||
| 493 | * | ||
| 494 | * @return Total number of elements in the array (product of all dimension sizes). | ||
| 495 | * | ||
| 496 | * @pre ap must contain exactly ndims dimension size arguments of type _index_t. | ||
| 497 | * | ||
| 498 | * @note The caller is responsible for allocating the actual data buffer separately | ||
| 499 | * and assigning it to dest->data. This function only allocates the metadata | ||
| 500 | * (dimension information). | ||
| 501 | * | ||
| 502 | * @attention Sets dest->flexible to 0. Used internally by type-specific allocation | ||
| 503 | * functions like alloc_real_array(). | ||
| 504 | */ | ||
| 505 | 5370891 | size_t alloc_base_array(base_array_t *dest, int ndims, va_list ap) | |
| 506 | { | ||
| 507 | int i; | ||
| 508 | size_t nr_of_elements = 1; | ||
| 509 | |||
| 510 | 5370891 | dest->ndims = ndims; | |
| 511 | 5370891 | dest->dim_size = size_alloc(ndims); | |
| 512 | |||
| 513 |
2/2✓ Branch 0 taken 5726224 times.
✓ Branch 1 taken 5370891 times.
|
11097115 | for(i = 0; i < ndims; ++i) { |
| 514 | 5726224 | dest->dim_size[i] = va_arg(ap, _index_t); | |
| 515 | 5726224 | nr_of_elements *= dest->dim_size[i]; | |
| 516 | } | ||
| 517 | |||
| 518 | 5370891 | dest->flexible = 0; | |
| 519 | 5370891 | dest->owns_data = 1; | |
| 520 | |||
| 521 | 5370891 | return nr_of_elements; | |
| 522 | } | ||
| 523 | |||
| 524 | /** | ||
| 525 | * @brief Copy dimension specification from one array to another. | ||
| 526 | * | ||
| 527 | * Creates a copy of the dimension metadata (number of dimensions and dimension sizes) | ||
| 528 | * from source array to destination array. Does not copy the data pointer. | ||
| 529 | * | ||
| 530 | * @param source Source array to copy specification from. | ||
| 531 | * @param dest Destination array to copy specification to. | ||
| 532 | * | ||
| 533 | * @pre source must be a valid base_array structure. | ||
| 534 | * | ||
| 535 | * @note The destination array should have an uninitialized dim_size pointer, | ||
| 536 | * as new memory will be allocated for it. | ||
| 537 | */ | ||
| 538 | 25959907 | void clone_base_array_spec(const base_array_t *source, base_array_t *dest) | |
| 539 | { | ||
| 540 | int i; | ||
| 541 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25959907 times.
|
25959907 | assert(base_array_ok(source)); |
| 542 | |||
| 543 | 25959907 | dest->ndims = source->ndims; | |
| 544 | 25959907 | dest->dim_size = size_alloc(dest->ndims); | |
| 545 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25959907 times.
|
25959907 | assert(dest->dim_size); |
| 546 | |||
| 547 |
2/2✓ Branch 0 taken 26117784 times.
✓ Branch 1 taken 25959907 times.
|
52077691 | for(i = 0; i < dest->ndims; ++i) { |
| 548 | 26117784 | dest->dim_size[i] = source->dim_size[i]; | |
| 549 | } | ||
| 550 | |||
| 551 | 25959907 | dest->flexible = source->flexible; | |
| 552 | 25959907 | dest->owns_data = 1; | |
| 553 | 25959907 | } | |
| 554 | |||
| 555 | /** | ||
| 556 | * @brief Calculate flat index using index specification. | ||
| 557 | * | ||
| 558 | * Converts multi-dimensional indices with an index specification into a flat 1D index. | ||
| 559 | * Handles both scalar indexing and array slicing specifications. | ||
| 560 | * | ||
| 561 | * @param ndims Number of dimensions. | ||
| 562 | * @param idx_vec Array of indices (0-based). | ||
| 563 | * @param arr Base array containing dimension information. | ||
| 564 | * @param spec Index specification defining how to map indices. | ||
| 565 | * | ||
| 566 | * @return Flat 1D index for array element access. | ||
| 567 | * | ||
| 568 | * @pre idx_vec must have exactly ndims elements. | ||
| 569 | * @pre spec and arr dimensions must be compatible. | ||
| 570 | * @pre All indices and specifications must be valid and within bounds. | ||
| 571 | * | ||
| 572 | * @note idx_vec uses 0-based indexing while spec uses 1-based indexing. | ||
| 573 | */ | ||
| 574 | 4419589 | size_t calc_base_index_spec(int ndims, const _index_t *idx_vec, | |
| 575 | const base_array_t *arr, const index_spec_t *spec) | ||
| 576 | { | ||
| 577 | int i; | ||
| 578 | int d2; | ||
| 579 | size_t index = 0; | ||
| 580 | |||
| 581 | /* index_spec_fit_base_array is O(size of spec); the callers check it once */ | ||
| 582 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4419589 times.
|
4419589 | assert(base_array_ok(arr)); |
| 583 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4419589 times.
|
4419589 | assert(index_spec_ok(spec)); |
| 584 |
2/4✓ Branch 0 taken 4419589 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4419589 times.
|
4419589 | assert((ndims == arr->ndims) && (ndims == spec->ndims)); |
| 585 | |||
| 586 | index = 0; | ||
| 587 |
2/2✓ Branch 0 taken 4763485 times.
✓ Branch 1 taken 4419589 times.
|
9183074 | for(i = 0; i < ndims; ++i) { |
| 588 | 4763485 | int d = idx_vec[i]; | |
| 589 |
2/2✓ Branch 0 taken 757177 times.
✓ Branch 1 taken 4006308 times.
|
4763485 | if(spec->index_type[i] != 'W') { |
| 590 | 757177 | d2 = spec->index[i][d] - 1; | |
| 591 | } else { | ||
| 592 | d2 = d; | ||
| 593 | } | ||
| 594 | 4763485 | index = (index * arr->dim_size[i]) + d2; | |
| 595 | } | ||
| 596 | |||
| 597 | 4419589 | return index; | |
| 598 | } | ||
| 599 | |||
| 600 | /** | ||
| 601 | * @brief Calculate flat index from 0-based multi-dimensional indices. | ||
| 602 | * | ||
| 603 | * Converts multi-dimensional indices (0-based) into a flat 1D index using row-major order. | ||
| 604 | * | ||
| 605 | * @param ndims Number of dimensions. | ||
| 606 | * @param idx_vec Array of 0-based indices. | ||
| 607 | * @param arr Base array containing dimension information. | ||
| 608 | * | ||
| 609 | * @return Flat 1D index for array element access. | ||
| 610 | * | ||
| 611 | * @pre idx_vec must have exactly ndims elements. | ||
| 612 | * @pre All indices must be within valid bounds. | ||
| 613 | */ | ||
| 614 | ✗ | size_t calc_base_index(int ndims, const _index_t *idx_vec, const base_array_t *arr) | |
| 615 | { | ||
| 616 | int i; | ||
| 617 | size_t index = 0; | ||
| 618 | ✗ | assert(ndims == arr->ndims); | |
| 619 | |||
| 620 | ✗ | for(i = 0; i < ndims; ++i) { | |
| 621 | /* Assert that idx_vec[i] is not out of bounds */ | ||
| 622 | ✗ | index = (index * arr->dim_size[i]) + idx_vec[i]; | |
| 623 | } | ||
| 624 | |||
| 625 | ✗ | return index; | |
| 626 | } | ||
| 627 | |||
| 628 | /** | ||
| 629 | * @brief Calculate flat index from dimension sizes and 1-based subscripts. | ||
| 630 | * | ||
| 631 | * Calculates a flat 1D index from variable argument lists containing dimension | ||
| 632 | * sizes followed by 1-based subscripts. Includes bounds checking with assertions. | ||
| 633 | * | ||
| 634 | * @param ndims Number of dimensions. | ||
| 635 | * @param ... Variable arguments: first ndims values are dimension sizes, | ||
| 636 | * next ndims values are 1-based subscripts. | ||
| 637 | * | ||
| 638 | * @return Flat 1D index for array element access. | ||
| 639 | * | ||
| 640 | * @attention Asserts on any out-of-bounds subscript. | ||
| 641 | * @attention Subscripts are converted from 1-based to 0-based internally. | ||
| 642 | */ | ||
| 643 | ✗ | size_t calc_base_index_dims_subs(int ndims,...) | |
| 644 | { | ||
| 645 | |||
| 646 | int i; | ||
| 647 | size_t index; | ||
| 648 | |||
| 649 | ✗ | _index_t *dims = (_index_t*)omc_alloc_interface.malloc(sizeof(_index_t)*ndims); | |
| 650 | ✗ | _index_t *subs = (_index_t*)omc_alloc_interface.malloc(sizeof(_index_t)*ndims); | |
| 651 | |||
| 652 | va_list ap; | ||
| 653 | ✗ | va_start(ap,ndims); | |
| 654 | ✗ | for(i = 0; i < ndims; ++i) { | |
| 655 | ✗ | dims[i] = va_arg(ap, _index_t); | |
| 656 | } | ||
| 657 | ✗ | for(i = 0; i < ndims; ++i) { | |
| 658 | ✗ | subs[i] = va_arg(ap, _index_t) - 1; | |
| 659 | } | ||
| 660 | ✗ | va_end(ap); | |
| 661 | |||
| 662 | index = 0; | ||
| 663 | ✗ | for(i = 0; i < ndims; ++i) { | |
| 664 | ✗ | if (subs[i] < 0 || subs[i] >= dims[i]) { | |
| 665 | ✗ | omc_assert(NULL, omc_dummyFileInfo, "Dimension %d has bounds 1..%d, got array subscript %d", i+1, dims[i], subs[i]+1); | |
| 666 | ✗ | return 0; | |
| 667 | } | ||
| 668 | ✗ | index = (index * dims[i]) + subs[i]; | |
| 669 | } | ||
| 670 | |||
| 671 | |||
| 672 | return index; | ||
| 673 | } | ||
| 674 | |||
| 675 | /** | ||
| 676 | * @brief Calculate flat index from 1-based subscripts in a variable argument list. | ||
| 677 | * | ||
| 678 | * Converts 1-based subscripts from a va_list into a flat 0-based index. | ||
| 679 | * Includes bounds checking with assertions. | ||
| 680 | * | ||
| 681 | * @param source Base array containing dimension information. | ||
| 682 | * @param ndims Number of dimensions. | ||
| 683 | * @param ap Variable argument list containing ndims 1-based subscripts. | ||
| 684 | * | ||
| 685 | * @return Flat 1D (0-based) index for array element access. | ||
| 686 | * | ||
| 687 | * @pre ap must contain exactly ndims subscript values (1-based). | ||
| 688 | * | ||
| 689 | * @attention Asserts on any out-of-bounds subscript. | ||
| 690 | * @attention Input subscripts are 1-based; output index is 0-based. | ||
| 691 | */ | ||
| 692 | 11060 | size_t calc_base_index_va(const base_array_t *source, int ndims, va_list ap) | |
| 693 | { | ||
| 694 | int i; | ||
| 695 | size_t index; | ||
| 696 | |||
| 697 | index = 0; | ||
| 698 |
2/2✓ Branch 0 taken 11060 times.
✓ Branch 1 taken 11060 times.
|
22120 | for(i = 0; i < ndims; ++i) { |
| 699 | 11060 | int sub_i = va_arg(ap, _index_t) - 1; | |
| 700 |
2/4✓ Branch 0 taken 11060 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11060 times.
|
11060 | if (sub_i < 0 || sub_i >= source->dim_size[i]) { |
| 701 | ✗ | omc_assert(NULL, omc_dummyFileInfo, "Dimension %d has bounds 1..%d, got array subscript %d", i+1, source->dim_size[i], sub_i+1); | |
| 702 | ✗ | return 0; | |
| 703 | } | ||
| 704 | 11060 | index = (index * source->dim_size[i]) + sub_i; | |
| 705 | } | ||
| 706 | |||
| 707 | return index; | ||
| 708 | } | ||
| 709 | |||
| 710 | ✗ | size_t omc_array_bounds_error(int dim, _index_t dim_size, _index_t sub) | |
| 711 | { | ||
| 712 | ✗ | omc_assert(NULL, omc_dummyFileInfo, "Dimension %d has bounds 1..%d, got array subscript %d", dim, (int)dim_size, (int)sub); | |
| 713 | ✗ | return 0; | |
| 714 | } | ||
| 715 | |||
| 716 | /** | ||
| 717 | * @brief Get the number of dimensions in an array. | ||
| 718 | * | ||
| 719 | * @param[in] a The base array structure. | ||
| 720 | * | ||
| 721 | * @return Number of dimensions (ndims). | ||
| 722 | * | ||
| 723 | * @pre a must be a valid base_array structure. | ||
| 724 | */ | ||
| 725 | 5543 | int ndims_base_array(const base_array_t* a) | |
| 726 | { | ||
| 727 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5543 times.
|
5543 | assert(base_array_ok(a)); |
| 728 | 5543 | return a->ndims; | |
| 729 | } | ||
| 730 | |||
| 731 | /** | ||
| 732 | * @brief Clone array dimensions in reversed order. | ||
| 733 | * | ||
| 734 | * Creates a copy of the source array's dimension specification but with | ||
| 735 | * dimensions in reverse order. For example, a 2x3x4 array becomes 4x3x2. | ||
| 736 | * | ||
| 737 | * @param source The source array with dimensions to reverse. | ||
| 738 | * @param dest The destination array where reversed dimensions are stored. | ||
| 739 | * | ||
| 740 | * @pre source must be a valid base_array structure. | ||
| 741 | * @pre dest must not be NULL. | ||
| 742 | * @attention Allocates new memory for dest->dim_size; caller is responsible | ||
| 743 | * for cleanup. | ||
| 744 | */ | ||
| 745 | 319827 | void clone_reverse_base_array_spec(const base_array_t* source, base_array_t* dest) | |
| 746 | { | ||
| 747 | int i; | ||
| 748 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 319827 times.
|
319827 | assert(base_array_ok(source)); |
| 749 | |||
| 750 | 319827 | dest->ndims = source->ndims; | |
| 751 | 319827 | dest->dim_size = size_alloc(dest->ndims); | |
| 752 | 319827 | dest->owns_data = 1; | |
| 753 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 319827 times.
|
319827 | assert(dest->dim_size); |
| 754 | |||
| 755 |
2/2✓ Branch 0 taken 400558 times.
✓ Branch 1 taken 319827 times.
|
720385 | for(i = 0; i < dest->ndims; ++i) { |
| 756 | 400558 | dest->dim_size[i] = source->dim_size[dest->ndims - 1 - i]; | |
| 757 | } | ||
| 758 | 319827 | } | |
| 759 | |||
| 760 | /** | ||
| 761 | * @brief Allocate and compute destination array dimensions from indexed access. | ||
| 762 | * | ||
| 763 | * Determines the resulting array dimensions when an index_spec is applied to | ||
| 764 | * a source array, handling 'A' (all) and 'W' (wildcard) index dimensions. | ||
| 765 | * Only counts non-zero dimension sizes. | ||
| 766 | * | ||
| 767 | * #### Example | ||
| 768 | * For a 3x4x5 source array with index spec that selects [2, :, :], | ||
| 769 | * the destination array will have dimensions 4x5 (skipping the indexed dimension). | ||
| 770 | * | ||
| 771 | * @param source The source array to index into. | ||
| 772 | * @param source_spec The index specification defining which dimensions/indices to access. | ||
| 773 | * @param dest The destination array where computed dimensions are stored. | ||
| 774 | * | ||
| 775 | * @pre source must be a valid base_array structure. | ||
| 776 | * @pre source_spec must be valid and fit the source array. | ||
| 777 | * @pre dest must not be NULL. | ||
| 778 | */ | ||
| 779 | 125684 | void index_alloc_base_array_size(const real_array * source, | |
| 780 | const index_spec_t* source_spec, | ||
| 781 | base_array_t* dest) | ||
| 782 | { | ||
| 783 | int i; | ||
| 784 | int j; | ||
| 785 | |||
| 786 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
|
125684 | omc_assert_macro(base_array_ok(source)); |
| 787 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
|
125684 | omc_assert_macro(index_spec_ok(source_spec)); |
| 788 |
1/2✓ Branch 1 taken 125684 times.
✗ Branch 2 not taken.
|
125684 | omc_assert_macro(index_spec_fit_base_array(source_spec, source)); |
| 789 | |||
| 790 |
2/2✓ Branch 0 taken 183367 times.
✓ Branch 1 taken 125684 times.
|
309051 | for(i = 0, j = 0; i < source_spec->ndims; ++i) { |
| 791 |
2/2✓ Branch 0 taken 125684 times.
✓ Branch 1 taken 57683 times.
|
183367 | if(source_spec->index_type[i] != 'S') { |
| 792 | 125684 | ++j; | |
| 793 | } | ||
| 794 | } | ||
| 795 | |||
| 796 | 125684 | dest->ndims = imax(j,1); | |
| 797 | 125684 | dest->dim_size = size_alloc(dest->ndims); | |
| 798 | 125684 | dest->owns_data = 1; | |
| 799 |
2/2✓ Branch 0 taken 125684 times.
✓ Branch 1 taken 125684 times.
|
251368 | for(i = 0; i < dest->ndims; ++i) { |
| 800 | 125684 | dest->dim_size[i] = 0; | |
| 801 | } | ||
| 802 | |||
| 803 |
2/2✓ Branch 0 taken 183367 times.
✓ Branch 1 taken 125684 times.
|
309051 | for(i = 0, j = 0; i < source_spec->ndims; ++i) { |
| 804 |
2/2✓ Branch 0 taken 125684 times.
✓ Branch 1 taken 57683 times.
|
183367 | if(source_spec->index_type[i] != 'S') { |
| 805 |
2/2✓ Branch 0 taken 59541 times.
✓ Branch 1 taken 66143 times.
|
125684 | if(source_spec->index_type[i] == 'A') { |
| 806 | 59541 | dest->dim_size[j] = source_spec->dim_size[i]; | |
| 807 | } else { /* is 'W' */ | ||
| 808 | 66143 | dest->dim_size[j] = source->dim_size[i]; | |
| 809 | } | ||
| 810 | |||
| 811 | 125684 | ++j; | |
| 812 | } | ||
| 813 | } | ||
| 814 | 125684 | } | |
| 815 | |||
| 816 | /** | ||
| 817 | * @brief Allocate and initialize index vectors for indexed assignment. | ||
| 818 | * | ||
| 819 | * Prepares index iteration structures for assigning elements to a destination | ||
| 820 | * array via an index specification. Allocates vectors for tracking current | ||
| 821 | * indices and dimension sizes in the indexed assignment operation. | ||
| 822 | * | ||
| 823 | * #### Example | ||
| 824 | * For assigning a 4x5 source array to elements dest[2, :, :] of a 3x4x5 array, | ||
| 825 | * this initializes the iteration indices and size boundaries. | ||
| 826 | * | ||
| 827 | * @param source The source array being assigned. | ||
| 828 | * @param dest The destination array being assigned to. | ||
| 829 | * @param dest_spec The index specification defining target locations in dest. | ||
| 830 | * @param _idx_vec1 Output: current iteration indices for destination. | ||
| 831 | * @param _idx_size Output: dimension size boundaries for destination iteration. | ||
| 832 | * | ||
| 833 | * @pre source must be a valid base_array with dimensions matching indexed dest. | ||
| 834 | * @pre dest must be a valid base_array structure. | ||
| 835 | * @pre dest_spec must be valid and fit the dest array. | ||
| 836 | * @pre _idx_vec1 and _idx_size must be valid pointers to _index_t*. | ||
| 837 | */ | ||
| 838 | 24016 | void indexed_assign_base_array_size_alloc(const base_array_t *source, base_array_t *dest, const index_spec_t *dest_spec, _index_t** _idx_vec1, _index_t** _idx_size) | |
| 839 | { | ||
| 840 | _index_t* idx_vec1; | ||
| 841 | _index_t* idx_size; | ||
| 842 | int i, j; | ||
| 843 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24016 times.
|
24016 | omc_assert_macro(base_array_ok(source)); |
| 844 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24016 times.
|
24016 | omc_assert_macro(base_array_ok(dest)); |
| 845 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24016 times.
|
24016 | omc_assert_macro(index_spec_ok(dest_spec)); |
| 846 |
1/2✓ Branch 1 taken 24016 times.
✗ Branch 2 not taken.
|
24016 | omc_assert_macro(index_spec_fit_base_array(dest_spec, dest)); |
| 847 |
2/2✓ Branch 0 taken 48032 times.
✓ Branch 1 taken 24016 times.
|
72048 | for(i = 0,j = 0; i < dest_spec->ndims; ++i) { |
| 848 |
2/2✓ Branch 0 taken 24519 times.
✓ Branch 1 taken 23513 times.
|
48032 | if(dest_spec->index_type[i] != 'S') { |
| 849 | 24519 | ++j; | |
| 850 | } | ||
| 851 | } | ||
| 852 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24016 times.
|
24016 | omc_assert_macro(j == source->ndims); |
| 853 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 24016 times.
|
24016 | omc_assert_macro(index_spec_nr_of_elements(dest_spec, dest) == base_array_nr_of_elements(*source)); |
| 854 | |||
| 855 | 24016 | idx_vec1 = size_alloc(dest->ndims); | |
| 856 | 24016 | idx_size = size_alloc(dest_spec->ndims); | |
| 857 | |||
| 858 |
2/2✓ Branch 0 taken 48032 times.
✓ Branch 1 taken 24016 times.
|
72048 | for(i = 0; i < dest_spec->ndims; ++i) { |
| 859 | 48032 | idx_vec1[i] = 0; | |
| 860 | |||
| 861 |
2/2✓ Branch 0 taken 39150 times.
✓ Branch 1 taken 8882 times.
|
48032 | if(dest_spec->index_type[i] != 'W') { |
| 862 | 39150 | idx_size[i] = imax(dest_spec->dim_size[i],1); | |
| 863 | } else { /* is 'W' */ | ||
| 864 | 8882 | idx_size[i] = dest->dim_size[i]; | |
| 865 | } | ||
| 866 | } | ||
| 867 | 24016 | *_idx_vec1 = idx_vec1; | |
| 868 | 24016 | *_idx_size = idx_size; | |
| 869 | 24016 | } | |
| 870 | |||
| 871 | 37610590 | void omc_array_retain(base_array_t *a) | |
| 872 | { | ||
| 873 |
1/2✓ Branch 0 taken 37610590 times.
✗ Branch 1 not taken.
|
37610590 | if (!a) { |
| 874 | return; | ||
| 875 | } | ||
| 876 |
2/2✓ Branch 0 taken 1887211 times.
✓ Branch 1 taken 35723379 times.
|
37610590 | if (a->owns_data) { |
| 877 |
1/2✓ Branch 0 taken 1887211 times.
✗ Branch 1 not taken.
|
1887211 | omc_rc_retain_inline(a->data); |
| 878 | } | ||
| 879 |
1/2✓ Branch 0 taken 37610590 times.
✗ Branch 1 not taken.
|
37610590 | omc_rc_retain_inline(a->dim_size); |
| 880 | } | ||
| 881 | |||
| 882 | 231361970 | void omc_array_release(base_array_t *a) | |
| 883 | { | ||
| 884 |
1/2✓ Branch 0 taken 231361970 times.
✗ Branch 1 not taken.
|
231361970 | if (!a) { |
| 885 | return; | ||
| 886 | } | ||
| 887 |
2/2✓ Branch 0 taken 57240009 times.
✓ Branch 1 taken 174121961 times.
|
231361970 | if (a->owns_data) { |
| 888 | 57240009 | omc_rc_release_inline(a->data); | |
| 889 | } | ||
| 890 | 231361970 | omc_rc_release_inline(a->dim_size); | |
| 891 | 231361970 | a->data = NULL; | |
| 892 | 231361970 | a->dim_size = NULL; | |
| 893 | 231361970 | a->ndims = 0; | |
| 894 | 231361970 | a->owns_data = 0; | |
| 895 | } | ||
| 896 | |||
| 897 | ✗ | void omc_record_array_release(base_array_t *a, void (*release)(void*), size_t elem_size) | |
| 898 | { | ||
| 899 | ✗ | if (a && a->owns_data && a->data && omc_rc_is_last(a->data)) { | |
| 900 | ✗ | size_t i, n = base_array_nr_of_elements(*a); | |
| 901 | ✗ | char *elems = (char*) a->data; | |
| 902 | ✗ | for (i = 0; i < n; ++i) { | |
| 903 | ✗ | release(elems + i*elem_size); | |
| 904 | } | ||
| 905 | } | ||
| 906 | ✗ | omc_array_release(a); | |
| 907 | ✗ | } | |
| 908 | |||
| 909 | 1801 | void omc_string_array_release(base_array_t *a) | |
| 910 | { | ||
| 911 |
5/8✓ Branch 0 taken 1801 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 141 times.
✓ Branch 3 taken 1660 times.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 141 times.
✗ Branch 8 not taken.
|
1801 | if (a && a->owns_data && a->data && omc_rc_is_last(a->data)) { |
| 912 | 141 | size_t i, n = base_array_nr_of_elements(*a); | |
| 913 | 141 | modelica_string *elems = (modelica_string*) a->data; | |
| 914 |
2/2✓ Branch 0 taken 212 times.
✓ Branch 1 taken 141 times.
|
353 | for (i = 0; i < n; ++i) { |
| 915 | 212 | omc_string_release(elems[i]); | |
| 916 | } | ||
| 917 | } | ||
| 918 | 1801 | omc_array_release(a); | |
| 919 | 1801 | } | |
| 920 | |||
| 921 | /** | ||
| 922 | * @brief Write vector into null-terminated string. | ||
| 923 | * | ||
| 924 | * Scalars are written as `v`, vectors as `{v1, v2, ...}`. If `buffer` is too | ||
| 925 | * small the output is truncated with `"...}"`. | ||
| 926 | * | ||
| 927 | * @param source Vector to write to `buffer`. | ||
| 928 | * @param isScalar Treat vector of length one as scalar. | ||
| 929 | * @param format_element Writes element `i` of `data` into a buffer, like `snprintf`. | ||
| 930 | * @param buffer Buffer to write into. | ||
| 931 | * @param bufsize Length of `buffer`. | ||
| 932 | */ | ||
| 933 | 16 | void base_vector_to_string(const base_array_t *source, | |
| 934 | modelica_boolean isScalar, | ||
| 935 | base_array_format_element_t format_element, | ||
| 936 | char *buffer, | ||
| 937 | size_t bufsize) | ||
| 938 | { | ||
| 939 | _index_t i; | ||
| 940 | size_t pos = 0; | ||
| 941 | int ret; | ||
| 942 | size_t remaining; | ||
| 943 | |||
| 944 | /* Validate input parameters */ | ||
| 945 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (buffer == NULL || bufsize == 0) { |
| 946 | return; | ||
| 947 | } | ||
| 948 | 16 | buffer[0] = '\0'; | |
| 949 | |||
| 950 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | omc_assert_macro(base_array_ok(source)); |
| 951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | assert(source->ndims == 1); |
| 952 | |||
| 953 |
3/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
16 | if (isScalar && source->ndims == 1 && source->dim_size[0] == 1) |
| 954 | { | ||
| 955 | /* Write scalar into buffer */ | ||
| 956 | 11 | format_element(buffer + pos, bufsize - pos, source->data, 0); | |
| 957 | 11 | return; | |
| 958 | } | ||
| 959 | |||
| 960 | /* Start brace */ | ||
| 961 | ret = snprintf(buffer + pos, (bufsize > pos) ? bufsize - pos : 0, "{"); | ||
| 962 | if (ret < 0) ret = 0; | ||
| 963 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if ((size_t)ret >= bufsize - pos) { |
| 964 | return; | ||
| 965 | } | ||
| 966 | pos += (size_t)ret; | ||
| 967 | |||
| 968 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
|
18 | for (i = 0; i < source->dim_size[0]; i++) |
| 969 | { | ||
| 970 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | remaining = (bufsize > pos) ? bufsize - pos : 0; |
| 971 | |||
| 972 | /* If not enough room to write an element, try to append "...}" and stop */ | ||
| 973 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (remaining <= 5) { |
| 974 | ✗ | snprintf(buffer + pos, remaining, "...}"); | |
| 975 | ✗ | return; | |
| 976 | } | ||
| 977 | |||
| 978 | /* Format element, use comma+space for non-last elements */ | ||
| 979 | 13 | ret = format_element(buffer + pos, remaining, source->data, i); | |
| 980 |
4/6✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 5 times.
|
13 | if (ret >= 0 && (size_t)ret < remaining && i < source->dim_size[0] - 1) { |
| 981 | 8 | ret += snprintf(buffer + pos + ret, remaining - ret, ", "); | |
| 982 | } | ||
| 983 | |||
| 984 | if (ret < 0) ret = 0; | ||
| 985 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (ret >= remaining - 5) { |
| 986 | /* Not enough space for more elements; try to write "...}" instead */ | ||
| 987 | snprintf(buffer + pos, remaining, "...}"); | ||
| 988 | ✗ | return; | |
| 989 | } | ||
| 990 | 13 | pos += (size_t)ret; | |
| 991 | } | ||
| 992 | |||
| 993 | /* Append closing brace */ | ||
| 994 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | remaining = (bufsize > pos) ? bufsize - pos : 0; |
| 995 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (remaining > 0) { |
| 996 | 5 | snprintf(buffer + pos, remaining, "}"); | |
| 997 | } | ||
| 998 | } | ||
| 999 |