OMCompiler/SimulationRuntime/c/util/generic_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 | #include <string.h> | ||
| 29 | #include <stdint.h> | ||
| 30 | |||
| 31 | #include "generic_array.h" | ||
| 32 | #include "omc_error.h" | ||
| 33 | |||
| 34 | static void* generic_ptrget(const base_array_t *a, size_t sze, size_t i) { | ||
| 35 | 11060 | return ((char*)a->data) + (i*sze); | |
| 36 | } | ||
| 37 | |||
| 38 | static int generic_array_ndims_eq(const base_array_t* src, const base_array_t* dst) { | ||
| 39 |
1/2✓ Branch 0 taken 8856494 times.
✗ Branch 1 not taken.
|
8856494 | if(src->ndims != dst->ndims) { |
| 40 | ✗ | fprintf(stderr, "src->ndims != dst->ndims, %d != %d\n", src->ndims, dst->ndims); | |
| 41 | return 0; | ||
| 42 | } | ||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | #define omc_FORMAT "src->dim_size[%d] != dst->dim_size[%d], %" PRINT_MMC_SINT_T " != %" PRINT_MMC_SINT_T "\n" | ||
| 47 | |||
| 48 | ✗ | static int generic_array_dimsizes_eq(const base_array_t* src, const base_array_t* dst, int print_error) | |
| 49 | { | ||
| 50 | int i; | ||
| 51 |
2/4✓ Branch 0 taken 9069533 times.
✓ Branch 1 taken 8853472 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
17923005 | for(i = 0; i < src->ndims; ++i) { |
| 52 |
2/4✓ Branch 0 taken 9066511 times.
✓ Branch 1 taken 3022 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
9069533 | if(src->dim_size[i] != dst->dim_size[i]) { |
| 53 | ✗ | if (print_error) { | |
| 54 | ✗ | fprintf(stderr, omc_FORMAT, | |
| 55 | i, i, src->dim_size[i], dst->dim_size[i]); | ||
| 56 | } | ||
| 57 | ✗ | return 0; | |
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | return 1; | ||
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | 8856494 | static size_t check_copy_sanity(const base_array_t* src, base_array_t* dst, size_t sze) { | |
| 66 | size_t i; | ||
| 67 | // TODO wrap me in debug. No need to do this in release. | ||
| 68 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8856494 times.
|
8856494 | omc_assert_macro(base_array_ok(src)); |
| 69 | ✗ | omc_assert_macro(generic_array_ndims_eq(src, dst)); | |
| 70 | |||
| 71 | 8856494 | size_t nr_of_elements = base_array_nr_of_elements(*src); | |
| 72 | |||
| 73 | // Check if shape is equal. | ||
| 74 | int shape_eq = generic_array_dimsizes_eq(src, dst, 0 /*do not print error yet*/); | ||
| 75 | |||
| 76 | if(shape_eq) { | ||
| 77 | return nr_of_elements; | ||
| 78 | } | ||
| 79 | |||
| 80 | // Shape not equal and destination is flexible array. | ||
| 81 | // Adjust the dim sizes and realloc the destination | ||
| 82 |
1/2✓ Branch 0 taken 3022 times.
✗ Branch 1 not taken.
|
3022 | if(dst->flexible) { |
| 83 |
2/2✓ Branch 0 taken 3022 times.
✓ Branch 1 taken 3022 times.
|
6044 | for(i = 0; i < dst->ndims; ++i) { |
| 84 | 3022 | dst->dim_size[i] = src->dim_size[i]; | |
| 85 | } | ||
| 86 | // let GC collect the old data. | ||
| 87 | 3022 | dst->data = generic_alloc(nr_of_elements, sze); | |
| 88 | |||
| 89 | 3022 | return nr_of_elements; | |
| 90 | } | ||
| 91 | |||
| 92 | // Shape not equal and destination is not flexible array. | ||
| 93 | ✗ | generic_array_dimsizes_eq(src, dst, 1 /*print error*/); // Just to print more info. | |
| 94 | ✗ | raiseStreamPrint(NULL, "Failed to copy array. Dimension sizes are not equal and destination array is not flexible."); | |
| 95 | ✗ | return 0; | |
| 96 | } | ||
| 97 | |||
| 98 | 3022 | void generic_array_create_flexible(base_array_t* dst, int ndims) | |
| 99 | { | ||
| 100 | 3022 | dst->ndims = ndims; | |
| 101 | 3022 | dst->dim_size = size_alloc(ndims); | |
| 102 | 3022 | dst->owns_data = 1; | |
| 103 | |||
| 104 | 3022 | dst->flexible = 1; | |
| 105 | |||
| 106 | size_t i; | ||
| 107 |
2/2✓ Branch 0 taken 3022 times.
✓ Branch 1 taken 3022 times.
|
6044 | for(i = 0; i < ndims; ++i) { |
| 108 | 3022 | dst->dim_size[i] = -1; | |
| 109 | } | ||
| 110 | 3022 | } | |
| 111 | |||
| 112 | 7045 | void generic_array_create(threadData_t* td, base_array_t* dst, constructor_func ctr_func, int ndims, size_t sze, ...) | |
| 113 | { | ||
| 114 | size_t i, nr_of_elements; | ||
| 115 | |||
| 116 | va_list ap; | ||
| 117 | 7045 | va_start(ap, sze); | |
| 118 | 7045 | nr_of_elements = alloc_base_array(dst, ndims, ap); | |
| 119 | 7045 | va_end(ap); | |
| 120 | 7045 | dst->data = generic_alloc(nr_of_elements, sze); | |
| 121 | |||
| 122 | // If we get here then the dst array has known dims | ||
| 123 | // Which means it is not flexible. | ||
| 124 | 7045 | dst->flexible = 0; | |
| 125 | |||
| 126 | // Initialize each element of the complex array | ||
| 127 | char* d_data = (char*)(dst->data); | ||
| 128 |
2/2✓ Branch 0 taken 28168 times.
✓ Branch 1 taken 7045 times.
|
35213 | for(i = 0; i < nr_of_elements; ++i) { |
| 129 | 28168 | ctr_func(td, d_data + (i*sze)); | |
| 130 | } | ||
| 131 | 7045 | } | |
| 132 | |||
| 133 | ✗ | void simple_array_create(threadData_t* td, base_array_t* dst, int ndims, size_t sze, ...) | |
| 134 | { | ||
| 135 | size_t i, nr_of_elements; | ||
| 136 | |||
| 137 | va_list ap; | ||
| 138 | ✗ | va_start(ap, sze); | |
| 139 | ✗ | nr_of_elements = alloc_base_array(dst, ndims, ap); | |
| 140 | ✗ | va_end(ap); | |
| 141 | ✗ | dst->data = generic_alloc(nr_of_elements, sze); | |
| 142 | |||
| 143 | // If we get here then the dst array has known dims | ||
| 144 | // Which means it is not flexible. | ||
| 145 | ✗ | dst->flexible = 0; | |
| 146 | |||
| 147 | // Init to 0. IDK if this is what Modelica expects | ||
| 148 | // I guess it is better than garbage values. | ||
| 149 | ✗ | memset(dst->data, 0, nr_of_elements*sze); | |
| 150 | ✗ | } | |
| 151 | |||
| 152 | |||
| 153 | ✗ | void generic_array_alloc_copy(const base_array_t src_cp, base_array_t* dst, copy_func cp_func, size_t sze) | |
| 154 | { | ||
| 155 | const base_array_t* src = &src_cp; | ||
| 156 | |||
| 157 | ✗ | clone_base_array_spec(src, dst); | |
| 158 | |||
| 159 | // If we get here then it means the dst array had a default value (i.e., binding to src array) | ||
| 160 | // Which means even if it was unknown size, it is not flexible anymore and is | ||
| 161 | // same shape as the src array. | ||
| 162 | ✗ | dst->flexible = 0; | |
| 163 | |||
| 164 | ✗ | size_t nr_of_elements = base_array_nr_of_elements(*dst); | |
| 165 | ✗ | dst->data = generic_alloc(nr_of_elements, sze); | |
| 166 | |||
| 167 | size_t i; | ||
| 168 | char* d_data = (char*)(dst->data); | ||
| 169 | ✗ | char* s_data = (char*)(src->data); | |
| 170 | ✗ | for(i = 0; i < nr_of_elements; ++i) { | |
| 171 | ✗ | cp_func(s_data + (i*sze), d_data + (i*sze)); | |
| 172 | } | ||
| 173 | ✗ | } | |
| 174 | |||
| 175 | 25243621 | void simple_array_alloc_copy(const base_array_t src_cp, base_array_t* dst, size_t sze) | |
| 176 | { | ||
| 177 | const base_array_t* src = &src_cp; | ||
| 178 | |||
| 179 | 25243621 | clone_base_array_spec(src, dst); | |
| 180 | |||
| 181 | // If we get here then it means the dst array had a default value (i.e., binding to src array) | ||
| 182 | // Which means even if it was unknown size, it is not flexible anymore and is | ||
| 183 | // same shape as the src array. | ||
| 184 | 25243621 | dst->flexible = 0; | |
| 185 | |||
| 186 | 25243621 | size_t nr_of_elements = base_array_nr_of_elements(*dst); | |
| 187 | 25243621 | dst->data = generic_alloc(nr_of_elements, sze); | |
| 188 | |||
| 189 | 25243621 | memcpy(dst->data, src->data, sze*nr_of_elements); | |
| 190 | 25243621 | } | |
| 191 | |||
| 192 | |||
| 193 | 2015 | void generic_array_copy_data(const base_array_t src_cp, base_array_t* dst, copy_func cp_func, size_t sze) | |
| 194 | { | ||
| 195 | const base_array_t* src = &src_cp; | ||
| 196 | |||
| 197 | 2015 | size_t nr_of_elements = check_copy_sanity(src, dst, sze); | |
| 198 | |||
| 199 | size_t i; | ||
| 200 | 2015 | char* d_data = (char*)(dst->data); | |
| 201 | 2015 | char* s_data = (char*)(src->data); | |
| 202 |
2/2✓ Branch 0 taken 5036 times.
✓ Branch 1 taken 2015 times.
|
7051 | for(i = 0; i < nr_of_elements; ++i) { |
| 203 | 5036 | cp_func(s_data + (i*sze), d_data + (i*sze)); | |
| 204 | } | ||
| 205 | 2015 | } | |
| 206 | |||
| 207 | 1039 | void simple_array_copy_to(const base_array_t src, void* dst, size_t n, size_t sze) | |
| 208 | { | ||
| 209 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1039 times.
|
1039 | if (base_array_nr_of_elements(src) != n) { |
| 210 | ✗ | raiseStreamPrint(NULL, "Failed to copy array. Dimension sizes are not equal."); | |
| 211 | ✗ | return; | |
| 212 | } | ||
| 213 | 1039 | memmove(dst, src.data, n*sze); | |
| 214 | } | ||
| 215 | |||
| 216 | 8854479 | void simple_array_copy_data(const base_array_t src_cp, base_array_t* dst, size_t sze) | |
| 217 | { | ||
| 218 | const base_array_t* src = &src_cp; | ||
| 219 | |||
| 220 | 8854479 | size_t nr_of_elements = check_copy_sanity(src, dst, sze); | |
| 221 | 8854479 | memcpy(dst->data, src->data, sze*nr_of_elements); | |
| 222 | 8854479 | } | |
| 223 | |||
| 224 | |||
| 225 | |||
| 226 | 11060 | void* generic_array_get(const base_array_t* src, size_t sze, ...) { | |
| 227 | va_list ap; | ||
| 228 | 11060 | va_start(ap,sze); | |
| 229 | // TODO assert va_list is as long as ndims. Otherwise we have slicing | ||
| 230 | 11060 | void* trgt = generic_ptrget(src, calc_base_index_va(src, src->ndims, ap), sze); | |
| 231 | 11060 | va_end(ap); | |
| 232 | 11060 | return trgt; | |
| 233 | } | ||
| 234 | |||
| 235 | ✗ | void generic_array_set(base_array_t* dst, void* val, copy_func cp_func, size_t sze, ...) { | |
| 236 | va_list ap; | ||
| 237 | ✗ | va_start(ap,sze); | |
| 238 | // TODO assert va_list is as long as ndims. Otherwise we have slicing | ||
| 239 | ✗ | void* trgt = generic_ptrget(dst, calc_base_index_va(dst, dst->ndims, ap), sze); | |
| 240 | ✗ | cp_func(val,trgt); | |
| 241 | ✗ | va_end(ap); | |
| 242 | ✗ | } | |
| 243 | |||
| 244 | |||
| 245 |