GCC Code Coverage Report


Directory: ./
File: tasks/kondrashova_v_marking_components/tbb/src/ops_tbb.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 19 109 17.4%
Functions: 5 12 41.7%
Branches: 5 126 4.0%

Line Branch Exec Source
1 #include "kondrashova_v_marking_components/tbb/include/ops_tbb.hpp"
2
3 #include <tbb/blocked_range.h>
4 #include <tbb/parallel_for.h>
5 #include <tbb/task_arena.h>
6
7 #include <algorithm>
8 #include <cstddef>
9 #include <cstdint>
10 #include <vector>
11
12 #include "kondrashova_v_marking_components/common/include/common.hpp"
13 #include "util/include/util.hpp"
14
15 namespace kondrashova_v_marking_components {
16
17
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 KondrashovaVTaskTBB::KondrashovaVTaskTBB(const InType &in) {
18 SetTypeOfTask(GetStaticTypeOfTask());
19 GetInput() = in;
20 52 GetOutput() = {};
21 52 }
22
23 52 bool KondrashovaVTaskTBB::ValidationImpl() {
24 52 return true;
25 }
26
27 52 bool KondrashovaVTaskTBB::PreProcessingImpl() {
28 const auto &in = GetInput();
29
30 52 width_ = in.width;
31 52 height_ = in.height;
32 52 image_ = in.data;
33
34
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
52 if (width_ > 0 && height_ > 0 && static_cast<int>(image_.size()) == width_ * height_) {
35 labels_1d_.assign(static_cast<size_t>(width_) * static_cast<size_t>(height_), 0);
36 } else {
37 labels_1d_.clear();
38 }
39
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 GetOutput().count = 0;
41 GetOutput().labels.clear();
42 52 return true;
43 }
44
45 namespace {
46
47 int Find(std::vector<int> &parent, int xx) {
48 while (parent[static_cast<size_t>(xx)] != xx) {
49 parent[static_cast<size_t>(xx)] = parent[static_cast<size_t>(parent[static_cast<size_t>(xx)])];
50 xx = parent[static_cast<size_t>(xx)];
51 }
52 return xx;
53 }
54
55 void Unite(std::vector<int> &parent, std::vector<int> &rnk, int aa, int bb) {
56 aa = Find(parent, aa);
57 bb = Find(parent, bb);
58 if (aa == bb) {
59 return;
60 }
61 if (rnk[static_cast<size_t>(aa)] < rnk[static_cast<size_t>(bb)]) {
62 std::swap(aa, bb);
63 }
64 parent[static_cast<size_t>(bb)] = aa;
65 if (rnk[static_cast<size_t>(aa)] == rnk[static_cast<size_t>(bb)]) {
66 rnk[static_cast<size_t>(aa)]++;
67 }
68 }
69
70 int GetNeighborLabel(int ii, int jj, int di, int dj, int row_start, int row_end, int width,
71 const std::vector<uint8_t> &image, const std::vector<int> &local_labels) {
72 int ni = ii + di;
73 int nj = jj + dj;
74 if (ni < row_start || ni >= row_end || nj < 0 || nj >= width) {
75 return 0;
76 }
77 auto nidx = (static_cast<size_t>(ni) * static_cast<size_t>(width)) + static_cast<size_t>(nj);
78 if (image[nidx] == 0) {
79 return local_labels[nidx];
80 }
81 return 0;
82 }
83
84 void ScanStripe(int row_start, int row_end, int width, int label_offset, const std::vector<uint8_t> &image,
85 std::vector<int> &local_labels) {
86 int current_label = label_offset;
87 for (int ii = row_start; ii < row_end; ++ii) {
88 for (int jj = 0; jj < width; ++jj) {
89 auto idx = (static_cast<size_t>(ii) * static_cast<size_t>(width)) + static_cast<size_t>(jj);
90 if (image[idx] != 0) {
91 continue;
92 }
93
94 int left_label = GetNeighborLabel(ii, jj, 0, -1, row_start, row_end, width, image, local_labels);
95 int top_label = GetNeighborLabel(ii, jj, -1, 0, row_start, row_end, width, image, local_labels);
96
97 if (left_label == 0 && top_label == 0) {
98 local_labels[idx] = ++current_label;
99 } else if (left_label != 0 && top_label == 0) {
100 local_labels[idx] = left_label;
101 } else if (left_label == 0) {
102 local_labels[idx] = top_label;
103 } else {
104 local_labels[idx] = std::min(left_label, top_label);
105 }
106 }
107 }
108 }
109
110 void MergeHorizontal(int height, int width, const std::vector<int> &local_labels, std::vector<int> &parent,
111 std::vector<int> &rnk) {
112 for (int ii = 0; ii < height; ++ii) {
113 for (int jj = 1; jj < width; ++jj) {
114 auto idx = (static_cast<size_t>(ii) * static_cast<size_t>(width)) + static_cast<size_t>(jj);
115 auto lidx = (static_cast<size_t>(ii) * static_cast<size_t>(width)) + static_cast<size_t>(jj - 1);
116 if (local_labels[idx] != 0 && local_labels[lidx] != 0 && local_labels[idx] != local_labels[lidx]) {
117 Unite(parent, rnk, local_labels[idx], local_labels[lidx]);
118 }
119 }
120 }
121 }
122
123 void MergeBoundaries(int height, int width, int num_threads, const std::vector<int> &local_labels,
124 std::vector<int> &parent, std::vector<int> &rnk) {
125 for (int tid = 1; tid < num_threads; ++tid) {
126 const int boundary_row = (tid * height) / num_threads;
127 if (boundary_row >= height) {
128 continue;
129 }
130 for (int jj = 0; jj < width; ++jj) {
131 auto idx = (static_cast<size_t>(boundary_row) * static_cast<size_t>(width)) + static_cast<size_t>(jj);
132 auto tidx = (static_cast<size_t>(boundary_row - 1) * static_cast<size_t>(width)) + static_cast<size_t>(jj);
133 if (local_labels[idx] != 0 && local_labels[tidx] != 0 && local_labels[idx] != local_labels[tidx]) {
134 Unite(parent, rnk, local_labels[idx], local_labels[tidx]);
135 }
136 }
137 }
138 }
139
140 int Relabel(int total, const std::vector<int> &local_labels, std::vector<int> &parent, std::vector<int> &relabel_map,
141 std::vector<int> &labels_1d) {
142 int count = 0;
143 for (int ii = 0; ii < total; ++ii) {
144 auto idx = static_cast<size_t>(ii);
145 if (local_labels[idx] == 0) {
146 continue;
147 }
148 int root = Find(parent, local_labels[idx]);
149 if (relabel_map[static_cast<size_t>(root)] == 0) {
150 relabel_map[static_cast<size_t>(root)] = ++count;
151 }
152 labels_1d[idx] = relabel_map[static_cast<size_t>(root)];
153 }
154 return count;
155 }
156
157 } // namespace
158
159 52 bool KondrashovaVTaskTBB::RunImpl() {
160
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
52 if (width_ <= 0 || height_ <= 0 || image_.empty()) {
161 52 GetOutput().count = 0;
162 52 return true;
163 }
164
165 const int total = width_ * height_;
166 const int num_threads = ppc::util::GetNumThreads();
167 const int max_labels_per_thread = total + 1;
168 const int max_total_labels = (num_threads * max_labels_per_thread) + 1;
169
170 std::vector<int> local_labels(static_cast<size_t>(total), 0);
171
172 const int width = width_;
173 const int height = height_;
174 const std::vector<uint8_t> &image = image_;
175
176 // Параллельное сканирование через TBB
177 tbb::task_arena arena(num_threads);
178 arena.execute([&] {
179 tbb::parallel_for(tbb::blocked_range<int>(0, num_threads), [&](const tbb::blocked_range<int> &range) {
180 for (int tid = range.begin(); tid < range.end(); ++tid) {
181 const int row_start = (tid * height) / num_threads;
182 const int row_end = ((tid + 1) * height) / num_threads;
183 const int label_offset = tid * max_labels_per_thread;
184 ScanStripe(row_start, row_end, width, label_offset, image, local_labels);
185 }
186 }, tbb::simple_partitioner());
187 });
188
189 std::vector<int> parent(static_cast<size_t>(max_total_labels));
190 std::vector<int> rnk(static_cast<size_t>(max_total_labels), 0);
191 for (int ii = 0; ii < max_total_labels; ++ii) {
192 parent[static_cast<size_t>(ii)] = ii;
193 }
194
195 MergeHorizontal(height, width, local_labels, parent, rnk);
196 MergeBoundaries(height, width, num_threads, local_labels, parent, rnk);
197
198 std::vector<int> relabel_map(static_cast<size_t>(max_total_labels), 0);
199 GetOutput().count = Relabel(total, local_labels, parent, relabel_map, labels_1d_);
200
201 return true;
202 }
203
204 52 bool KondrashovaVTaskTBB::PostProcessingImpl() {
205
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
52 if (width_ <= 0 || height_ <= 0) {
206 GetOutput().labels.clear();
207 52 return true;
208 }
209
210 GetOutput().labels.assign(height_, std::vector<int>(width_, 0));
211 for (int ii = 0; ii < height_; ++ii) {
212 for (int jj = 0; jj < width_; ++jj) {
213 auto idx = (static_cast<size_t>(ii) * static_cast<size_t>(width_)) + static_cast<size_t>(jj);
214 GetOutput().labels[ii][jj] = labels_1d_[idx];
215 }
216 }
217 return true;
218 }
219
220 } // namespace kondrashova_v_marking_components
221