Ginkgo  Generated from pipelines/2662685947 branch based on develop. Ginkgo version 2.0.0
A numerical linear algebra library targeting many-core architectures
utils_helper.hpp
1 // SPDX-FileCopyrightText: 2017 - 2026 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_UTILS_HELPER_HPP_
6 #define GKO_PUBLIC_CORE_BASE_UTILS_HELPER_HPP_
7 
8 
9 #include <functional>
10 #include <memory>
11 #include <type_traits>
12 
13 #include <ginkgo/core/base/exception.hpp>
14 #include <ginkgo/core/base/name_demangling.hpp>
15 #include <ginkgo/core/base/types.hpp>
16 
17 
18 #ifndef NDEBUG
19 #include <cstdio>
20 #endif // NDEBUG
21 
22 
23 namespace gko {
24 
25 
26 class Executor;
27 
28 class Cloneable;
29 
30 
42 template <typename T>
43 class ptr_param {
44 public:
46  ptr_param(T* ptr) : ptr_{ptr} {}
47 
49  template <typename U,
50  std::enable_if_t<std::is_base_of<T, U>::value>* = nullptr>
51  ptr_param(const std::shared_ptr<U>& ptr) : ptr_param{ptr.get()}
52  {}
53 
55  template <typename U, typename Deleter,
56  std::enable_if_t<std::is_base_of<T, U>::value>* = nullptr>
57  ptr_param(const std::unique_ptr<U, Deleter>& ptr) : ptr_param{ptr.get()}
58  {}
59 
61  template <typename U,
62  std::enable_if_t<std::is_base_of<T, U>::value>* = nullptr>
63  ptr_param(const ptr_param<U>& ptr) : ptr_param{ptr.get()}
64  {}
65 
66  ptr_param(const ptr_param&) = default;
67 
68  ptr_param(ptr_param&&) = default;
69 
71  T& operator*() const { return *ptr_; }
72 
74  T* operator->() const { return ptr_; }
75 
77  T* get() const { return ptr_; }
78 
80  explicit operator bool() const { return ptr_; }
81 
82  ptr_param& operator=(const ptr_param&) = delete;
83 
84  ptr_param& operator=(ptr_param&&) = delete;
85 
86 private:
87  T* ptr_;
88 };
89 
90 
91 namespace detail {
92 
93 
94 template <typename T>
95 using pointee =
96  std::remove_reference_t<decltype(*std::declval<std::decay_t<T>>())>;
97 
98 
99 template <typename T, typename = void>
100 struct has_clone_impl : std::false_type {};
101 
102 template <typename T>
103 struct has_clone_impl<T, std::void_t<decltype(std::declval<T>().clone())>>
104  : std::true_type {};
105 
106 template <typename T>
107 constexpr bool is_cloneable()
108 {
109  return has_clone_impl<std::decay_t<T>>::value;
110 }
111 
112 
113 template <typename T, typename = void>
114 struct has_clone_to_impl : std::false_type {};
115 
116 template <typename T>
117 struct has_clone_to_impl<T,
118  std::void_t<decltype(std::declval<T>().clone(
119  std::declval<std::shared_ptr<const Executor>>()))>>
120  : std::true_type {};
121 
122 template <typename T>
123 constexpr bool has_clone_to()
124 {
125  return has_clone_to_impl<std::decay_t<T>>::value;
126 }
127 
128 
129 template <typename T>
130 struct have_ownership_impl : std::false_type {};
131 
132 template <typename T, typename Deleter>
133 struct have_ownership_impl<std::unique_ptr<T, Deleter>> : std::true_type {};
134 
135 template <typename T>
136 struct have_ownership_impl<std::shared_ptr<T>> : std::true_type {};
137 
138 template <typename T>
139 using have_ownership_s = have_ownership_impl<std::decay_t<T>>;
140 
141 template <typename T>
142 constexpr bool have_ownership()
143 {
144  return have_ownership_s<T>::value;
145 }
146 
147 
148 template <typename Pointer>
149 using cloned_type =
150  std::unique_ptr<typename std::remove_cv<pointee<Pointer>>::type>;
151 
152 
153 template <typename Pointer>
154 using shared_type = std::shared_ptr<pointee<Pointer>>;
155 
156 
157 } // namespace detail
158 
159 
173 template <typename OwningPointer>
174 inline detail::shared_type<OwningPointer> share(OwningPointer&& p)
175 {
176  static_assert(detail::have_ownership<OwningPointer>(),
177  "OwningPointer does not have ownership of the object");
178  static_assert(std::is_rvalue_reference<decltype(p)>::value,
179  "p must be an rvalue for this function to work");
180  return detail::shared_type<OwningPointer>(std::move(p));
181 }
182 
183 
196 template <typename OwningPointer>
197 inline typename std::remove_reference<OwningPointer>::type&& give(
198  OwningPointer&& p)
199 {
200  static_assert(detail::have_ownership<OwningPointer>(),
201  "OwningPointer does not have ownership of the object");
202  return std::move(p);
203 }
204 
205 
216 template <typename Pointer>
217 GKO_DEPRECATED("no longer necessary, just pass the object without lend")
218 inline typename std::enable_if<detail::have_ownership_s<Pointer>::value,
219  detail::pointee<Pointer>*>::type
220  lend(const Pointer& p)
221 {
222  return p.get();
223 }
224 
235 template <typename Pointer>
236 GKO_DEPRECATED("no longer necessary, just pass the object without lend")
237 inline typename std::enable_if<!detail::have_ownership_s<Pointer>::value,
238  detail::pointee<Pointer>*>::type
239  lend(const Pointer& p)
240 {
241  return p;
242 }
243 
244 
256 template <typename T, typename U>
257 inline std::decay_t<T>* as(U* obj)
258 {
259  if (auto p = dynamic_cast<std::decay_t<T>*>(obj)) {
260  return p;
261  } else {
262  throw NotSupported(__FILE__, __LINE__,
263  std::string{"gko::as<"} +
264  name_demangling::get_type_name(typeid(T)) + ">",
265  name_demangling::get_type_name(typeid(*obj)));
266  }
267 }
268 
282 template <typename T, typename U>
283 inline const std::decay_t<T>* as(const U* obj)
284 {
285  if (auto p = dynamic_cast<const std::decay_t<T>*>(obj)) {
286  return p;
287  } else {
288  throw NotSupported(__FILE__, __LINE__,
289  std::string{"gko::as<"} +
290  name_demangling::get_type_name(typeid(T)) + ">",
291  name_demangling::get_type_name(typeid(*obj)));
292  }
293 }
294 
295 
307 template <typename T, typename U>
308 inline std::decay_t<T>* as(ptr_param<U> obj)
309 {
310  return as<T>(obj.get());
311 }
312 
326 template <typename T, typename U>
327 inline const std::decay_t<T>* as(ptr_param<const U> obj)
328 {
329  return as<T>(obj.get());
330 }
331 
332 
345 template <typename T, typename U>
346 inline std::unique_ptr<std::decay_t<T>> as(std::unique_ptr<U>&& obj)
347 {
348  if (auto p = dynamic_cast<std::decay_t<T>*>(obj.get())) {
349  obj.release();
350  return std::unique_ptr<std::decay_t<T>>{p};
351  } else {
352  throw NotSupported(__FILE__, __LINE__, __func__,
353  name_demangling::get_type_name(typeid(*obj)));
354  }
355 }
356 
357 
369 template <typename T, typename U>
370 inline std::shared_ptr<std::decay_t<T>> as(std::shared_ptr<U> obj)
371 {
372  auto ptr = std::dynamic_pointer_cast<std::decay_t<T>>(obj);
373  if (ptr) {
374  return ptr;
375  } else {
376  throw NotSupported(__FILE__, __LINE__, __func__,
377  name_demangling::get_type_name(typeid(*obj)));
378  }
379 }
380 
381 
395 template <typename T, typename U>
396 inline std::shared_ptr<const std::decay_t<T>> as(std::shared_ptr<const U> obj)
397 {
398  auto ptr = std::dynamic_pointer_cast<const std::decay_t<T>>(obj);
399  if (ptr) {
400  return ptr;
401  } else {
402  throw NotSupported(__FILE__, __LINE__, __func__,
403  name_demangling::get_type_name(typeid(*obj)));
404  }
405 }
406 
407 
422 template <typename Pointer,
423  std::enable_if_t<detail::is_cloneable<detail::pointee<Pointer>>()>* =
424  nullptr>
425 inline detail::cloned_type<Pointer> clone(const Pointer& p)
426 {
427  return detail::cloned_type<Pointer>(
428  static_cast<typename std::remove_cv<detail::pointee<Pointer>>::type*>(
429  p->clone().release()));
430 }
431 
435 template <typename Pointer,
436  std::enable_if_t<!detail::is_cloneable<detail::pointee<Pointer>>()>* =
437  nullptr>
438 inline detail::cloned_type<Pointer> clone(const Pointer& p)
439 {
440  using type = typename std::remove_cv<detail::pointee<Pointer>>::type;
441  // wrap it into ptr_param to accept different type of pointer
442  return detail::cloned_type<Pointer>(dynamic_cast<type*>(
443  as<Cloneable>(ptr_param<const type>(p).get())->clone().release()));
444 }
445 
446 
462 template <typename Pointer,
463  std::enable_if_t<detail::has_clone_to<detail::pointee<Pointer>>()>* =
464  nullptr>
465 inline detail::cloned_type<Pointer> clone(std::shared_ptr<const Executor> exec,
466  const Pointer& p)
467 {
468  return detail::cloned_type<Pointer>(
469  static_cast<typename std::remove_cv<detail::pointee<Pointer>>::type*>(
470  p->clone(std::move(exec)).release()));
471 }
472 
476 template <typename Pointer,
477  std::enable_if_t<!detail::has_clone_to<detail::pointee<Pointer>>()>* =
478  nullptr>
479 inline detail::cloned_type<Pointer> clone(std::shared_ptr<const Executor> exec,
480  const Pointer& p)
481 {
482  using type = typename std::remove_cv<detail::pointee<Pointer>>::type;
483  // wrap it into ptr_param to accept different type of pointer
484  return detail::cloned_type<Pointer>(
485  dynamic_cast<type*>(as<Cloneable>(ptr_param<const type>(p).get())
486  ->clone(std::move(exec))
487  .release()));
488 }
489 
496 template <typename T>
498 public:
499  using pointer = T*;
500 
506  void operator()(pointer) const noexcept {}
507 };
508 
509 // a specialization for arrays
510 template <typename T>
511 class null_deleter<T[]> {
512 public:
513  using pointer = T[];
514 
515  void operator()(pointer) const noexcept {}
516 };
517 
518 
519 } // namespace gko
520 
521 
522 #endif // GKO_PUBLIC_CORE_BASE_UTILS_HELPER_HPP_
gko::ptr_param::ptr_param
ptr_param(const std::unique_ptr< U, Deleter > &ptr)
Initializes the ptr_param from a unique_ptr.
Definition: utils_helper.hpp:57
gko::give
std::remove_reference< OwningPointer >::type && give(OwningPointer &&p)
Marks that the object pointed to by p can be given to the callee.
Definition: utils_helper.hpp:197
gko::ptr_param::ptr_param
ptr_param(const ptr_param< U > &ptr)
Initializes the ptr_param from a ptr_param of a derived type.
Definition: utils_helper.hpp:63
gko::ptr_param::operator->
T * operator->() const
Definition: utils_helper.hpp:74
gko::null_deleter
This is a deleter that does not delete the object.
Definition: utils_helper.hpp:497
gko::ptr_param::operator*
T & operator*() const
Definition: utils_helper.hpp:71
gko::null_deleter::operator()
void operator()(pointer) const noexcept
Deletes the object.
Definition: utils_helper.hpp:506
gko::ptr_param::get
T * get() const
Definition: utils_helper.hpp:77
gko::ptr_param::ptr_param
ptr_param(const std::shared_ptr< U > &ptr)
Initializes the ptr_param from a shared_ptr.
Definition: utils_helper.hpp:51
gko::NotSupported
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition: exception.hpp:127
gko::clone
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition: utils_helper.hpp:425
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::as
std::decay_t< T > * as(U *obj)
Performs polymorphic type conversion.
Definition: utils_helper.hpp:257
gko::ptr_param
This class is used for function parameters in the place of raw pointers.
Definition: utils_helper.hpp:43
gko::share
detail::shared_type< OwningPointer > share(OwningPointer &&p)
Marks the object pointed to by p as shared.
Definition: utils_helper.hpp:174
gko::lend
std::enable_if< detail::have_ownership_s< Pointer >::value, detail::pointee< Pointer > * >::type lend(const Pointer &p)
Returns a non-owning (plain) pointer to the object pointed to by p.
Definition: utils_helper.hpp:220
gko::xstd::void_t
typename detail::make_void< Ts... >::type void_t
Use the custom implementation, since the std::void_t used in is_matrix_type_builder seems to trigger ...
Definition: std_extensions.hpp:47
gko::ptr_param::ptr_param
ptr_param(T *ptr)
Initializes the ptr_param from a raw pointer.
Definition: utils_helper.hpp:46