GCC Code Coverage Report


Directory: ./
File: tasks/kondrashova_v_marking_components/omp/src/ops_omp.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 19 100 19.0%
Functions: 5 10 50.0%
Branches: 5 124 4.0%

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