KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/types.h
Date: 2026-01-20 20:58:59
Exec Total Coverage
Lines: 191 191 100.0%
Functions: 1881 1883 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 1728 explicit Point(size_t x, size_t y) KLEIDICV_STREAMING : x_{x}, y_{y} {}
26
27 4928 size_t x() const KLEIDICV_STREAMING { return x_; }
28 628024 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 78898 explicit Rectangle(size_t width, size_t height) KLEIDICV_STREAMING
39 78898 : width_(width),
40 78898 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 1840414 size_t width() const KLEIDICV_STREAMING { return width_; }
49 5534302 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 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 1262837 explicit Columns(T *ptr, size_t channels) KLEIDICV_STREAMING
112 1262837 : ptr_{ptr},
113 1262837 channels_{channels} {}
114
115 // Subscript operator to return an arbitrary column at an index. To account
116 // for channel count use at() method.
117 3300695 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING { return ptr_[index]; }
118
119 // Addition assignment operator to step across the columns.
120 1028918 Columns &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
121 1028918 ptr_ += static_cast<ptrdiff_t>(channels()) * diff;
122 1028918 return *this;
123 }
124
125 // Subtraction assignment operator to step across the columns.
126 6864 Columns &operator-=(ptrdiff_t diff) KLEIDICV_STREAMING {
127 6864 ptr_ -= static_cast<ptrdiff_t>(channels()) * diff;
128 6864 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 520021 [[nodiscard]] Columns<T> at(ptrdiff_t column) KLEIDICV_STREAMING {
143 1040042 return Columns<T>{&ptr_[column * static_cast<ptrdiff_t>(channels())],
144 520021 channels()};
145 }
146
147 // Returns a pointer to a given column.
148 387946 [[nodiscard]] T *ptr_at(ptrdiff_t column) KLEIDICV_STREAMING {
149 387946 return ptr_ + column * static_cast<ptrdiff_t>(channels());
150 }
151
152 // Returns the number of channels in a row.
153 2480230 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 127971680 size_t stride() const KLEIDICV_STREAMING { return stride_; }
206
207 // Returns the number of channels in a row.
208 129906809 size_t channels() const KLEIDICV_STREAMING { return channels_; }
209
210 // Returns true if rows are continuous for a given length, otherwise false.
211 83100 bool is_continuous(size_t length) const KLEIDICV_STREAMING {
212 83100 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 63855644 RowBase(size_t stride, size_t channels) KLEIDICV_STREAMING
230 63855644 : stride_(stride),
231 63855644 channels_(channels) {}
232
233 // Adds a stride to a pointer, and returns the new pointer.
234 template <typename P>
235 63948019 [[nodiscard]] static P *add_stride(P *ptr,
236 ptrdiff_t stride) KLEIDICV_STREAMING {
237 63948019 uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
238 63948019 intptr += stride;
239 // NOLINTBEGIN(performance-no-int-to-ptr)
240 127896038 return reinterpret_cast<P *>(intptr);
241 // NOLINTEND(performance-no-int-to-ptr)
242 63948019 }
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 63835452 explicit Rows(T *ptr, size_t stride, size_t channels) KLEIDICV_STREAMING
275 63835452 : RowBase<T>(stride, channels),
276 63835452 ptr_{ptr} {}
277
278 58726 explicit Rows(T *ptr, size_t stride) KLEIDICV_STREAMING
279 58726 : 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 64576242 T &operator[](ptrdiff_t index) KLEIDICV_STREAMING { return ptr_[index]; }
286
287 // Addition assignment operator to navigate among rows.
288 498490 Rows<T> &operator+=(ptrdiff_t diff) KLEIDICV_STREAMING {
289 498490 ptr_ = get_pointer_at(diff);
290 498490 return *this;
291 }
292
293 // Prefix increment operator to advance to the next row.
294 488378 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 63430729 [[nodiscard]] Rows<T> at(ptrdiff_t row,
305 ptrdiff_t column = 0) KLEIDICV_STREAMING {
306 63430729 return Rows<T>{get_pointer_at(row, column), stride(), channels()};
307 }
308
309 // Returns a view on columns within the current row.
310 687888 [[nodiscard]] Columns<T> as_columns() const KLEIDICV_STREAMING {
311 687888 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 784 [[nodiscard]] size_t offset_for_index(size_t index,
317 size_t width) const KLEIDICV_STREAMING {
318 784 size_t row = index / width;
319 784 size_t column = index % width;
320 1568 return row * stride() + column * sizeof(T);
321 784 }
322
323 private:
324 // Returns a column in a row at a given index taking stride and channels into
325 // account.
326 63929219 [[nodiscard]] T *get_pointer_at(ptrdiff_t row,
327 ptrdiff_t column = 0) KLEIDICV_STREAMING {
328 127858438 T *ptr =
329 63929219 RowBase<T>::add_stride(ptr_, row * static_cast<ptrdiff_t>(stride()));
330 127858438 return &ptr[column * static_cast<ptrdiff_t>(channels())];
331 63929219 }
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 3920 explicit ParallelRows(T *ptr, size_t stride,
446 size_t channels) KLEIDICV_STREAMING
447 3920 : RowBase<T>(2 * stride, channels),
448 3920 ptrs_{ptr, RowBase<T>::add_stride(ptr, stride)} {}
449
450 1960 explicit ParallelRows(T *ptr, size_t stride) KLEIDICV_STREAMING
451 1960 : 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 40360 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 11027 times.
✓ Branch 1 taken 5219 times.
✓ Branch 2 taken 6876 times.
✓ Branch 3 taken 4295 times.
✓ Branch 4 taken 3243 times.
✓ Branch 5 taken 3368 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.
40360 if ((... && (rows.is_continuous(rect.width())))) {
484 26392 rect.flatten();
485 26392 }
486
487
24/24
✓ Branch 0 taken 23909 times.
✓ Branch 1 taken 16246 times.
✓ Branch 2 taken 9801 times.
✓ Branch 3 taken 6159 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.
99370 for (size_t row_index = 0; row_index < rect.height(); ++row_index) {
488 59010 operation.process_row(rect.width(), rows.as_columns()...);
489 // Call pre-increment operator on all elements in the parameter pack.
490 59010 ((++rows), ...);
491 59010 }
492 40360 }
493
494 template <typename OperationType, typename... RowTypes>
495 1960 KLEIDICV_FORCE_INLINE void zip_parallel_rows(OperationType &operation,
496 Rectangle rect, RowTypes... rows)
497 KLEIDICV_STREAMING {
498
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) {
499 // Handle the last odd row in a special way.
500
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))) {
501 840 ((rows.make_single_row(), ...));
502 840 }
503
504 3720 operation.process_row(rect.width(), rows.as_columns()...);
505 // Call pre-increment operator on all elements in the parameter pack.
506 3720 ((++rows), ...);
507 3720 }
508 1960 }
509
510 // Copy rows with support for overlapping memory.
511 template <typename T>
512 class CopyRows final {
513 public:
514 KLEIDICV_FORCE_INLINE
515 796 void process_row(size_t length, Columns<const T> src,
516 Columns<T> dst) KLEIDICV_STREAMING {
517 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
518 __arm_sc_memmove(static_cast<void *>(&dst[0]),
519 static_cast<const void *>(&src[0]),
520 length * sizeof(T) * dst.channels());
521 #else
522 1592 std::memmove(static_cast<void *>(&dst[0]),
523 796 static_cast<const void *>(&src[0]),
524 796 length * sizeof(T) * dst.channels());
525 #endif
526 796 }
527
528 template <typename S, typename D>
529 790 static void copy_rows(Rectangle rect, S src, D dst) KLEIDICV_STREAMING {
530 790 CopyRows<T> operation;
531 790 zip_rows(operation, rect, src, dst);
532 790 }
533 }; // end of class CopyRows<T>
534
535 // Copy non-verlapping rows.
536 template <typename T>
537 class CopyNonOverlappingRows final {
538 public:
539 KLEIDICV_FORCE_INLINE
540 10560 void process_row(size_t length, Columns<const T> src,
541 Columns<T> dst) KLEIDICV_STREAMING {
542 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
543 __arm_sc_memcpy(static_cast<void *>(&dst[0]),
544 static_cast<const void *>(&src[0]),
545 length * sizeof(T) * dst.channels());
546 #else
547 21120 std::memcpy(static_cast<void *>(&dst[0]),
548 10560 static_cast<const void *>(&src[0]),
549 10560 length * sizeof(T) * dst.channels());
550 #endif
551 10560 }
552
553 1408 static void copy_rows(Rectangle rect, Rows<const T> src,
554 Rows<T> dst) KLEIDICV_STREAMING {
555 1408 CopyNonOverlappingRows<T> operation;
556 1408 zip_rows(operation, rect, src, dst);
557 1408 }
558 }; // end of class CopyNonOverlappingRows<T>
559
560 // Sets the margins to zero. It takes both channel count and element size into
561 // account. For example, margin.left() = 1 means that one pixel worth of space,
562 // that is sizeof(T) * channels, will be set to zero. The first argument, rect,
563 // describes the total available memory, including all margins.
564 template <typename T>
565 void make_zero_border_border(Rectangle rect, Rows<T> rows, Margin margin) {
566 if (margin.left()) {
567 size_t margin_width_in_bytes = margin.left() * sizeof(T) * rows.channels();
568 for (size_t index = 0; index < rect.height(); ++index) {
569 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
570 __arm_sc_memset(&rows.at(index)[0], 0, margin_width_in_bytes);
571 #else
572 std::memset(&rows.at(index)[0], 0, margin_width_in_bytes);
573 #endif
574 }
575 }
576
577 if (margin.top()) {
578 size_t top_width = rect.width() - margin.left() - margin.right();
579 size_t top_width_in_bytes = top_width * sizeof(T) * rows.channels();
580 for (size_t index = 0; index < margin.top(); ++index) {
581 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
582 __arm_sc_memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
583 #else
584 std::memset(&rows.at(index, margin.left())[0], 0, top_width_in_bytes);
585 #endif
586 }
587 }
588
589 if (margin.right()) {
590 size_t margin_width_in_bytes = margin.right() * sizeof(T) * rows.channels();
591 for (size_t index = 0; index < rect.height(); ++index) {
592 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
593 __arm_sc_memset(&rows.at(index, rect.width() - margin.right())[0], 0,
594 margin_width_in_bytes);
595 #else
596 std::memset(&rows.at(index, rect.width() - margin.right())[0], 0,
597 margin_width_in_bytes);
598 #endif
599 }
600 }
601
602 if (margin.bottom()) {
603 size_t bottom_width = rect.width() - margin.left() - margin.right();
604 size_t bottom_width_in_bytes = bottom_width * sizeof(T) * rows.channels();
605 for (size_t index = rect.height() - margin.bottom(); index < rect.height();
606 ++index) {
607 #if (KLEIDICV_TARGET_SME || KLEIDICV_TARGET_SME2) && defined(__ANDROID__)
608 __arm_sc_memset(&rows.at(index, margin.left())[0], 0,
609 bottom_width_in_bytes);
610 #else
611 std::memset(&rows.at(index, margin.left())[0], 0, bottom_width_in_bytes);
612 #endif
613 }
614 }
615 }
616
617 // Struct for providing Rows object over memory managed by std::unique_ptr.
618 template <typename T>
619 class RowsOverUniquePtr {
620 public:
621 // Returns a rectangle which describes the layout of the allocated memory.
622 Rectangle rect() const { return rect_; }
623
624 // Returns a raw pointer to the allocated memory.
625 T *data() const { return data_.get(); }
626
627 // Returns a Rows instance over the allocated memory.
628 Rows<T> rows() const { return rows_; }
629
630 // Like rows() but without margins.
631 Rows<T> rows_without_margin() const { return rows_without_margin_; }
632
633 protected:
634 RowsOverUniquePtr(Rectangle rect, Margin margin)
635 : rect_{get_rectangle(rect, margin)},
636 data_{std::unique_ptr<T[]>(new(std::nothrow) T[rect_.area()])} {
637 if (!data_) {
638 // Code that uses this class is required to check that data() is valid.
639 return;
640 }
641
642 rows_ = Rows<T>{&data_[0], rect_.width() * sizeof(T)};
643 rows_without_margin_ = rows_.at(margin.top(), margin.left());
644 make_zero_border_border<T>(rect_, rows_, margin);
645 }
646
647 private:
648 static Rectangle get_rectangle(Rectangle rect, Margin margin) {
649 return Rectangle{margin.left() + rect.width() + margin.right(),
650 margin.top() + rect.height() + margin.bottom()};
651 }
652
653 Rectangle rect_;
654 Rows<T> rows_;
655 Rows<T> rows_without_margin_;
656 std::unique_ptr<T[]> data_;
657 };
658
659 } // namespace KLEIDICV_TARGET_NAMESPACE
660
661 #endif // KLEIDICV_TYPES_H
662