KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/types.h
Date: 2026-03-05 15:57:40
Exec Total Coverage
Lines: 188 188 100.0%
Functions: 1880 1882 99.9%
Branches: 140 140 100.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2023 - 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 #ifndef KLEIDICV_TYPES_H
6 #define KLEIDICV_TYPES_H
7
8 #include <cstring>
9 #include <memory>
10 #include <utility>
11
12 #include "kleidicv/config.h"
13 #include "kleidicv/ctypes.h"
14 #include "kleidicv/utils.h"
15
16 #if KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2
17 #include <arm_sme.h>
18 #endif
19
20 namespace KLEIDICV_TARGET_NAMESPACE {
21
22 // Represents a point on a 2D plane.
23 class Point final {
24 public:
25 3096 explicit Point(size_t x, size_t y) KLEIDICV_STREAMING : x_{x}, y_{y} {}
26
27 8968 size_t x() const KLEIDICV_STREAMING { return x_; }
28 632048 size_t y() const KLEIDICV_STREAMING { return y_; }
29
30 private:
31 size_t x_;
32 size_t y_;
33 }; // end of class Point
34
35 // Represents an area given by its width and height.
36 class Rectangle final {
37 public:
38 76522 explicit Rectangle(size_t width, size_t height) KLEIDICV_STREAMING
39 76522 : width_(width),
40 76522 height_(height) {}
41
42 8 explicit Rectangle(int width, int height) KLEIDICV_STREAMING
43 8 : Rectangle(static_cast<size_t>(width), static_cast<size_t>(height)) {}
44
45 explicit Rectangle(kleidicv_rectangle_t rect) KLEIDICV_STREAMING
46 : Rectangle(rect.width, rect.height) {}
47
48 1855042 size_t width() const KLEIDICV_STREAMING { return width_; }
49 5533726 size_t height() const KLEIDICV_STREAMING { return height_; }
50 26392 size_t area() const KLEIDICV_STREAMING { return width() * height(); }
51
52 26392 void flatten() KLEIDICV_STREAMING {
53 26392 width_ = area();
54 26392 height_ = 1;
55 26392 }
56
57 bool operator==(const Rectangle &rhs) const KLEIDICV_STREAMING {
58 return width() == rhs.width() && height() == rhs.height();
59 }
60
61 bool operator!=(const Rectangle &rhs) const KLEIDICV_STREAMING {
62 return !operator==(rhs);
63 }
64
65 private:
66 size_t width_;
67 size_t height_;
68 }; // end of class Rectangle
69
70 // Represents margins around a two dimensional area.
71 class Margin final {
72 public:
73 1336 explicit constexpr Margin(size_t left, size_t top, size_t right,
74 size_t bottom) KLEIDICV_STREAMING
75 1336 : left_(left),
76 1336 top_(top),
77 1336 right_(right),
78 1336 bottom_(bottom) {}
79
80 explicit constexpr Margin(size_t margin) KLEIDICV_STREAMING
81 : left_(margin),
82 top_(margin),
83 right_(margin),
84 bottom_(margin) {}
85
86 explicit Margin(kleidicv_rectangle_t kernel,
87 kleidicv_point_t anchor) KLEIDICV_STREAMING
88 : Margin(anchor.x, anchor.y, kernel.width - anchor.x - 1,
89 kernel.height - anchor.y - 1) {}
90
91 1336 explicit Margin(Rectangle kernel, Point anchor) KLEIDICV_STREAMING
92 2672 : Margin(anchor.x(), anchor.y(), kernel.width() - anchor.x() - 1,
93 2672 kernel.height() - anchor.y() - 1) {}
94
95 41944 size_t left() const KLEIDICV_STREAMING { return left_; }
96 23168 size_t top() const KLEIDICV_STREAMING { return top_; }
97 13720 size_t right() const KLEIDICV_STREAMING { return right_; }
98 1496 size_t bottom() const KLEIDICV_STREAMING { return bottom_; }
99
100 private:
101 size_t left_;
102 size_t top_;
103 size_t right_;
104 size_t bottom_;
105 }; // end of class Margin
106
107 // Describes the layout of one row given by a base pointer and channel count.
108 template <typename T>
109 class Columns final {
110 public:
111 1262877 explicit Columns(T *ptr, size_t channels) KLEIDICV_STREAMING
112 1262877 : ptr_{ptr},
113 1262877 channels_{channels} {}
114
115 // Subscript operator to return an arbitrary column at an index. To account
116 // for channel count use at() method.
117 3300719 T &operator[](ptrdiff_t index) const KLEIDICV_STREAMING {
118 3300719 return ptr_[index];
119 }
120
121 // Addition assignment operator to step across the columns.
122 1028918 Columns &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
123 1028918 ptr_ += static_cast<ptrdiff_t>(channels()) * diff;
124 1028918 return *this;
125 }
126
127 // Subtraction assignment operator to step across the columns.
128 6864 Columns &operator-=(ptrdiff_t diff) KLEIDICV_STREAMING {
129 6864 ptr_ -= static_cast<ptrdiff_t>(channels()) * diff;
130 6864 return *this;
131 }
132
133 // Prefix increment operator to advance to the next column.
134 Columns &operator++() KLEIDICV_STREAMING { return operator+=(1); }
135
136 // NOLINTBEGIN(hicpp-explicit-conversions)
137 // Implicit conversion operator from Columns<T> to Columns<const T>.
138 5112 [[nodiscard]] operator Columns<const T>() const KLEIDICV_STREAMING {
139 5112 return Columns<const T>{ptr_, channels()};
140 }
141 // NOLINTEND(hicpp-explicit-conversions)
142
143 // Returns a new instance at a given column.
144 520029 [[nodiscard]] Columns<T> at(ptrdiff_t column) const KLEIDICV_STREAMING {
145 1040058 return Columns<T>{&ptr_[column * static_cast<ptrdiff_t>(channels())],
146 520029 channels()};
147 }
148
149 // Returns a pointer to a given column.
150 387946 [[nodiscard]] T *ptr_at(ptrdiff_t column) const KLEIDICV_STREAMING {
151 387946 return ptr_ + column * static_cast<ptrdiff_t>(channels());
152 }
153
154 // Returns the number of channels in a row.
155 2480262 size_t channels() const KLEIDICV_STREAMING { return channels_; }
156
157 private:
158 // Pointer to the current position.
159 T *ptr_;
160 // Number of channels within a row.
161 size_t channels_;
162 }; // end of class Columns<T>
163
164 // Describes the layout of one row given by a base pointer and channel count.
165 template <typename T>
166 class ParallelColumns final {
167 public:
168 7440 explicit ParallelColumns(Columns<T> columns_0,
169 Columns<T> columns_1) KLEIDICV_STREAMING
170 7440 : columns_{columns_0, columns_1} {}
171
172 // Addition assignment operator to step across the columns.
173 288 ParallelColumns &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
174 288 columns_[0] += diff;
175 288 columns_[1] += diff;
176 288 return *this;
177 }
178
179 // Subtraction assignment operator to navigate among rows.
180 96 ParallelColumns &operator-=(ptrdiff_t diff) KLEIDICV_STREAMING {
181 96 return operator+=(-1 * diff);
182 }
183
184 // Prefix increment operator to advance to the next column.
185 ParallelColumns &operator++() KLEIDICV_STREAMING { return operator+=(1); }
186
187 // Returns the columns belonging to the first row.
188 7136 [[nodiscard]] Columns<T> first() const KLEIDICV_STREAMING {
189 7136 return columns_[0];
190 }
191
192 // Returns the columns belonging to the second row.
193 7136 [[nodiscard]] Columns<T> second() const KLEIDICV_STREAMING {
194 7136 return columns_[1];
195 }
196
197 private:
198 // The columns this instance handles.
199 Columns<T> columns_[2];
200 }; // end of class ParallelColumns<T>
201
202 // Base class of different row implementations.
203 template <typename T>
204 class RowBase {
205 public:
206 // Returns the distance in bytes between two consecutive rows.
207 131233488 size_t stride() const KLEIDICV_STREAMING { return stride_; }
208
209 // Returns the number of channels in a row.
210 133330636 size_t channels() const KLEIDICV_STREAMING { return channels_; }
211
212 // Returns true if rows are continuous for a given length, otherwise false.
213 83116 bool is_continuous(size_t length) const KLEIDICV_STREAMING {
214 83116 return stride() == (length * channels() * sizeof(T));
215 }
216
217 // When handling multiple rows this switches to a single row in an
218 // implementation defined way.
219 840 void make_single_row() const KLEIDICV_STREAMING {}
220
221 // Returns false if is_continuous() always returns false, otherwise true.
222 static constexpr bool maybe_continuous() KLEIDICV_STREAMING { return true; }
223
224 protected:
225 // TODO: default initialise members.
226 // NOLINTBEGIN(hicpp-member-init)
227 // The default constructor creates an uninitialized instance.
228 RowBase() KLEIDICV_STREAMING = default;
229 // NOLINTEND(hicpp-member-init)
230
231 65509636 RowBase(size_t stride, size_t channels) KLEIDICV_STREAMING
232 65509636 : stride_(stride),
233 65509636 channels_(channels) {}
234
235 // Adds a stride to a pointer, and returns the new pointer.
236 template <typename P>
237 65562655 [[nodiscard]] static P *add_stride(P *ptr,
238 ptrdiff_t stride) KLEIDICV_STREAMING {
239 65562655 uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
240 65562655 intptr += stride;
241 // NOLINTBEGIN(performance-no-int-to-ptr)
242 131125310 return reinterpret_cast<P *>(intptr);
243 // NOLINTEND(performance-no-int-to-ptr)
244 65562655 }
245
246 // Subtracts a stride to a pointer, and returns the new pointer.
247 template <typename P>
248 [[nodiscard]] static P *subtract_stride(P *ptr,
249 ptrdiff_t stride) KLEIDICV_STREAMING {
250 uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
251 intptr -= stride;
252 // NOLINTBEGIN(performance-no-int-to-ptr)
253 return reinterpret_cast<P *>(intptr);
254 // NOLINTEND(performance-no-int-to-ptr)
255 }
256
257 private:
258 // Distance in bytes between two consecutive rows.
259 size_t stride_;
260 // Number of channels within a row.
261 size_t channels_;
262 }; // end of class RowBase<T>
263
264 // Describes the layout of rows given by a base pointer, channel count and a
265 // stride in bytes.
266 template <typename T>
267 class Rows final : public RowBase<T> {
268 public:
269 // Shorten code: no need for 'this->'.
270 using RowBase<T>::channels;
271 using RowBase<T>::stride;
272
273 // The default constructor creates an uninitialized instance.
274 9848 Rows() KLEIDICV_STREAMING : RowBase<T>() {}
275
276 65489420 explicit Rows(T *ptr, size_t stride, size_t channels) KLEIDICV_STREAMING
277 65489420 : RowBase<T>(stride, channels),
278 65489420 ptr_{ptr} {}
279
280 58726 explicit Rows(T *ptr, size_t stride) KLEIDICV_STREAMING
281 58726 : Rows(ptr, stride, 1) {}
282
283 explicit Rows(T *ptr) KLEIDICV_STREAMING : Rows(ptr, 0, 0) {}
284
285 // Subscript operator to return an arbitrary position within the current row.
286 // To account for stride and channel count use at() method.
287 66709061 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING { return ptr_[index]; }
288
289 // Addition assignment operator to navigate among rows.
290 499242 Rows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
291 499242 ptr_ = get_pointer_at(diff);
292 499242 return *this;
293 }
294
295 // Prefix increment operator to advance to the next row.
296 488770 Rows<T> &operator++() KLEIDICV_STREAMING { return operator+=(1); }
297
298 // NOLINTBEGIN(hicpp-explicit-conversions)
299 // Returns a const variant of this instance.
300 258648 [[nodiscard]] operator Rows<const T>() KLEIDICV_STREAMING {
301 258648 return Rows<const T>{ptr_, stride(), channels()};
302 }
303 // NOLINTEND(hicpp-explicit-conversions)
304
305 // Returns a new instance at a given row and column.
306 65044613 [[nodiscard]] Rows<T> at(ptrdiff_t row,
307 ptrdiff_t column = 0) const KLEIDICV_STREAMING {
308 65044613 return Rows<T>{get_pointer_at(row, column), stride(), channels()};
309 }
310
311 // Returns a view on columns within the current row.
312 687904 [[nodiscard]] Columns<T> as_columns() const KLEIDICV_STREAMING {
313 687904 return Columns{ptr_, channels()};
314 }
315
316 // Translates a logical one-dimensional element index into physical byte
317 // offset for that element with a given row width.
318 784 [[nodiscard]] size_t offset_for_index(size_t index,
319 size_t width) const KLEIDICV_STREAMING {
320 784 size_t row = index / width;
321 784 size_t column = index % width;
322 1568 return row * stride() + column * sizeof(T);
323 784 }
324
325 private:
326 // Returns a column in a row at a given index taking stride and channels into
327 // account.
328 65543855 [[nodiscard]] T *get_pointer_at(ptrdiff_t row, ptrdiff_t column = 0) const
329 KLEIDICV_STREAMING {
330 131087710 T *ptr =
331 65543855 RowBase<T>::add_stride(ptr_, row * static_cast<ptrdiff_t>(stride()));
332 131087710 return &ptr[column * static_cast<ptrdiff_t>(channels())];
333 65543855 }
334
335 // Pointer to the first row.
336 T *ptr_;
337 }; // end of class Rows<T>
338
339 // Similar to Rows<T>, but in this case rows are indirectly addressed.
340 template <typename T>
341 class IndirectRows : public RowBase<T> {
342 public:
343 // Shorten code: no need for 'this->'.
344 using RowBase<T>::channels;
345 using RowBase<T>::stride;
346
347 // The default constructor creates an uninitialized instance.
348 IndirectRows() KLEIDICV_STREAMING : RowBase<T>() {}
349
350 14800 explicit IndirectRows(T **ptr_storage, size_t stride,
351 size_t channels) KLEIDICV_STREAMING
352 14800 : RowBase<T>(stride, channels),
353 14800 ptr_storage_(ptr_storage) {}
354
355 1496 explicit IndirectRows(T **ptr_storage, size_t depth,
356 Rows<T> rows) KLEIDICV_STREAMING
357 1496 : RowBase<T>(rows.stride(), rows.channels()),
358 1496 ptr_storage_(ptr_storage) {
359
2/2
✓ Branch 0 taken 1496 times.
✓ Branch 1 taken 95744 times.
97240 for (size_t index = 0; index < depth; ++index) {
360 95744 ptr_storage_[index] = &rows.at(index, 0)[0];
361 95744 }
362 1496 }
363
364 // Subscript operator to return a position within the current row. To account
365 // for stride and channel count use at() method.
366 27480 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING {
367 27480 return ptr_storage_[0][index];
368 }
369
370 // Addition assignment operator to navigate among rows.
371 31426 IndirectRows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
372 31426 ptr_storage_ += diff;
373 31426 return *this;
374 }
375
376 // Prefix increment operator to advance to the next row.
377 20958 IndirectRows<T> &operator++() KLEIDICV_STREAMING {
378 20958 return this->operator+=(1);
379 }
380
381 // Returns a new instance at a given row and column.
382 24864 [[nodiscard]] Rows<T> at(ptrdiff_t row,
383 ptrdiff_t column = 0) KLEIDICV_STREAMING {
384 24864 auto rows = Rows<T>{ptr_storage_[row], stride(), channels()};
385 24864 return rows.at(0, column);
386 24864 }
387
388 // Returns a view on columns within the current row.
389 152 [[nodiscard]] Columns<T> as_columns() const KLEIDICV_STREAMING {
390 152 return Columns{ptr_storage_[0], channels()};
391 }
392
393 protected:
394 // Pointer to the pointer storage.
395 T **ptr_storage_;
396 }; // end of class IndirectRows<T>
397
398 // Same as IndirectRows<T> but with double buffering. Requires 3 times the depth
399 // of pointers.
400 template <typename T>
401 class DoubleBufferedIndirectRows final : public IndirectRows<T> {
402 public:
403 // Shorten code: no need for 'this->'.
404 using IndirectRows<T>::channels;
405 using IndirectRows<T>::stride;
406
407 1496 explicit DoubleBufferedIndirectRows(T **ptr_storage, size_t depth,
408 Rows<T> rows) KLEIDICV_STREAMING
409 1496 : IndirectRows<T>(ptr_storage, 2 * depth, rows) {
410 // Fill the second half of the pointer storage.
411
2/2
✓ Branch 0 taken 1496 times.
✓ Branch 1 taken 95744 times.
97240 for (size_t index = 0; index < 2 * depth; ++index) {
412 95744 this->ptr_storage_[2 * depth + index] = this->ptr_storage_[index];
413 95744 }
414
415 1496 db_ptr_storage_[0] = &this->ptr_storage_[0];
416 1496 db_ptr_storage_[1] = &this->ptr_storage_[depth];
417 1496 }
418
419 // Swaps the double buffered indirect rows.
420 3096 void swap() KLEIDICV_STREAMING {
421 3096 std::swap(db_ptr_storage_[0], db_ptr_storage_[1]);
422 3096 }
423
424 // Returns indirect rows where write is allowed.
425 13200 [[nodiscard]] IndirectRows<T> write_at() KLEIDICV_STREAMING {
426 13200 return IndirectRows<T>{db_ptr_storage_[0], stride(), channels()};
427 }
428
429 // Returns indirect rows where read is allowed.
430 1600 [[nodiscard]] IndirectRows<T> read_at() KLEIDICV_STREAMING {
431 1600 return IndirectRows<T>{db_ptr_storage_[1], stride(), channels()};
432 }
433
434 private:
435 // The double buffer.
436 T **db_ptr_storage_[2];
437 }; // end of class DoubleBufferedIndirectRows<T>
438
439 // Describes the layout of two parallel rows.
440 template <typename T>
441 class ParallelRows final : public RowBase<T> {
442 public:
443 // Shorten code: no need for 'this->'.
444 using RowBase<T>::channels;
445 using RowBase<T>::stride;
446
447 3920 explicit ParallelRows(T *ptr, size_t stride,
448 size_t channels) KLEIDICV_STREAMING
449 3920 : RowBase<T>(2 * stride, channels),
450 3920 ptrs_{ptr, RowBase<T>::add_stride(ptr, stride)} {}
451
452 1960 explicit ParallelRows(T *ptr, size_t stride) KLEIDICV_STREAMING
453 1960 : ParallelRows(ptr, stride, 1) {}
454
455 // Addition assignment operator to navigate among rows.
456 7440 ParallelRows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
457 7440 ptrs_[0] = RowBase<T>::add_stride(ptrs_[0], diff * stride());
458 7440 ptrs_[1] = RowBase<T>::add_stride(ptrs_[1], diff * stride());
459 7440 return *this;
460 }
461
462 // Prefix increment operator to advance to the next row.
463 7440 ParallelRows<T> &operator++() KLEIDICV_STREAMING { return operator+=(1); }
464
465 // Returns views on columns within the current rows.
466 7440 [[nodiscard]] ParallelColumns<T> as_columns() const KLEIDICV_STREAMING {
467 7440 Columns columns_0{ptrs_[0], channels()};
468 7440 Columns columns_1{ptrs_[1], channels()};
469 7440 return ParallelColumns{columns_0, columns_1};
470 7440 }
471
472 // Instructs the logic to drop the second row.
473 1680 void make_single_row() KLEIDICV_STREAMING { ptrs_[1] = ptrs_[0]; }
474
475 private:
476 // Pointers to the two parallel rows.
477 T *ptrs_[2];
478 }; // end of class ParallelRows<T>
479
480 template <typename OperationType, typename... RowTypes>
481 40372 KLEIDICV_FORCE_INLINE void zip_rows(OperationType &operation, Rectangle rect,
482 RowTypes... rows) KLEIDICV_STREAMING {
483 // Unary left fold. Evaluates the expression for every part of the unexpanded
484 // parameter pack 'rows'.
485
96/96
✓ Branch 0 taken 11031 times.
✓ Branch 1 taken 5223 times.
✓ Branch 2 taken 6880 times.
✓ Branch 3 taken 4295 times.
✓ Branch 4 taken 3243 times.
✓ Branch 5 taken 3372 times.
✓ Branch 6 taken 2664 times.
✓ Branch 7 taken 3195 times.
✓ Branch 8 taken 4461 times.
✓ Branch 9 taken 688 times.
✓ Branch 10 taken 628 times.
✓ Branch 11 taken 4265 times.
✓ Branch 12 taken 3700 times.
✓ Branch 13 taken 293 times.
✓ Branch 14 taken 2088 times.
✓ Branch 15 taken 1804 times.
✓ Branch 16 taken 552 times.
✓ Branch 17 taken 1670 times.
✓ Branch 18 taken 1688 times.
✓ Branch 19 taken 584 times.
✓ Branch 20 taken 1977 times.
✓ Branch 21 taken 42 times.
✓ Branch 22 taken 16 times.
✓ Branch 23 taken 1961 times.
✓ Branch 24 taken 1696 times.
✓ Branch 25 taken 120 times.
✓ Branch 26 taken 1664 times.
✓ Branch 27 taken 32 times.
✓ Branch 28 taken 16 times.
✓ Branch 29 taken 1648 times.
✓ Branch 30 taken 1072 times.
✓ Branch 31 taken 128 times.
✓ Branch 32 taken 1024 times.
✓ Branch 33 taken 48 times.
✓ Branch 34 taken 32 times.
✓ Branch 35 taken 992 times.
✓ Branch 36 taken 1008 times.
✓ Branch 37 taken 84 times.
✓ Branch 38 taken 1088 times.
✓ Branch 39 taken 112 times.
✓ Branch 40 taken 80 times.
✓ Branch 41 taken 1008 times.
✓ Branch 42 taken 1040 times.
✓ Branch 43 taken 96 times.
✓ Branch 44 taken 1008 times.
✓ Branch 45 taken 32 times.
✓ Branch 46 taken 16 times.
✓ Branch 47 taken 992 times.
✓ Branch 48 taken 48 times.
✓ Branch 49 taken 40 times.
✓ Branch 50 taken 32 times.
✓ Branch 51 taken 16 times.
✓ Branch 52 taken 8 times.
✓ Branch 53 taken 24 times.
✓ Branch 54 taken 72 times.
✓ Branch 55 taken 64 times.
✓ Branch 56 taken 40 times.
✓ Branch 57 taken 32 times.
✓ Branch 58 taken 24 times.
✓ Branch 59 taken 16 times.
✓ Branch 60 taken 8 times.
✓ Branch 61 taken 16 times.
✓ Branch 62 taken 104 times.
✓ Branch 63 taken 96 times.
✓ Branch 64 taken 72 times.
✓ Branch 65 taken 32 times.
✓ Branch 66 taken 40 times.
✓ Branch 67 taken 32 times.
✓ Branch 68 taken 24 times.
✓ Branch 69 taken 16 times.
✓ Branch 70 taken 8 times.
✓ Branch 71 taken 16 times.
✓ Branch 72 taken 48 times.
✓ Branch 73 taken 40 times.
✓ Branch 74 taken 32 times.
✓ Branch 75 taken 16 times.
✓ Branch 76 taken 8 times.
✓ Branch 77 taken 24 times.
✓ Branch 78 taken 72 times.
✓ Branch 79 taken 64 times.
✓ Branch 80 taken 40 times.
✓ Branch 81 taken 32 times.
✓ Branch 82 taken 24 times.
✓ Branch 83 taken 16 times.
✓ Branch 84 taken 8 times.
✓ Branch 85 taken 16 times.
✓ Branch 86 taken 104 times.
✓ Branch 87 taken 96 times.
✓ Branch 88 taken 72 times.
✓ Branch 89 taken 32 times.
✓ Branch 90 taken 40 times.
✓ Branch 91 taken 32 times.
✓ Branch 92 taken 24 times.
✓ Branch 93 taken 16 times.
✓ Branch 94 taken 8 times.
✓ Branch 95 taken 16 times.
40372 if ((... && (rows.is_continuous(rect.width())))) {
486 26392 rect.flatten();
487 26392 }
488
489
24/24
✓ Branch 0 taken 23917 times.
✓ Branch 1 taken 16254 times.
✓ Branch 2 taken 9805 times.
✓ Branch 3 taken 6163 times.
✓ Branch 4 taken 7571 times.
✓ Branch 5 taken 5009 times.
✓ Branch 6 taken 6015 times.
✓ Branch 7 taken 4701 times.
✓ Branch 8 taken 4096 times.
✓ Branch 9 taken 2998 times.
✓ Branch 10 taken 2990 times.
✓ Branch 11 taken 2267 times.
✓ Branch 12 taken 1836 times.
✓ Branch 13 taken 1156 times.
✓ Branch 14 taken 1624 times.
✓ Branch 15 taken 1200 times.
✓ Branch 16 taken 384 times.
✓ Branch 17 taken 200 times.
✓ Branch 18 taken 144 times.
✓ Branch 19 taken 88 times.
✓ Branch 20 taken 256 times.
✓ Branch 21 taken 136 times.
✓ Branch 22 taken 384 times.
✓ Branch 23 taken 200 times.
99394 for (size_t row_index = 0; row_index < rect.height(); ++row_index) {
490 59022 operation.process_row(rect.width(), rows.as_columns()...);
491 // Call pre-increment operator on all elements in the parameter pack.
492 59022 ((++rows), ...);
493 59022 }
494 40372 }
495
496 template <typename OperationType, typename... RowTypes>
497 1960 KLEIDICV_FORCE_INLINE void zip_parallel_rows(OperationType &operation,
498 Rectangle rect, RowTypes... rows)
499 KLEIDICV_STREAMING {
500
8/8
✓ Branch 0 taken 490 times.
✓ Branch 1 taken 930 times.
✓ Branch 2 taken 490 times.
✓ Branch 3 taken 930 times.
✓ Branch 4 taken 490 times.
✓ Branch 5 taken 930 times.
✓ Branch 6 taken 490 times.
✓ Branch 7 taken 930 times.
5680 for (size_t row_index = 0; row_index < rect.height(); row_index += 2) {
501 // Handle the last odd row in a special way.
502
8/8
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 720 times.
✓ Branch 3 taken 210 times.
✓ Branch 4 taken 720 times.
✓ Branch 5 taken 210 times.
✓ Branch 6 taken 720 times.
✓ Branch 7 taken 210 times.
3720 if (KLEIDICV_UNLIKELY(row_index == (rect.height() - 1))) {
503 840 ((rows.make_single_row(), ...));
504 840 }
505
506 3720 operation.process_row(rect.width(), rows.as_columns()...);
507 // Call pre-increment operator on all elements in the parameter pack.
508 3720 ((++rows), ...);
509 3720 }
510 1960 }
511
512 // Copy rows with support for overlapping memory.
513 template <typename T>
514 class CopyRows final {
515 public:
516 KLEIDICV_FORCE_INLINE
517 804 void process_row(size_t length, Columns<const T> src,
518 Columns<T> dst) KLEIDICV_STREAMING {
519 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
520 __arm_sc_memmove(static_cast<void *>(&dst[0]),
521 static_cast<const void *>(&src[0]),
522 length * sizeof(T) * dst.channels());
523 #else
524 1608 std::memmove(static_cast<void *>(&dst[0]),
525 804 static_cast<const void *>(&src[0]),
526 804 length * sizeof(T) * dst.channels());
527 #endif
528 804 }
529
530 template <typename S, typename D>
531 798 static void copy_rows(Rectangle rect, S src, D dst) KLEIDICV_STREAMING {
532 798 CopyRows<T> operation;
533 798 zip_rows(operation, rect, src, dst);
534 798 }
535 }; // end of class CopyRows<T>
536
537 // Copy non-verlapping rows.
538 template <typename T>
539 class CopyNonOverlappingRows final {
540 public:
541 KLEIDICV_FORCE_INLINE
542 10560 void process_row(size_t length, Columns<const T> src,
543 Columns<T> dst) KLEIDICV_STREAMING {
544 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
545 __arm_sc_memcpy(static_cast<void *>(&dst[0]),
546 static_cast<const void *>(&src[0]),
547 length * sizeof(T) * dst.channels());
548 #else
549 21120 std::memcpy(static_cast<void *>(&dst[0]),
550 10560 static_cast<const void *>(&src[0]),
551 10560 length * sizeof(T) * dst.channels());
552 #endif
553 10560 }
554
555 1408 static void copy_rows(Rectangle rect, Rows<const T> src,
556 Rows<T> dst) KLEIDICV_STREAMING {
557 1408 CopyNonOverlappingRows<T> operation;
558 1408 zip_rows(operation, rect, src, dst);
559 1408 }
560 }; // end of class CopyNonOverlappingRows<T>
561
562 // Sets the margins to zero. It takes both channel count and element size into
563 // account. For example, margin.left() = 1 means that one pixel worth of space,
564 // that is sizeof(T) * channels, will be set to zero. The first argument, rect,
565 // describes the total available memory, including all margins.
566 template <typename T>
567 void make_zero_border_border(Rectangle rect, Rows<T> rows, Margin margin) {
568 if (margin.left()) {
569 size_t margin_width_in_bytes = margin.left() * sizeof(T) * rows.channels();
570 for (size_t index = 0; index < rect.height(); ++index) {
571 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
572 __arm_sc_memset(&rows.at(index)[0], 0, margin_width_in_bytes);
573 #else
574 std::memset(&rows.at(index)[0], 0, margin_width_in_bytes);
575 #endif
576 }
577 }
578
579 if (margin.top()) {
580 size_t top_width = rect.width() - margin.left() - margin.right();
581 size_t top_width_in_bytes = top_width * sizeof(T) * rows.channels();
582 for (size_t index = 0; index < margin.top(); ++index) {
583 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
584 __arm_sc_memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
585 #else
586 std::memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
587 #endif
588 }
589 }
590
591 if (margin.right()) {
592 size_t margin_width_in_bytes = margin.right() * sizeof(T) * rows.channels();
593 for (size_t index = 0; index < rect.height(); ++index) {
594 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
595 __arm_sc_memset(&rows.at(index, rect.width() - margin.right())[0], 0,
596 margin_width_in_bytes);
597 #else
598 std::memset(&rows.at(index, rect.width() - margin.right())[0], 0,
599 margin_width_in_bytes);
600 #endif
601 }
602 }
603
604 if (margin.bottom()) {
605 size_t bottom_width = rect.width() - margin.left() - margin.right();
606 size_t bottom_width_in_bytes = bottom_width * sizeof(T) * rows.channels();
607 for (size_t index = rect.height() - margin.bottom(); index < rect.height();
608 ++index) {
609 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
610 __arm_sc_memset(&rows.at(index, margin.left())[0], 0,
611 bottom_width_in_bytes);
612 #else
613 std::memset(&rows.at(index, margin.left())[0], 0, bottom_width_in_bytes);
614 #endif
615 }
616 }
617 }
618
619 // Struct for providing Rows object over memory managed by std::unique_ptr.
620 template <typename T>
621 class RowsOverUniquePtr {
622 public:
623 // Returns a rectangle which describes the layout of the allocated memory.
624 Rectangle rect() const { return rect_; }
625
626 // Returns a raw pointer to the allocated memory.
627 T *data() const { return data_.get(); }
628
629 // Returns a Rows instance over the allocated memory.
630 Rows<T> rows() const { return rows_; }
631
632 // Like rows() but without margins.
633 Rows<T> rows_without_margin() const { return rows_without_margin_; }
634
635 protected:
636 RowsOverUniquePtr(Rectangle rect, Margin margin)
637 : rect_{get_rectangle(rect, margin)},
638 data_{std::unique_ptr<T[]>(new(std::nothrow) T[rect_.area()])} {
639 if (!data_) {
640 // Code that uses this class is required to check that data() is valid.
641 return;
642 }
643
644 rows_ = Rows<T>{&data_[0], rect_.width() * sizeof(T)};
645 rows_without_margin_ = rows_.at(margin.top(), margin.left());
646 make_zero_border_border<T>(rect_, rows_, margin);
647 }
648
649 private:
650 static Rectangle get_rectangle(Rectangle rect, Margin margin) {
651 return Rectangle{margin.left() + rect.width() + margin.right(),
652 margin.top() + rect.height() + margin.bottom()};
653 }
654
655 Rectangle rect_;
656 Rows<T> rows_;
657 Rows<T> rows_without_margin_;
658 std::unique_ptr<T[]> data_;
659 };
660
661 } // namespace KLEIDICV_TARGET_NAMESPACE
662
663 #endif // KLEIDICV_TYPES_H
664