KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/types.h
Date: 2025-11-25 17:23:32
Exec Total Coverage
Lines: 191 191 100.0%
Functions: 1878 1880 99.9%
Branches: 142 142 100.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2023 - 2025 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 1440 explicit Point(size_t x, size_t y) KLEIDICV_STREAMING : x_{x}, y_{y} {}
26
27 4160 size_t x() const KLEIDICV_STREAMING { return x_; }
28 595204 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 72726 explicit Rectangle(size_t width, size_t height) KLEIDICV_STREAMING
39 72726 : width_(width),
40 72726 height_(height) {}
41
42 explicit Rectangle(int width, int height) KLEIDICV_STREAMING
43 : Rectangle(static_cast<size_t>(width), static_cast<size_t>(height)) {}
44
45 2680 explicit Rectangle(kleidicv_rectangle_t rect) KLEIDICV_STREAMING
46 2680 : Rectangle(rect.width, rect.height) {}
47
48 1787926 size_t width() const KLEIDICV_STREAMING { return width_; }
49 5486494 size_t height() const KLEIDICV_STREAMING { return height_; }
50 20972 size_t area() const KLEIDICV_STREAMING { return width() * height(); }
51
52 20972 void flatten() KLEIDICV_STREAMING {
53 20972 width_ = area();
54 20972 height_ = 1;
55 20972 }
56
57 1376 bool operator==(const Rectangle &rhs) const KLEIDICV_STREAMING {
58
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1360 times.
1376 return width() == rhs.width() && height() == rhs.height();
59 }
60
61 1376 bool operator!=(const Rectangle &rhs) const KLEIDICV_STREAMING {
62 1376 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 2632 explicit constexpr Margin(size_t left, size_t top, size_t right,
74 size_t bottom) KLEIDICV_STREAMING
75 2632 : left_(left),
76 2632 top_(top),
77 2632 right_(right),
78 2632 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 2632 explicit Margin(kleidicv_rectangle_t kernel,
87 kleidicv_point_t anchor) KLEIDICV_STREAMING
88 5264 : Margin(anchor.x, anchor.y, kernel.width - anchor.x - 1,
89 5264 kernel.height - anchor.y - 1) {}
90
91 explicit Margin(Rectangle kernel, Point anchor) KLEIDICV_STREAMING
92 : Margin(anchor.x(), anchor.y(), kernel.width() - anchor.x() - 1,
93 kernel.height() - anchor.y() - 1) {}
94
95 41888 size_t left() const KLEIDICV_STREAMING { return left_; }
96 23144 size_t top() const KLEIDICV_STREAMING { return top_; }
97 13696 size_t right() const KLEIDICV_STREAMING { return right_; }
98 1488 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 919364 explicit Columns(T *ptr, size_t channels) KLEIDICV_STREAMING
112 919364 : ptr_{ptr},
113 919364 channels_{channels} {}
114
115 // Subscript operator to return an arbitrary column at an index. To account
116 // for channel count use at() method.
117 3259661 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING { return ptr_[index]; }
118
119 // Addition assignment operator to step across the columns.
120 1031530 Columns &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
121 1031530 ptr_ += static_cast<ptrdiff_t>(channels()) * diff;
122 1031530 return *this;
123 }
124
125 // Subtraction assignment operator to step across the columns.
126 5567 Columns &operator-=(ptrdiff_t diff) KLEIDICV_STREAMING {
127 5567 ptr_ -= static_cast<ptrdiff_t>(channels()) * diff;
128 5567 return *this;
129 }
130
131 // Prefix increment operator to advance to the next column.
132 Columns &operator++() KLEIDICV_STREAMING { return operator+=(1); }
133
134 // NOLINTBEGIN(hicpp-explicit-conversions)
135 // Implicit conversion operator from Columns<T> to Columns<const T>.
136 5104 [[nodiscard]] operator Columns<const T>() const KLEIDICV_STREAMING {
137 5104 return Columns<const T>{ptr_, channels()};
138 }
139 // NOLINTEND(hicpp-explicit-conversions)
140
141 // Returns a new instance at a given column.
142 481308 [[nodiscard]] Columns<T> at(ptrdiff_t column) KLEIDICV_STREAMING {
143 962616 return Columns<T>{&ptr_[column * static_cast<ptrdiff_t>(channels())],
144 481308 channels()};
145 }
146
147 // Returns a pointer to a given column.
148 91856 [[nodiscard]] T *ptr_at(ptrdiff_t column) KLEIDICV_STREAMING {
149 91856 return ptr_ + column * static_cast<ptrdiff_t>(channels());
150 }
151
152 // Returns the number of channels in a row.
153 2107885 size_t channels() const KLEIDICV_STREAMING { return channels_; }
154
155 private:
156 // Pointer to the current position.
157 T *ptr_;
158 // Number of channels within a row.
159 size_t channels_;
160 }; // end of class Columns<T>
161
162 // Describes the layout of one row given by a base pointer and channel count.
163 template <typename T>
164 class ParallelColumns final {
165 public:
166 7440 explicit ParallelColumns(Columns<T> columns_0,
167 Columns<T> columns_1) KLEIDICV_STREAMING
168 7440 : columns_{columns_0, columns_1} {}
169
170 // Addition assignment operator to step across the columns.
171 288 ParallelColumns &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
172 288 columns_[0] += diff;
173 288 columns_[1] += diff;
174 288 return *this;
175 }
176
177 // Subtraction assignment operator to navigate among rows.
178 96 ParallelColumns &operator-=(ptrdiff_t diff) KLEIDICV_STREAMING {
179 96 return operator+=(-1 * diff);
180 }
181
182 // Prefix increment operator to advance to the next column.
183 ParallelColumns &operator++() KLEIDICV_STREAMING { return operator+=(1); }
184
185 // Returns the columns belonging to the first row.
186 7136 [[nodiscard]] Columns<T> first() const KLEIDICV_STREAMING {
187 7136 return columns_[0];
188 }
189
190 // Returns the columns belonging to the second row.
191 7136 [[nodiscard]] Columns<T> second() const KLEIDICV_STREAMING {
192 7136 return columns_[1];
193 }
194
195 private:
196 // The columns this instance handles.
197 Columns<T> columns_[2];
198 }; // end of class ParallelColumns<T>
199
200 // Base class of different row implementations.
201 template <typename T>
202 class RowBase {
203 public:
204 // Returns the distance in bytes between two consecutive rows.
205 127752160 size_t stride() const KLEIDICV_STREAMING { return stride_; }
206
207 // Returns the number of channels in a row.
208 129418133 size_t channels() const KLEIDICV_STREAMING { return channels_; }
209
210 // Returns true if rows are continuous for a given length, otherwise false.
211 69848 bool is_continuous(size_t length) const KLEIDICV_STREAMING {
212 69848 return stride() == (length * channels() * sizeof(T));
213 }
214
215 // When handling multiple rows this switches to a single row in an
216 // implementation defined way.
217 840 void make_single_row() const KLEIDICV_STREAMING {}
218
219 // Returns false if is_continuous() always returns false, otherwise true.
220 static constexpr bool maybe_continuous() KLEIDICV_STREAMING { return true; }
221
222 protected:
223 // TODO: default initialise members.
224 // NOLINTBEGIN(hicpp-member-init)
225 // The default constructor creates an uninitialized instance.
226 RowBase() KLEIDICV_STREAMING = default;
227 // NOLINTEND(hicpp-member-init)
228
229 63795065 RowBase(size_t stride, size_t channels) KLEIDICV_STREAMING
230 63795065 : stride_(stride),
231 63795065 channels_(channels) {}
232
233 // Adds a stride to a pointer, and returns the new pointer.
234 template <typename P>
235 63781819 [[nodiscard]] static P *add_stride(P *ptr,
236 ptrdiff_t stride) KLEIDICV_STREAMING {
237 63781819 uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
238 63781819 intptr += stride;
239 // NOLINTBEGIN(performance-no-int-to-ptr)
240 127563638 return reinterpret_cast<P *>(intptr);
241 // NOLINTEND(performance-no-int-to-ptr)
242 63781819 }
243
244 // Subtracts a stride to a pointer, and returns the new pointer.
245 template <typename P>
246 [[nodiscard]] static P *subtract_stride(P *ptr,
247 ptrdiff_t stride) KLEIDICV_STREAMING {
248 uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
249 intptr -= stride;
250 // NOLINTBEGIN(performance-no-int-to-ptr)
251 return reinterpret_cast<P *>(intptr);
252 // NOLINTEND(performance-no-int-to-ptr)
253 }
254
255 private:
256 // Distance in bytes between two consecutive rows.
257 size_t stride_;
258 // Number of channels within a row.
259 size_t channels_;
260 }; // end of class RowBase<T>
261
262 // Describes the layout of rows given by a base pointer, channel count and a
263 // stride in bytes.
264 template <typename T>
265 class Rows final : public RowBase<T> {
266 public:
267 // Shorten code: no need for 'this->'.
268 using RowBase<T>::channels;
269 using RowBase<T>::stride;
270
271 // The default constructor creates an uninitialized instance.
272 9840 Rows() KLEIDICV_STREAMING : RowBase<T>() {}
273
274 63775753 explicit Rows(T *ptr, size_t stride, size_t channels) KLEIDICV_STREAMING
275 63775753 : RowBase<T>(stride, channels),
276 63775753 ptr_{ptr} {}
277
278 48886 explicit Rows(T *ptr, size_t stride) KLEIDICV_STREAMING
279 48886 : Rows(ptr, stride, 1) {}
280
281 explicit Rows(T *ptr) KLEIDICV_STREAMING : Rows(ptr, 0, 0) {}
282
283 // Subscript operator to return an arbitrary position within the current row.
284 // To account for stride and channel count use at() method.
285 64544676 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING { return ptr_[index]; }
286
287 // Addition assignment operator to navigate among rows.
288 370170 Rows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
289 370170 ptr_ = get_pointer_at(diff);
290 370170 return *this;
291 }
292
293 // Prefix increment operator to advance to the next row.
294 360202 Rows<T> &operator++() KLEIDICV_STREAMING { return operator+=(1); }
295
296 // NOLINTBEGIN(hicpp-explicit-conversions)
297 // Returns a const variant of this instance.
298 225416 [[nodiscard]] operator Rows<const T>() KLEIDICV_STREAMING {
299 225416 return Rows<const T>{ptr_, stride(), channels()};
300 }
301 // NOLINTEND(hicpp-explicit-conversions)
302
303 // Returns a new instance at a given row and column.
304 63393729 [[nodiscard]] Rows<T> at(ptrdiff_t row,
305 ptrdiff_t column = 0) KLEIDICV_STREAMING {
306 63393729 return Rows<T>{get_pointer_at(row, column), stride(), channels()};
307 }
308
309 // Returns a view on columns within the current row.
310 417928 [[nodiscard]] Columns<T> as_columns() const KLEIDICV_STREAMING {
311 417928 return Columns{ptr_, channels()};
312 }
313
314 // Translates a logical one-dimensional element index into physical byte
315 // offset for that element with a given row width.
316 688 [[nodiscard]] size_t offset_for_index(size_t index,
317 size_t width) const KLEIDICV_STREAMING {
318 688 size_t row = index / width;
319 688 size_t column = index % width;
320 1376 return row * stride() + column * sizeof(T);
321 688 }
322
323 private:
324 // Returns a column in a row at a given index taking stride and channels into
325 // account.
326 63763899 [[nodiscard]] T *get_pointer_at(ptrdiff_t row,
327 ptrdiff_t column = 0) KLEIDICV_STREAMING {
328 127527798 T *ptr =
329 63763899 RowBase<T>::add_stride(ptr_, row * static_cast<ptrdiff_t>(stride()));
330 127527798 return &ptr[column * static_cast<ptrdiff_t>(channels())];
331 63763899 }
332
333 // Pointer to the first row.
334 T *ptr_;
335 }; // end of class Rows<T>
336
337 // Similar to Rows<T>, but in this case rows are indirectly addressed.
338 template <typename T>
339 class IndirectRows : public RowBase<T> {
340 public:
341 // Shorten code: no need for 'this->'.
342 using RowBase<T>::channels;
343 using RowBase<T>::stride;
344
345 // The default constructor creates an uninitialized instance.
346 IndirectRows() KLEIDICV_STREAMING : RowBase<T>() {}
347
348 14784 explicit IndirectRows(T **ptr_storage, size_t stride,
349 size_t channels) KLEIDICV_STREAMING
350 14784 : RowBase<T>(stride, channels),
351 14784 ptr_storage_(ptr_storage) {}
352
353 1488 explicit IndirectRows(T **ptr_storage, size_t depth,
354 Rows<T> rows) KLEIDICV_STREAMING
355 1488 : RowBase<T>(rows.stride(), rows.channels()),
356 1488 ptr_storage_(ptr_storage) {
357
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 95232 times.
96720 for (size_t index = 0; index < depth; ++index) {
358 95232 ptr_storage_[index] = &rows.at(index, 0)[0];
359 95232 }
360 1488 }
361
362 // Subscript operator to return a position within the current row. To account
363 // for stride and channel count use at() method.
364 27480 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING {
365 27480 return ptr_storage_[0][index];
366 }
367
368 // Addition assignment operator to navigate among rows.
369 31418 IndirectRows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
370 31418 ptr_storage_ += diff;
371 31418 return *this;
372 }
373
374 // Prefix increment operator to advance to the next row.
375 20950 IndirectRows<T> &operator++() KLEIDICV_STREAMING {
376 20950 return this->operator+=(1);
377 }
378
379 // Returns a new instance at a given row and column.
380 24856 [[nodiscard]] Rows<T> at(ptrdiff_t row,
381 ptrdiff_t column = 0) KLEIDICV_STREAMING {
382 24856 auto rows = Rows<T>{ptr_storage_[row], stride(), channels()};
383 24856 return rows.at(0, column);
384 24856 }
385
386 // Returns a view on columns within the current row.
387 144 [[nodiscard]] Columns<T> as_columns() const KLEIDICV_STREAMING {
388 144 return Columns{ptr_storage_[0], channels()};
389 }
390
391 protected:
392 // Pointer to the pointer storage.
393 T **ptr_storage_;
394 }; // end of class IndirectRows<T>
395
396 // Same as IndirectRows<T> but with double buffering. Requires 3 times the depth
397 // of pointers.
398 template <typename T>
399 class DoubleBufferedIndirectRows final : public IndirectRows<T> {
400 public:
401 // Shorten code: no need for 'this->'.
402 using IndirectRows<T>::channels;
403 using IndirectRows<T>::stride;
404
405 1488 explicit DoubleBufferedIndirectRows(T **ptr_storage, size_t depth,
406 Rows<T> rows) KLEIDICV_STREAMING
407 1488 : IndirectRows<T>(ptr_storage, 2 * depth, rows) {
408 // Fill the second half of the pointer storage.
409
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 95232 times.
96720 for (size_t index = 0; index < 2 * depth; ++index) {
410 95232 this->ptr_storage_[2 * depth + index] = this->ptr_storage_[index];
411 95232 }
412
413 1488 db_ptr_storage_[0] = &this->ptr_storage_[0];
414 1488 db_ptr_storage_[1] = &this->ptr_storage_[depth];
415 1488 }
416
417 // Swaps the double buffered indirect rows.
418 3080 void swap() KLEIDICV_STREAMING {
419 3080 std::swap(db_ptr_storage_[0], db_ptr_storage_[1]);
420 3080 }
421
422 // Returns indirect rows where write is allowed.
423 13192 [[nodiscard]] IndirectRows<T> write_at() KLEIDICV_STREAMING {
424 13192 return IndirectRows<T>{db_ptr_storage_[0], stride(), channels()};
425 }
426
427 // Returns indirect rows where read is allowed.
428 1592 [[nodiscard]] IndirectRows<T> read_at() KLEIDICV_STREAMING {
429 1592 return IndirectRows<T>{db_ptr_storage_[1], stride(), channels()};
430 }
431
432 private:
433 // The double buffer.
434 T **db_ptr_storage_[2];
435 }; // end of class DoubleBufferedIndirectRows<T>
436
437 // Describes the layout of two parallel rows.
438 template <typename T>
439 class ParallelRows final : public RowBase<T> {
440 public:
441 // Shorten code: no need for 'this->'.
442 using RowBase<T>::channels;
443 using RowBase<T>::stride;
444
445 3040 explicit ParallelRows(T *ptr, size_t stride,
446 size_t channels) KLEIDICV_STREAMING
447 3040 : RowBase<T>(2 * stride, channels),
448 3040 ptrs_{ptr, RowBase<T>::add_stride(ptr, stride)} {}
449
450 1520 explicit ParallelRows(T *ptr, size_t stride) KLEIDICV_STREAMING
451 1520 : ParallelRows(ptr, stride, 1) {}
452
453 // Addition assignment operator to navigate among rows.
454 7440 ParallelRows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
455 7440 ptrs_[0] = RowBase<T>::add_stride(ptrs_[0], diff * stride());
456 7440 ptrs_[1] = RowBase<T>::add_stride(ptrs_[1], diff * stride());
457 7440 return *this;
458 }
459
460 // Prefix increment operator to advance to the next row.
461 7440 ParallelRows<T> &operator++() KLEIDICV_STREAMING { return operator+=(1); }
462
463 // Returns views on columns within the current rows.
464 7440 [[nodiscard]] ParallelColumns<T> as_columns() const KLEIDICV_STREAMING {
465 7440 Columns columns_0{ptrs_[0], channels()};
466 7440 Columns columns_1{ptrs_[1], channels()};
467 7440 return ParallelColumns{columns_0, columns_1};
468 7440 }
469
470 // Instructs the logic to drop the second row.
471 1680 void make_single_row() KLEIDICV_STREAMING { ptrs_[1] = ptrs_[0]; }
472
473 private:
474 // Pointers to the two parallel rows.
475 T *ptrs_[2];
476 }; // end of class ParallelRows<T>
477
478 template <typename OperationType, typename... RowTypes>
479 34856 KLEIDICV_FORCE_INLINE void zip_rows(OperationType &operation, Rectangle rect,
480 RowTypes... rows) KLEIDICV_STREAMING {
481 // Unary left fold. Evaluates the expression for every part of the unexpanded
482 // parameter pack 'rows'.
483
96/96
✓ Branch 0 taken 9618 times.
✓ Branch 1 taken 5097 times.
✓ Branch 2 taken 6300 times.
✓ Branch 3 taken 3406 times.
✓ Branch 4 taken 2625 times.
✓ Branch 5 taken 2712 times.
✓ Branch 6 taken 2232 times.
✓ Branch 7 taken 2521 times.
✓ Branch 8 taken 3755 times.
✓ Branch 9 taken 612 times.
✓ Branch 10 taken 628 times.
✓ Branch 11 taken 3487 times.
✓ Branch 12 taken 3003 times.
✓ Branch 13 taken 263 times.
✓ Branch 14 taken 1728 times.
✓ Branch 15 taken 1467 times.
✓ Branch 16 taken 410 times.
✓ Branch 17 taken 1310 times.
✓ Branch 18 taken 1328 times.
✓ Branch 19 taken 442 times.
✓ Branch 20 taken 1545 times.
✓ Branch 21 taken 42 times.
✓ Branch 22 taken 16 times.
✓ Branch 23 taken 1529 times.
✓ Branch 24 taken 1336 times.
✓ Branch 25 taken 120 times.
✓ Branch 26 taken 1304 times.
✓ Branch 27 taken 32 times.
✓ Branch 28 taken 16 times.
✓ Branch 29 taken 1288 times.
✓ Branch 30 taken 856 times.
✓ Branch 31 taken 128 times.
✓ Branch 32 taken 808 times.
✓ Branch 33 taken 48 times.
✓ Branch 34 taken 32 times.
✓ Branch 35 taken 776 times.
✓ Branch 36 taken 792 times.
✓ Branch 37 taken 84 times.
✓ Branch 38 taken 872 times.
✓ Branch 39 taken 112 times.
✓ Branch 40 taken 80 times.
✓ Branch 41 taken 792 times.
✓ Branch 42 taken 824 times.
✓ Branch 43 taken 96 times.
✓ Branch 44 taken 792 times.
✓ Branch 45 taken 32 times.
✓ Branch 46 taken 16 times.
✓ Branch 47 taken 776 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.
34856 if ((... && (rows.is_continuous(rect.width())))) {
484 20972 rect.flatten();
485 20972 }
486
487
24/24
✓ Branch 0 taken 22392 times.
✓ Branch 1 taken 14715 times.
✓ Branch 2 taken 8685 times.
✓ Branch 3 taken 5029 times.
✓ Branch 4 taken 6871 times.
✓ Branch 5 taken 4299 times.
✓ Branch 6 taken 5238 times.
✓ Branch 7 taken 3918 times.
✓ Branch 8 taken 3538 times.
✓ Branch 9 taken 2440 times.
✓ Branch 10 taken 2630 times.
✓ Branch 11 taken 1907 times.
✓ Branch 12 taken 1620 times.
✓ Branch 13 taken 940 times.
✓ Branch 14 taken 1408 times.
✓ Branch 15 taken 984 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.
88406 for (size_t row_index = 0; row_index < rect.height(); ++row_index) {
488 53550 operation.process_row(rect.width(), rows.as_columns()...);
489 // Call pre-increment operator on all elements in the parameter pack.
490 53550 ((++rows), ...);
491 53550 }
492 34856 }
493
494 template <typename OperationType, typename... RowTypes>
495 1520 void zip_parallel_rows(OperationType &operation, Rectangle rect,
496 RowTypes... rows) KLEIDICV_STREAMING {
497
8/8
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 930 times.
✓ Branch 2 taken 380 times.
✓ Branch 3 taken 930 times.
✓ Branch 4 taken 380 times.
✓ Branch 5 taken 930 times.
✓ Branch 6 taken 380 times.
✓ Branch 7 taken 930 times.
5240 for (size_t row_index = 0; row_index < rect.height(); row_index += 2) {
498 // Handle the last odd row in a special way.
499
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))) {
500 840 ((rows.make_single_row(), ...));
501 840 }
502
503 3720 operation.process_row(rect.width(), rows.as_columns()...);
504 // Call pre-increment operator on all elements in the parameter pack.
505 3720 ((++rows), ...);
506 3720 }
507 1520 }
508
509 // Copy rows with support for overlapping memory.
510 template <typename T>
511 class CopyRows final {
512 public:
513 652 void process_row(size_t length, Columns<const T> src,
514 Columns<T> dst) KLEIDICV_STREAMING {
515 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
516 __arm_sc_memmove(static_cast<void *>(&dst[0]),
517 static_cast<const void *>(&src[0]),
518 length * sizeof(T) * dst.channels());
519 #else
520 1304 std::memmove(static_cast<void *>(&dst[0]),
521 652 static_cast<const void *>(&src[0]),
522 652 length * sizeof(T) * dst.channels());
523 #endif
524 652 }
525
526 template <typename S, typename D>
527 646 static void copy_rows(Rectangle rect, S src, D dst) KLEIDICV_STREAMING {
528 646 CopyRows<T> operation;
529 646 zip_rows(operation, rect, src, dst);
530 646 }
531 }; // end of class CopyRows<T>
532
533 // Copy non-verlapping rows.
534 template <typename T>
535 class CopyNonOverlappingRows final {
536 public:
537 10560 void process_row(size_t length, Columns<const T> src,
538 Columns<T> dst) KLEIDICV_STREAMING {
539 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
540 __arm_sc_memcpy(static_cast<void *>(&dst[0]),
541 static_cast<const void *>(&src[0]),
542 length * sizeof(T) * dst.channels());
543 #else
544 21120 std::memcpy(static_cast<void *>(&dst[0]),
545 10560 static_cast<const void *>(&src[0]),
546 10560 length * sizeof(T) * dst.channels());
547 #endif
548 10560 }
549
550 1408 static void copy_rows(Rectangle rect, Rows<const T> src,
551 Rows<T> dst) KLEIDICV_STREAMING {
552 1408 CopyNonOverlappingRows<T> operation;
553 1408 zip_rows(operation, rect, src, dst);
554 1408 }
555 }; // end of class CopyNonOverlappingRows<T>
556
557 // Sets the margins to zero. It takes both channel count and element size into
558 // account. For example, margin.left() = 1 means that one pixel worth of space,
559 // that is sizeof(T) * channels, will be set to zero. The first argument, rect,
560 // describes the total available memory, including all margins.
561 template <typename T>
562 void make_zero_border_border(Rectangle rect, Rows<T> rows, Margin margin) {
563 if (margin.left()) {
564 size_t margin_width_in_bytes = margin.left() * sizeof(T) * rows.channels();
565 for (size_t index = 0; index < rect.height(); ++index) {
566 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
567 __arm_sc_memset(&rows.at(index)[0], 0, margin_width_in_bytes);
568 #else
569 std::memset(&rows.at(index)[0], 0, margin_width_in_bytes);
570 #endif
571 }
572 }
573
574 if (margin.top()) {
575 size_t top_width = rect.width() - margin.left() - margin.right();
576 size_t top_width_in_bytes = top_width * sizeof(T) * rows.channels();
577 for (size_t index = 0; index < margin.top(); ++index) {
578 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
579 __arm_sc_memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
580 #else
581 std::memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
582 #endif
583 }
584 }
585
586 if (margin.right()) {
587 size_t margin_width_in_bytes = margin.right() * sizeof(T) * rows.channels();
588 for (size_t index = 0; index < rect.height(); ++index) {
589 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
590 __arm_sc_memset(&rows.at(index, rect.width() - margin.right())[0], 0,
591 margin_width_in_bytes);
592 #else
593 std::memset(&rows.at(index, rect.width() - margin.right())[0], 0,
594 margin_width_in_bytes);
595 #endif
596 }
597 }
598
599 if (margin.bottom()) {
600 size_t bottom_width = rect.width() - margin.left() - margin.right();
601 size_t bottom_width_in_bytes = bottom_width * sizeof(T) * rows.channels();
602 for (size_t index = rect.height() - margin.bottom(); index < rect.height();
603 ++index) {
604 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
605 __arm_sc_memset(&rows.at(index, margin.left())[0], 0,
606 bottom_width_in_bytes);
607 #else
608 std::memset(&rows.at(index, margin.left())[0], 0, bottom_width_in_bytes);
609 #endif
610 }
611 }
612 }
613
614 // Struct for providing Rows object over memory managed by std::unique_ptr.
615 template <typename T>
616 class RowsOverUniquePtr {
617 public:
618 // Returns a rectangle which describes the layout of the allocated memory.
619 Rectangle rect() const { return rect_; }
620
621 // Returns a raw pointer to the allocated memory.
622 T *data() const { return data_.get(); }
623
624 // Returns a Rows instance over the allocated memory.
625 Rows<T> rows() const { return rows_; }
626
627 // Like rows() but without margins.
628 Rows<T> rows_without_margin() const { return rows_without_margin_; }
629
630 protected:
631 RowsOverUniquePtr(Rectangle rect, Margin margin)
632 : rect_{get_rectangle(rect, margin)},
633 data_{std::unique_ptr<T[]>(new(std::nothrow) T[rect_.area()])} {
634 if (!data_) {
635 // Code that uses this class is required to check that data() is valid.
636 return;
637 }
638
639 rows_ = Rows<T>{&data_[0], rect_.width() * sizeof(T)};
640 rows_without_margin_ = rows_.at(margin.top(), margin.left());
641 make_zero_border_border<T>(rect_, rows_, margin);
642 }
643
644 private:
645 static Rectangle get_rectangle(Rectangle rect, Margin margin) {
646 return Rectangle{margin.left() + rect.width() + margin.right(),
647 margin.top() + rect.height() + margin.bottom()};
648 }
649
650 Rectangle rect_;
651 Rows<T> rows_;
652 Rows<T> rows_without_margin_;
653 std::unique_ptr<T[]> data_;
654 };
655
656 } // namespace KLEIDICV_TARGET_NAMESPACE
657
658 #endif // KLEIDICV_TYPES_H
659