cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
minmax_impl.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cpp-toolbox/types/minmax.hpp> // Include the header with declarations
4
5// Include necessary headers for implementation details
6#include <algorithm> // For std::min, std::max
7#include <cmath> // For std::ceil
8#include <future> // For std::future
9#include <iostream> // For std::cerr
10#include <iterator> // For std::begin, std::end, std::distance, std::advance
11#include <limits> // For std::numeric_limits
12#include <stdexcept> // For potential exceptions
13#include <thread> // For std::thread::hardware_concurrency
14#include <vector> // For std::vector
15
19
21{
22
23// --- minmax_t<T> Implementations ---
24
25// General template default constructor (for non-specialized primitive types)
26template<typename T>
28 : initialized_(false)
29{
30 // Check if T has numeric_limits specialization
31 if constexpr (std::numeric_limits<T>::is_specialized) {
32 // Use lowest() for floating point to handle negative infinity correctly
33 if constexpr (std::is_floating_point_v<T>) {
34 min = std::numeric_limits<T>::max(); // Start min high
35 max =
36 std::numeric_limits<T>::lowest(); // Start max low (potentially -inf)
37 } else {
38 // For integers, use min() and max()
39 min = std::numeric_limits<T>::max(); // Start min high
40 max = std::numeric_limits<T>::min(); // Start max low
41 }
42 } else {
43 // Fallback for types without numeric_limits (likely custom types)
44 min = T {};
45 max = T {};
46 }
47}
48
49// Constructor with initial values
50template<typename T>
51minmax_t<T>::minmax_t(T initial_min, T initial_max)
52 : min(initial_min)
53 , max(initial_max)
54 , initialized_(true) // Mark as initialized since values are provided
55{
56}
57
58// Generic operator+= to update min and max
59template<typename T>
61{
62 if (!initialized_) {
63 min = value;
64 max = value;
65 initialized_ = true;
66 } else {
67 // Use std::min and std::max for comparison
68 min = std::min(min, value);
69 max = std::max(max, value);
70 }
71 return *this;
72}
73
74// --- minmax_t<point_t<T>> Implementations ---
75
76template<typename T>
78 : initialized_(false)
79{
80 static_assert(std::numeric_limits<T>::is_specialized,
81 "Coordinate type T must have specialized std::numeric_limits.");
82
83 // Initialize min components to maximum possible value
84 min = point_t<T>(std::numeric_limits<T>::max(),
85 std::numeric_limits<T>::max(),
86 std::numeric_limits<T>::max());
87
88 // Initialize max components to lowest/minimum possible value
89 if constexpr (std::is_floating_point_v<T>) {
90 max = point_t<T>(std::numeric_limits<T>::lowest(),
91 std::numeric_limits<T>::lowest(),
92 std::numeric_limits<T>::lowest());
93 } else { // Assuming integral type otherwise
94 max = point_t<T>(std::numeric_limits<T>::min(),
95 std::numeric_limits<T>::min(),
96 std::numeric_limits<T>::min());
97 }
98}
99
100template<typename T>
101minmax_t<point_t<T>>::minmax_t(point_t<T> initial_min, point_t<T> initial_max)
102 : min(initial_min)
103 , max(initial_max)
104 , initialized_(true) // Mark as initialized
105{
106}
107
108template<typename T>
110{
111 if (!initialized_) {
112 min = value;
113 max = value;
114 initialized_ = true;
115 } else {
116 // Update min components
117 min.x = std::min(min.x, value.x);
118 min.y = std::min(min.y, value.y);
119 min.z = std::min(min.z, value.z);
120
121 // Update max components
122 max.x = std::max(max.x, value.x);
123 max.y = std::max(max.y, value.y);
124 max.z = std::max(max.z, value.z);
125 }
126 return *this;
127}
128
129// --- Helper Function Implementations ---
130
131template<typename T>
133{
134 if (!a.initialized_) {
135 return b;
136 }
137 if (!b.initialized_) {
138 return a;
139 }
140 // Both are initialized, combine them
141 return minmax_t<T>(std::min(a.min, b.min), std::max(a.max, b.max));
142}
143
144template<typename CoordT>
146 const minmax_t<point_t<CoordT>>& b)
147{
148 if (!a.initialized_) {
149 return b;
150 }
151 if (!b.initialized_) {
152 return a;
153 }
154 // Both are initialized, combine component-wise
155 point_t<CoordT> combined_min;
156 point_t<CoordT> combined_max;
157
158 combined_min.x = std::min(a.min.x, b.min.x);
159 combined_min.y = std::min(a.min.y, b.min.y);
160 combined_min.z = std::min(a.min.z, b.min.z);
161
162 combined_max.x = std::max(a.max.x, b.max.x);
163 combined_max.y = std::max(a.max.y, b.max.y);
164 combined_max.z = std::max(a.max.z, b.max.z);
165
166 return minmax_t<point_t<CoordT>>(combined_min, combined_max);
167}
168
169// --- Sequential calculate_minmax Implementations ---
170
171// For single items (non-containers)
172template<typename InputType>
173[[nodiscard]] auto calculate_minmax(const InputType& input)
174 -> std::enable_if_t<!detail::is_calculable_container_v<InputType>,
176{
177 using ItemType = std::decay_t<InputType>;
178 // Result is just the item itself as both min and max
179 return minmax_t<ItemType>(input,
180 input); // Directly construct and mark initialized
181}
182
183// For calculable containers
184template<typename InputType>
185[[nodiscard]] auto calculate_minmax(const InputType& input)
186 -> std::enable_if_t<detail::is_calculable_container_v<InputType>,
187 minmax_t<typename InputType::value_type>>
188{
189 using ItemType = typename InputType::value_type;
190 minmax_t<ItemType> result; // Default constructor handles initial state
191
192 auto it = std::begin(input);
193 auto end = std::end(input);
194
195 if (it == end) { // Handle empty container explicitly
196 result.initialized_ = false; // Ensure it's marked uninitialized
197 return result;
198 }
199
200 // Initialize with the first element - Use operator+= for correct
201 // initialization and potential point_t handling
202 result += *it;
203 ++it;
204
205 // Process remaining elements using operator+= which handles component-wise
206 // logic correctly for point_t
207 for (; it != end; ++it) {
208 result += *it; // Use operator+= for correct update logic
209 }
210
211 return result;
212}
213
214// For point_cloud_t
215template<typename T>
216[[nodiscard]] auto calculate_minmax(const point_cloud_t<T>& input)
218{
219 // Delegate to the container version using the points vector
220 return calculate_minmax(input.points);
221}
222
223// --- Parallel calculate_minmax Implementations ---
224
225// For single items (delegates to sequential)
226template<typename InputType>
227[[nodiscard]] auto calculate_minmax_parallel(const InputType& input)
228 -> std::enable_if_t<!detail::is_calculable_container_v<InputType>,
230{
231 return calculate_minmax(input); // No benefit from parallel for single item
232}
233
234// For calculable containers
235template<typename InputType>
236[[nodiscard]] auto calculate_minmax_parallel(const InputType& input)
237 -> std::enable_if_t<detail::is_calculable_container_v<InputType>,
238 minmax_t<typename InputType::value_type>>
239{
240 using ItemType = typename InputType::value_type;
241 using ResultType = minmax_t<ItemType>;
242
243 const auto total_size_signed =
244 std::distance(std::begin(input), std::end(input));
245 constexpr size_t sequential_threshold =
246 1024; // Threshold for switching to sequential
247
248 if (total_size_signed <= 0) { // Handle empty range
249 return ResultType(); // Return default (uninitialized)
250 }
251 const size_t total_size = static_cast<size_t>(total_size_signed);
252
253 if (total_size < sequential_threshold) {
254 return calculate_minmax(input); // Fallback to sequential
255 }
256
257 // --- Parallel Execution Logic ---
259 const size_t num_threads = pool.get_thread_count();
260 const size_t hardware_threads =
261 std::max(1u, std::thread::hardware_concurrency());
262 const size_t min_chunk_size = 256;
263 // Determine number of tasks, aiming for reasonable granularity
264 const size_t max_tasks = std::max(
265 static_cast<size_t>(1), std::max(num_threads, hardware_threads) * 4);
266 const size_t chunk_size =
267 std::max(min_chunk_size,
268 static_cast<size_t>(
269 std::ceil(static_cast<double>(total_size) / max_tasks)));
270 size_t num_tasks = (total_size == 0)
271 ? 0
272 : static_cast<size_t>(
273 std::ceil(static_cast<double>(total_size) / chunk_size));
274 if (num_tasks == 0 && total_size > 0)
275 num_tasks = 1; // Ensure at least one task if not empty
276
277 std::vector<std::future<ResultType>> futures;
278 if (num_tasks == 0) {
279 return ResultType();
280 }
281 futures.reserve(num_tasks);
282
283 auto task_lambda = [](auto chunk_begin_it, auto chunk_end_it) -> ResultType
284 {
285 ResultType local_result;
286 if (chunk_begin_it == chunk_end_it) { // Handle empty chunk
287 local_result.initialized_ = false;
288 return local_result;
289 }
290
291 // Use operator+= for the first element and subsequent elements
292 auto it = chunk_begin_it;
293 local_result += *it; // Initialize using operator+=
294 ++it;
295 for (; it != chunk_end_it; ++it) {
296 local_result += *it; // Update using operator+=
297 }
298 return local_result;
299 };
300
301 auto first = std::begin(input);
302 for (size_t i = 0; i < num_tasks; ++i) {
303 size_t start_offset = i * chunk_size;
304 size_t current_chunk_size = std::min(chunk_size, total_size - start_offset);
305
306 if (current_chunk_size == 0)
307 break; // No more elements
308
309 auto chunk_begin = first;
310 std::advance(chunk_begin, start_offset);
311 auto chunk_end = chunk_begin;
312 std::advance(chunk_end, current_chunk_size);
313
314 futures.emplace_back(pool.submit(task_lambda, chunk_begin, chunk_end));
315 }
316
317 // Reduce the results
318 ResultType final_result; // Default constructed (uninitialized)
319 try {
320 for (auto& fut : futures) {
321 ResultType partial_result = fut.get();
322 // Combine using the helper function which handles initialization state
323 final_result = combine_minmax(final_result, partial_result);
324 }
325 } catch (const std::exception& e) {
326 std::cerr << "Exception during parallel minmax reduction: " << e.what()
327 << '\n';
328 throw; // Rethrow for now
329 } catch (...) {
330 std::cerr << "Unknown exception during parallel minmax reduction.\n";
331 throw; // Rethrow for now
332 }
333
334 return final_result;
335}
336
337// For point_cloud_t (delegates to parallel container version)
338template<typename T>
339[[nodiscard]] auto calculate_minmax_parallel(const point_cloud_t<T>& input)
341{
342 return calculate_minmax_parallel(input.points);
343}
344
345} // namespace toolbox::types
包含点和相关数据的点云类 / A point cloud class containing points and associated data
Definition point.hpp:268
base::thread_pool_singleton_t & default_pool()
获取默认线程池实例/Get the default thread pool instance
Definition parallel.hpp:22
Definition minmax_impl.hpp:21
auto calculate_minmax(const InputType &input) -> std::enable_if_t<!detail::is_calculable_container_v< InputType >, minmax_t< std::decay_t< InputType > > >
计算非容器类型的最小最大值 / Calculate minmax for non-container type
Definition minmax_impl.hpp:173
minmax_t< T > combine_minmax(const minmax_t< T > &a, const minmax_t< T > &b)
合并两个minmax_t对象 / Combine two minmax_t objects
Definition minmax_impl.hpp:132
auto calculate_minmax_parallel(const InputType &input) -> std::enable_if_t<!detail::is_calculable_container_v< InputType >, minmax_t< std::decay_t< InputType > > >
并行计算非容器类型的最小最大值 / Calculate minmax for non-container type in parallel
Definition minmax_impl.hpp:227
存储和计算最小最大值的主模板类 / Primary template class for storing and calculating minimum and maximum values
Definition minmax.hpp:92
bool initialized_
是否已初始化 / Whether initialized
Definition minmax.hpp:95
T max
最大值 / Maximum value
Definition minmax.hpp:94
minmax_t()
默认构造函数 / Default constructor
Definition minmax_impl.hpp:27
minmax_t & operator+=(const T &value)
添加新值并更新最小最大值 / Add new value and update min/max
Definition minmax_impl.hpp:60
T min
最小值 / Minimum value
Definition minmax.hpp:93
3D点/向量模板类 / A 3D point/vector template class
Definition point.hpp:48
T x
X坐标 / X coordinate.
Definition point.hpp:51
T z
Z坐标 / Z coordinate.
Definition point.hpp:53
T y
Y坐标 / Y coordinate.
Definition point.hpp:52
std::size_t size_t
大小类型别名/Size type alias
Definition types.hpp:31