misc.hpp
1 
5 #pragma once
6 
7 #include <algorithm>
8 #include <chrono>
9 #include <cmath>
10 #include <concepts>
11 #include <cstdlib>
12 #include <functional>
13 #include <memory>
14 #include <ranges>
15 #include <source_location>
16 #include <stdexcept>
17 #include <type_traits>
18 #include <utility>
19 #include <vector>
20 
21 #include <cuda_runtime_api.h>
22 
23 namespace rapidsmpf {
24 
30 #define RAPIDSMPF_CUDA_VERSION_AT_LEAST(version) (CUDART_VERSION >= version)
31 
33 using Clock = std::chrono::high_resolution_clock;
35 using Duration = std::chrono::duration<double>;
37 using TimePoint = std::chrono::time_point<Clock, Duration>;
38 
51 template <typename MapType>
52 std::pair<typename MapType::key_type, typename MapType::mapped_type> extract_item(
53  MapType& map, typename MapType::const_iterator position
54 ) {
55  auto node = map.extract(position);
56  if (!node) {
57  throw std::out_of_range("Invalid iterator passed to extract");
58  }
59  return {std::move(node.key()), std::move(node.mapped())};
60 }
61 
72 template <typename MapType>
73 std::pair<typename MapType::key_type, typename MapType::mapped_type> extract_item(
74  MapType& map, typename MapType::key_type const& key
75 ) {
76  auto node = map.extract(key);
77  if (!node) {
78  throw std::out_of_range("Invalid key passed to extract");
79  }
80  return {std::move(node.key()), std::move(node.mapped())};
81 }
82 
94 template <typename MapType>
95 typename MapType::mapped_type extract_value(
96  MapType& map, typename MapType::key_type const& key
97 ) {
98  return std::move(extract_item(map, key).second);
99 }
100 
114 template <typename MapType>
115 typename MapType::mapped_type extract_value(
116  MapType& map, typename MapType::const_iterator position
117 ) {
118  return std::move(extract_item(map, position).second);
119 }
120 
131 template <typename MapType>
132 typename MapType::key_type extract_key(
133  MapType& map, typename MapType::key_type const& key
134 ) {
135  return std::move(extract_item(map, key).first);
136 }
137 
150 template <typename MapType>
151 typename MapType::key_type extract_key(
152  MapType& map, typename MapType::const_iterator position
153 ) {
154  return std::move(extract_item(map, position).first);
155 }
156 
167 template <typename MapType>
168 auto to_vector(MapType&& map) {
169  using ValueType = typename std::remove_reference_t<MapType>::mapped_type;
170  std::vector<ValueType> vec;
171  vec.reserve(map.size());
172  for (auto&& [key, value] : map) {
173  vec.push_back(std::move(value));
174  }
175  return vec;
176 }
177 
184 
193 template <typename T>
194 constexpr T safe_div(T x, T y) {
195  return (y == 0) ? 0 : x / y;
196 }
197 
210 template <std::integral T>
211 constexpr T ceil_div(T x, T y) {
212  return x / y + (x % y != 0 ? T{1} : T{0});
213 }
214 
231 [[nodiscard]] inline auto chunk_indices(std::size_t count, std::size_t num_chunks) {
232  std::size_t const chunk_size = ceil_div(count, num_chunks);
233  return std::views::iota(std::size_t{0}, num_chunks)
234  | std::views::transform([count, chunk_size](std::size_t k) {
235  return std::pair<std::size_t, std::size_t>{
236  std::min(k * chunk_size, count),
237  std::min((k + 1) * chunk_size, count)
238  };
239  });
240 }
241 
242 // Macro to concatenate two tokens x and y.
243 #define RAPIDSMPF_CONCAT_DETAIL_(x, y) x##y
244 #define RAPIDSMPF_CONCAT(x, y) RAPIDSMPF_CONCAT_DETAIL_(x, y)
245 
246 // Stringify a macro argument.
247 #define RAPIDSMPF_STRINGIFY_DETAIL_(x) #x
248 #define RAPIDSMPF_STRINGIFY(x) RAPIDSMPF_STRINGIFY_DETAIL_(x)
249 
266 #define RAPIDSMPF_OVERLOAD_BY_ARG_COUNT(_1, _2, NAME, ...) NAME
267 
268 namespace detail {
269 
279 template <typename T>
280 constexpr T* to_pointer(T* ptr) noexcept {
281  return ptr;
282 }
283 
285 template <typename T>
286 constexpr T* to_pointer(T& ptr) noexcept {
287  return std::addressof(ptr);
288 }
289 
291 template <typename T>
292 constexpr T* to_pointer(std::unique_ptr<T>& ptr) noexcept {
293  return ptr.get();
294 }
295 
297 template <typename T>
298 constexpr T* to_pointer(std::shared_ptr<T>& ptr) noexcept {
299  return ptr.get();
300 }
301 
302 } // namespace detail
303 
305 template <class... Ts>
306 struct overloaded : Ts... {
307  using Ts::operator()...;
308 };
309 
326 template <std::ranges::input_range R, typename T, typename Proj = std::identity>
327 [[nodiscard]] constexpr bool contains(R&& range, T const& value, Proj proj = {}) {
328  for (auto const& elem : range) {
329  if (std::invoke(proj, elem) == value) {
330  return true;
331  }
332  }
333  return false;
334 }
335 
342 template <typename T>
343 concept SharedOrWeakPtr = requires {
344  typename T::element_type;
345  requires std::same_as<T, std::shared_ptr<typename T::element_type>>
346  || std::same_as<T, std::weak_ptr<typename T::element_type>>;
347 };
348 
366 template <SharedOrWeakPtr A, SharedOrWeakPtr B>
367  requires std::same_as<typename A::element_type, typename B::element_type>
368 [[nodiscard]] constexpr bool owner_equal(A const& a, B const& b) noexcept {
369  return !a.owner_before(b) && !b.owner_before(a);
370 }
371 
391 template <typename To, typename From>
392  requires std::is_arithmetic_v<To> && std::is_arithmetic_v<From>
393 constexpr To safe_cast(
394  From value, std::source_location const& loc = std::source_location::current()
395 ) {
396  if constexpr (std::is_same_v<From, To>) {
397  // Same type, no-op.
398  return value;
399  } else if constexpr (std::is_integral_v<From> && std::is_integral_v<To>) {
400  // Integer to integer.
401  if (!std::in_range<To>(value)) {
402  throw std::overflow_error(
403  "RapidsMPF cast error at: " + std::string(loc.file_name()) + ":"
404  + std::to_string(loc.line())
405  + ", value out of range (value=" + std::to_string(value) + ")"
406  );
407  }
408  return static_cast<To>(value);
409  } else {
410  // Floating point conversions: direct cast (well-defined overflow behavior).
411  return static_cast<To>(value);
412  }
413 }
414 
415 } // namespace rapidsmpf
constexpr T * to_pointer(T *ptr) noexcept
Returns the raw pointer from a pointer, reference, or smart pointer.
Definition: misc.hpp:280
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14
constexpr T ceil_div(T x, T y)
Computes the ceiling of the division of two integers.
Definition: misc.hpp:211
std::chrono::duration< double > Duration
Alias for a duration type representing time in seconds as a double.
Definition: misc.hpp:35
std::chrono::time_point< Clock, Duration > TimePoint
Alias for a time point with double precision in seconds.
Definition: misc.hpp:37
MapType::mapped_type extract_value(MapType &map, typename MapType::key_type const &key)
Extracts the value associated with a specific key from a map, removing the key-value pair.
Definition: misc.hpp:95
MapType::key_type extract_key(MapType &map, typename MapType::key_type const &key)
Extracts a key from a map, removing the key-value pair.
Definition: misc.hpp:132
bool is_running_under_valgrind()
Checks whether the application is running under Valgrind.
std::pair< typename MapType::key_type, typename MapType::mapped_type > extract_item(MapType &map, typename MapType::const_iterator position)
Extracts a key-value pair from a map, removing it from the map.
Definition: misc.hpp:52
auto chunk_indices(std::size_t count, std::size_t num_chunks)
Splits the index range [0, count) into exactly num_chunks contiguous chunks.
Definition: misc.hpp:231
concept SharedOrWeakPtr
Satisfied by specializations of std::shared_ptr and std::weak_ptr.
Definition: misc.hpp:343
constexpr T safe_div(T x, T y)
Performs safe division, returning 0 if the denominator is zero.
Definition: misc.hpp:194
std::chrono::high_resolution_clock Clock
Alias for high-resolution clock from the chrono library.
Definition: misc.hpp:33
requires constexpr std::same_as< typename A::element_type, typename B::element_type > bool owner_equal(A const &a, B const &b) noexcept
Backport of std::weak_ptr::owner_equal / std::owner_equal from C++26.
Definition: misc.hpp:368
constexpr bool contains(R &&range, T const &value, Proj proj={})
Backport of std::ranges::contains from C++23 for C++20.
Definition: misc.hpp:327
requires std::is_arithmetic_v< To > &&constexpr std::is_arithmetic_v< From > To safe_cast(From value, std::source_location const &loc=std::source_location::current())
Safely casts a numeric value to another type with overflow checking.
Definition: misc.hpp:393
auto to_vector(MapType &&map)
Converts a map-like associative container to a vector by moving the values and discarding the keys.
Definition: misc.hpp:168
Helper for overloaded lambdas using std::visit.
Definition: misc.hpp:306