GCC Code Coverage Report


Directory: ./
File: tasks/tsarkov_k_jarvis_convex_hull/omp/src/ops_omp.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 55 55 100.0%
Functions: 10 10 100.0%
Branches: 36 48 75.0%

Line Branch Exec Source
1 #include "tsarkov_k_jarvis_convex_hull/omp/include/ops_omp.hpp"
2
3 #include <omp.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <cstdint>
8 #include <ranges>
9 #include <vector>
10
11 #include "tsarkov_k_jarvis_convex_hull/common/include/common.hpp"
12
13 namespace tsarkov_k_jarvis_convex_hull {
14
15 namespace {
16
17 std::int64_t CrossProduct(const Point &first_point, const Point &second_point, const Point &third_point) {
18 450 const std::int64_t vector_first_x =
19 450 static_cast<std::int64_t>(second_point.x) - static_cast<std::int64_t>(first_point.x);
20 450 const std::int64_t vector_first_y =
21 450 static_cast<std::int64_t>(second_point.y) - static_cast<std::int64_t>(first_point.y);
22 450 const std::int64_t vector_second_x =
23 450 static_cast<std::int64_t>(third_point.x) - static_cast<std::int64_t>(first_point.x);
24 450 const std::int64_t vector_second_y =
25 450 static_cast<std::int64_t>(third_point.y) - static_cast<std::int64_t>(first_point.y);
26
27 450 return (vector_first_x * vector_second_y) - (vector_first_y * vector_second_x);
28 }
29
30 std::int64_t SquaredDistance(const Point &first_point, const Point &second_point) {
31 const std::int64_t delta_x = static_cast<std::int64_t>(second_point.x) - static_cast<std::int64_t>(first_point.x);
32 const std::int64_t delta_y = static_cast<std::int64_t>(second_point.y) - static_cast<std::int64_t>(first_point.y);
33
34 206 return (delta_x * delta_x) + (delta_y * delta_y);
35 }
36
37 284 bool PointLess(const Point &first_point, const Point &second_point) {
38
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 64 times.
284 if (first_point.x != second_point.x) {
39 220 return first_point.x < second_point.x;
40 }
41 64 return first_point.y < second_point.y;
42 }
43
44 28 std::vector<Point> RemoveDuplicatePoints(const std::vector<Point> &input_points) {
45 28 std::vector<Point> unique_points = input_points;
46
47 std::ranges::sort(unique_points, PointLess);
48 unique_points.erase(std::ranges::unique(unique_points).begin(), unique_points.end());
49
50 28 return unique_points;
51 }
52
53 20 std::size_t FindLeftmostPointIndex(const std::vector<Point> &input_points) {
54 std::size_t leftmost_point_index = 0;
55
56
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 20 times.
100 for (std::size_t point_index = 1; point_index < input_points.size(); ++point_index) {
57 const Point &current_point = input_points[point_index];
58 const Point &leftmost_point = input_points[leftmost_point_index];
59
60
3/4
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 8 times.
80 if ((current_point.x < leftmost_point.x) ||
61
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 ((current_point.x == leftmost_point.x) && (current_point.y < leftmost_point.y))) {
62 leftmost_point_index = point_index;
63 }
64 }
65
66 20 return leftmost_point_index;
67 }
68
69 518 bool ShouldReplaceBestPoint(const std::vector<Point> &unique_points, std::size_t current_point_index,
70 std::size_t best_point_index, std::size_t candidate_point_index) {
71
2/2
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 68 times.
518 if (candidate_point_index == current_point_index) {
72 return false;
73 }
74
75 const std::int64_t orientation = CrossProduct(unique_points[current_point_index], unique_points[best_point_index],
76 unique_points[candidate_point_index]);
77
78
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 132 times.
450 if (orientation < 0) {
79 return true;
80 }
81
82
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 112 times.
318 if (orientation == 0) {
83 const std::int64_t best_distance =
84 SquaredDistance(unique_points[current_point_index], unique_points[best_point_index]);
85 const std::int64_t candidate_distance =
86 SquaredDistance(unique_points[current_point_index], unique_points[candidate_point_index]);
87
88 206 return candidate_distance > best_distance;
89 }
90
91 return false;
92 }
93
94 std::size_t FindThreadLocalBestIndex(const std::vector<Point> &unique_points, std::size_t current_point_index,
95 std::size_t initial_best_index, std::size_t range_begin, std::size_t range_end) {
96 std::size_t local_best_index = initial_best_index;
97
98 for (std::size_t point_index = range_begin; point_index < range_end; ++point_index) {
99 if (ShouldReplaceBestPoint(unique_points, current_point_index, local_best_index, point_index)) {
100 local_best_index = point_index;
101 }
102 }
103
104 return local_best_index;
105 }
106
107 std::size_t ReduceBestIndices(const std::vector<Point> &unique_points, std::size_t current_point_index,
108 std::size_t initial_best_index, const std::vector<std::size_t> &local_best_indices) {
109 std::size_t next_point_index = initial_best_index;
110
111
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 68 times.
238 for (std::size_t local_best_index : local_best_indices) {
112
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 103 times.
170 if (ShouldReplaceBestPoint(unique_points, current_point_index, next_point_index, local_best_index)) {
113 next_point_index = local_best_index;
114 }
115 }
116
117 return next_point_index;
118 }
119
120 68 std::size_t FindNextHullPointIndexOMP(const std::vector<Point> &unique_points, std::size_t current_point_index) {
121
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 const std::size_t initial_next_point_index = (current_point_index == 0) ? 1 : 0;
122 68 const int thread_count = omp_get_max_threads();
123
124 68 std::vector<std::size_t> local_best_indices(static_cast<std::size_t>(thread_count), initial_next_point_index);
125
126 68 #pragma omp parallel default(none) \
127 shared(unique_points, current_point_index, local_best_indices, initial_next_point_index, thread_count)
128 {
129 const int thread_index = omp_get_thread_num();
130 const std::size_t point_count = unique_points.size();
131 const std::size_t chunk_size =
132 (point_count + static_cast<std::size_t>(thread_count) - 1) / static_cast<std::size_t>(thread_count);
133 const std::size_t range_begin = static_cast<std::size_t>(thread_index) * chunk_size;
134 const std::size_t range_end = std::min(range_begin + chunk_size, point_count);
135
136 local_best_indices[static_cast<std::size_t>(thread_index)] =
137 FindThreadLocalBestIndex(unique_points, current_point_index, initial_next_point_index, range_begin, range_end);
138 }
139
140 68 return ReduceBestIndices(unique_points, current_point_index, initial_next_point_index, local_best_indices);
141 }
142
143 } // namespace
144
145
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 TsarkovKJarvisConvexHullOMP::TsarkovKJarvisConvexHullOMP(const InType &input_points) {
146 SetTypeOfTask(GetStaticTypeOfTask());
147
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 GetInput() = input_points;
148 GetOutput().clear();
149 28 }
150
151
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 bool TsarkovKJarvisConvexHullOMP::ValidationImpl() {
152
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
28 return !GetInput().empty() && GetOutput().empty();
153 }
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 bool TsarkovKJarvisConvexHullOMP::PreProcessingImpl() {
156 GetOutput().clear();
157 28 return true;
158 }
159
160 28 bool TsarkovKJarvisConvexHullOMP::RunImpl() {
161 28 const std::vector<Point> unique_points = RemoveDuplicatePoints(GetInput());
162
163
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (unique_points.empty()) {
164 return false;
165 }
166
167
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
28 if (unique_points.size() == 1) {
168
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 GetOutput() = unique_points;
169 return true;
170 }
171
172
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
24 if (unique_points.size() == 2) {
173
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 GetOutput() = unique_points;
174 return true;
175 }
176
177 20 const std::size_t start_point_index = FindLeftmostPointIndex(unique_points);
178 std::size_t current_point_index = start_point_index;
179
180 while (true) {
181 GetOutput().push_back(unique_points[current_point_index]);
182
183
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 current_point_index = FindNextHullPointIndexOMP(unique_points, current_point_index);
184
185
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 if (current_point_index == start_point_index) {
186 break;
187 }
188 }
189
190 20 return !GetOutput().empty();
191 }
192
193 28 bool TsarkovKJarvisConvexHullOMP::PostProcessingImpl() {
194 28 return true;
195 }
196
197 } // namespace tsarkov_k_jarvis_convex_hull
198