Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 551
Functions: 0.0% 0 / 1 / 109
Branches: 0.0% 0 / 0 / 862

OMCompiler/SimulationRuntime/cpp/Core/Math/ArraySlice.h
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 #pragma once
29
30 /* Implement Modelica array slices. */
31
32 #include "Array.h"
33 /** @addtogroup math
34 * @{
35 */
36
37 /**
38 * Modelica slice.
39 * Defined by an index vector iset != NULL or by start:stop or start:step:stop,
40 * start == stop and step == 0 meaning reduction of dimension,
41 * is_stop_end marking stop == end.
42 */
43 class Slice {
44 public:
45 // all indices
46 ✗ Slice() {
47 ✗ start = 1;
48 ✗ step = 1;
49 ✗ stop = 0;
50 ✗ is_stop_end = true;
51 ✗ iset = NULL;
52 }
53
54 // one index (reduction)
55 Slice(int index) {
56 start = index;
57 step = 0;
58 stop = index;
59 is_stop_end = false;
60 iset = NULL;
61 }
62
63 Slice(int start, int stop) {
64 this->start = start;
65 step = 1;
66 this->stop = stop;
67 is_stop_end = false;
68 iset = NULL;
69 }
70
71 Slice(int start, int step, int stop) {
72 this->start = start;
73 this->step = step;
74 this->stop = stop;
75 is_stop_end = false;
76 iset = NULL;
77 }
78
79 // index set
80 Slice(const BaseArray<int> &indices) {
81 start = 0;
82 step = 0;
83 stop = 0;
84 is_stop_end = false;
85 if (indices.getNumDims() != 1)
86 throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
87 "Slice requires an index vector");
88 // store pointer as indices should live long enough in a Modelica model
89 iset = &indices;
90 }
91
92 int start;
93 int step;
94 int stop;
95 bool is_stop_end;
96 const BaseArray<int> *iset;
97 };
98
99 /**
100 * Multi-dimensional array slice holding a const reference to a BaseArray.
101 */
102 template<class T>
103 class ArraySliceConst: public BaseArray<T> {
104 public:
105 ✗ ArraySliceConst(const BaseArray<T> &baseArray, const vector<Slice> &slice)
106 : BaseArray<T>(baseArray.isStatic(), false)
107 ✗ , _baseArray(baseArray)
108 ✗ , _isets(baseArray.getNumDims())
109 ✗ , _idxs(baseArray.getNumDims())
110 ✗ , _baseReduction(baseArray.getNumDims())
111 ✗ , _baseIdx(baseArray.getNumDims())
112 ✗ , _tmp_data(NULL) {
113
114 ✗ if (baseArray.getNumDims() < slice.size())
115 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
116 "Wrong slices exceeding array dimensions");
117 // create an explicit index set per dimension,
118 // except for all indices that are indicated with an empty index set
119 size_t dim, size;
120 vector<Slice>::const_iterator sit;
121 vector< vector<size_t> >::iterator dit = _idxs.begin();
122 ✗ for (dim = 1, sit = slice.begin(); sit != slice.end(); dim++, sit++) {
123 ✗ if (sit->iset != NULL) {
124 ✗ _isets[dim - 1] = sit->iset;
125 ✗ size = sit->iset->getNumElems();
126 }
127 else {
128 ✗ _isets[dim - 1] = NULL;
129 ✗ int maxIndex = baseArray.getDim(dim);
130 ✗ int start = sit->start;
131 ✗ int step = sit->step;
132 ✗ int stop = sit->is_stop_end? maxIndex: sit->stop;
133 ✗ size = step == 0? 1: std::max(0, (stop - start) / step + 1);
134 ✗ if (size > 0 && (start > maxIndex || stop > maxIndex))
135 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
136 "Wrong slice exceeding array size");
137 ✗ if (start != 1 || step != 1 || stop != maxIndex) {
138 // only fill non-trivial _idxs if this is not WHOLEDIM
139 ✗ for (int i = 0; i < size; i++)
140 ✗ dit->push_back(start + i * step);
141 }
142 }
143 ✗ if (sit->iset == NULL && size == 1 && sit->step == 0) {
144 ✗ _baseReduction[dim - 1] = true;
145 // preset constant _baseIdx in case of reduction
146 ✗ _baseIdx[dim - 1] = sit->iset != NULL? (*_isets[dim - 1])(1): (*dit)[0];
147 }
148 else {
149 ✗ _baseReduction[dim - 1] = false;
150 ✗ if (size == 0)
151 ✗ _baseIdx[dim - 1] = 0; // mark empty dimension to distinguish it from WHOLEDIM
152 else
153 ✗ _baseIdx[dim - 1] = 1; // mark regular case with a positive value
154 // store dimension of array slice
155 ✗ _dims.push_back(size);
156 }
157 dit++;
158 }
159 // use all indices of remaining dims
160 ✗ for (; dim <= baseArray.getNumDims(); dim++) {
161 ✗ _isets[dim - 1] = NULL;
162 _baseReduction[dim - 1] = false;
163 ✗ _baseIdx[dim - 1] = 1; // mark regular case with positive value
164 ✗ _dims.push_back(_baseArray.getDim(dim));
165 }
166 ✗ }
167
168 ✗ virtual ~ArraySliceConst() {
169 ✗ if (_tmp_data != NULL)
170 ✗ delete [] _tmp_data;
171 ✗ }
172
173 ✗ virtual const T& operator()(const vector<size_t> &idx) const {
174 ✗ return _baseArray(baseIdx(idx.size(), &idx[0]));
175 }
176
177 ✗ virtual T& operator()(const vector<size_t> &idx) {
178 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
179 "Can't write to ArraySliceConst");
180 }
181
182 ✗ virtual void assign(const T* data) {
183 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
184 "Can't assign data to ArraySliceConst");
185 }
186
187 ✗ virtual void assign(const BaseArray<T>& otherArray) {
188 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
189 "Can't assign array to ArraySliceConst");
190 }
191
192 ✗ virtual void assign(const T& value) {
193 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
194 "Can't assign value to ArraySliceConst");
195 }
196
197 ✗ virtual std::vector<size_t> getDims() const {
198 ✗ return _dims;
199 }
200
201 ✗ virtual int getDim(size_t sliceDim) const {
202 ✗ return (int)_dims[sliceDim - 1];
203 }
204
205 ✗ virtual T* getData() {
206 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
207 "Can't get pointer to write to ArraySlice");
208 }
209
210 ✗ virtual void getDataCopy(T data[], size_t n) const {
211 ✗ if (n != getNumElems())
212 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
213 "Wrong number of elements in getDataCopy");
214 ✗ if (n > 0) {
215 ✗ const T* base_data = _baseArray.getData();
216 ✗ if (base_data <= data && data < base_data + n) {
217 // in-situ access requires an internal copy to avoid side effects,
218 // e.g. v = v[n:-1:1]
219 ✗ const T* slice_data = getData();
220 std::copy(slice_data, slice_data + n, data);
221 }
222 else
223 // direct access
224 ✗ getDataDim(_idxs.size(), data);
225 }
226 ✗ }
227
228 ✗ virtual const T* getData() const {
229 ✗ if (_tmp_data == NULL)
230 // allocate on first use
231 ✗ _tmp_data = new T [getNumElems()];
232 ✗ getDataDim(_idxs.size(), _tmp_data);
233 ✗ return _tmp_data;
234 }
235
236 ✗ virtual size_t getNumElems() const {
237 return std::accumulate(_dims.begin(), _dims.end(),
238 ✗ 1, std::multiplies<size_t>());
239 }
240
241 ✗ virtual size_t getNumDims() const {
242 ✗ return _dims.size();
243 }
244
245 ✗ virtual void setDims(const std::vector<size_t> &v) {
246 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
247 "Can't set dims of ArraySlice");
248 }
249
250 ✗ virtual void resize(const std::vector<size_t> &dims) {
251 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
252 "Can't resize ArraySlice");
253 }
254
255 ✗ virtual const T& operator()(size_t i) const {
256 ✗ return _baseArray(baseIdx(1, &i));
257 }
258
259 ✗ virtual const T& operator()(size_t i, size_t j) const {
260 ✗ size_t idx[] = {i, j};
261 ✗ return _baseArray(baseIdx(2, idx));
262 }
263
264 ✗ virtual const T& operator()(size_t i, size_t j, size_t k) const {
265 ✗ size_t idx[] = {i, j, k};
266 ✗ return _baseArray(baseIdx(3, idx));
267 }
268
269 ✗ virtual const T& operator()(size_t i, size_t j, size_t k, size_t l) const {
270 ✗ size_t idx[] = {i, j, k, l};
271 ✗ return _baseArray(baseIdx(4, idx));
272 }
273
274 ✗ virtual const T& operator()(size_t i, size_t j, size_t k, size_t l, size_t m) const {
275 ✗ size_t idx[] = {i, j, k, l, m};
276 ✗ return _baseArray(baseIdx(5, idx));
277 }
278
279 ✗ virtual const T& operator()(size_t i, size_t j, size_t k, size_t l, size_t m, size_t n) const {
280 ✗ size_t idx[] = {i, j, k, l, m, n};
281 ✗ return _baseArray(baseIdx(6, idx));
282 }
283
284 protected:
285 const BaseArray<T> &_baseArray; // underlying array
286 vector<const BaseArray<int>*> _isets; // given index sets per dimension
287 vector< vector<size_t> > _idxs; // created index sets per dimension
288 vector<size_t> _dims; // dimensions of array slice
289 vector<bool> _baseReduction; // mark reduced dimensions to distinguish them from size == 1
290 mutable vector<size_t> _baseIdx; // idx into underlying array
291 mutable T *_tmp_data; // storage for const T* getData()
292
293 /**
294 * returns idx vector to access an element
295 */
296 ✗ const vector<size_t> &baseIdx(size_t ndims, const size_t idx[]) const {
297 ✗ if (ndims != _dims.size())
298 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
299 "Wrong dimensions accessing ArraySlice");
300 size_t dim, size;
301 const BaseArray<int> *iset;
302 vector< vector<size_t> >::const_iterator dit;
303 ✗ for (dim = 1, dit = _idxs.begin(); dit != _idxs.end(); dim++, dit++) {
304 ✗ if (_baseReduction[dim - 1])
305 // preset base index in case of reduction
306 ✗ continue;
307 ✗ iset = _isets[dim - 1];
308 ✗ size = iset? iset->getNumElems(): dit->size();
309 ✗ switch (size) {
310 ✗ case 0:
311 ✗ if (_baseIdx[dim - 1] > 0)
312 // all indices
313 ✗ _baseIdx[dim - 1] = *idx++;
314 else
315 ✗ throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION,
316 "Access to empty ArraySlice");
317 ✗ break;
318 ✗ default:
319 // regular index mapping
320 ✗ _baseIdx[dim - 1] = iset? (*iset)(*idx++): (*dit)[*idx++ - 1];
321 }
322 }
323 ✗ return _baseIdx;
324 }
325
326 /**
327 * recursive method for reading raw data
328 */
329 ✗ size_t getDataDim(size_t dim, T* data) const {
330 size_t processed = 0;
331 ✗ const BaseArray<int> *iset = _isets[dim - 1];
332 ✗ size_t size = iset? iset->getNumElems(): _idxs[dim - 1].size();
333 ✗ if (size == 0 && _baseIdx[dim - 1] > 0)
334 ✗ size = _baseArray.getDim(dim);
335 ✗ for (size_t i = 1; i <= size; i++) {
336 ✗ if (iset)
337 ✗ _baseIdx[dim - 1] = iset->getNumElems() > 0? (*iset)(i): i;
338 else
339 ✗ _baseIdx[dim - 1] = _idxs[dim - 1].size() > 0? _idxs[dim - 1][i - 1]: i;
340 ✗ if (dim > 1)
341 ✗ processed += getDataDim(dim - 1, data + processed);
342 else
343 ✗ data[processed++] = _baseArray(_baseIdx);
344 }
345 ✗ return processed;
346 }
347 };
348
349 /**
350 * Multi-dimensional array slice extending ArraySliceConst with write access
351 */
352 template<class T>
353 ✗ class ArraySlice: public ArraySliceConst<T> {
354 public:
355 ✗ ArraySlice(BaseArray<T> &baseArray, const vector<Slice> &slice)
356 : ArraySliceConst<T>(baseArray, slice)
357 ✗ , _baseArray(baseArray)
358 ✗ , _idxs(ArraySliceConst<T>::_idxs)
359 ✗ , _baseIdx(ArraySliceConst<T>::_baseIdx) {
360 }
361
362 ArraySlice<T>& operator=(const ArraySlice<T>& b)
363 {
364 this->assign(b);
365 return *this;
366 }
367
368 ArraySlice<T>& operator=(const BaseArray<T>& b)
369 {
370 this->assign(b);
371 return *this;
372 }
373
374 ✗ virtual T& operator()(const vector<size_t> &idx) {
375 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(idx.size(), &idx[0]));
376 }
377
378 ✗ virtual void assign(const T* data) {
379 ✗ setDataDim(_idxs.size(), data);
380 ✗ }
381
382 ✗ virtual void assign(const BaseArray<T>& otherArray) {
383 ✗ setDataDim(_idxs.size(), otherArray.getData());
384 ✗ }
385
386 ✗ virtual void assign(const T& value) {
387 ✗ setEachDim(_idxs.size(), value);
388 ✗ }
389
390 ✗ virtual T& operator()(size_t i) {
391 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(1, &i));
392 }
393
394 ✗ virtual T& operator()(size_t i, size_t j) {
395 ✗ size_t idx[] = {i, j};
396 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(2, idx));
397 }
398
399 ✗ virtual T& operator()(size_t i, size_t j, size_t k) {
400 ✗ size_t idx[] = {i, j, k};
401 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(3, idx));
402 }
403
404 ✗ virtual T& operator()(size_t i, size_t j, size_t k, size_t l) {
405 ✗ size_t idx[] = {i, j, k, l};
406 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(4, idx));
407 }
408
409 ✗ virtual T& operator()(size_t i, size_t j, size_t k, size_t l, size_t m) {
410 ✗ size_t idx[] = {i, j, k, l, m};
411 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(5, idx));
412 }
413
414 ✗ virtual T& operator()(size_t i, size_t j, size_t k, size_t l, size_t m, size_t n) {
415 ✗ size_t idx[] = {i, j, k, l, m, n};
416 ✗ return _baseArray(ArraySliceConst<T>::baseIdx(6, idx));
417 }
418
419 protected:
420 BaseArray<T> &_baseArray; // underlying array
421 vector< vector<size_t> > &_idxs; // reference to index set of ArraySliceConst
422 vector<size_t> &_baseIdx; // reference to idx into underlying array
423
424 /**
425 * recursive method for muli-dimensional assignment of raw data
426 */
427 ✗ size_t setDataDim(size_t dim, const T* data) {
428 size_t processed = 0;
429 ✗ const BaseArray<int> *iset = ArraySliceConst<T>::_isets[dim - 1];
430 ✗ size_t size = iset? iset->getNumElems(): _idxs[dim - 1].size();
431 ✗ if (size == 0 && _baseIdx[dim - 1] > 0)
432 ✗ size = _baseArray.getDim(dim);
433 ✗ for (size_t i = 1; i <= size; i++) {
434 ✗ if (iset)
435 ✗ _baseIdx[dim - 1] = iset->getNumElems() > 0? (*iset)(i): i;
436 else
437 ✗ _baseIdx[dim - 1] = _idxs[dim - 1].size() > 0? _idxs[dim - 1][i - 1]: i;
438 ✗ if (dim > 1)
439 ✗ processed += setDataDim(dim - 1, data + processed);
440 else
441 ✗ _baseArray(_baseIdx) = data[processed++];
442 }
443 ✗ return processed;
444 }
445
446 /**
447 * recursive method for muli-dimensional fill of each element
448 */
449 ✗ void setEachDim(size_t dim, const T& value) {
450 ✗ const BaseArray<int> *iset = ArraySliceConst<T>::_isets[dim - 1];
451 ✗ size_t size = iset? iset->getNumElems(): _idxs[dim - 1].size();
452 ✗ if (size == 0 && _baseIdx[dim - 1] > 0)
453 ✗ size = _baseArray.getDim(dim);
454 ✗ for (size_t i = 1; i <= size; i++) {
455 ✗ if (iset)
456 ✗ _baseIdx[dim - 1] = iset->getNumElems() > 0? (*iset)(i): i;
457 else
458 ✗ _baseIdx[dim - 1] = _idxs[dim - 1].size() > 0? _idxs[dim - 1][i - 1]: i;
459 ✗ if (dim > 1)
460 ✗ setEachDim(dim - 1, value);
461 else
462 ✗ _baseArray(_baseIdx) = value;
463 }
464 ✗ }
465 };
466 /** @} */ // end of math
467