Ginkgo  Generated from pipelines/1330831941 branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
temporary_conversion.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_TEMPORARY_CONVERSION_HPP_
6 #define GKO_PUBLIC_CORE_BASE_TEMPORARY_CONVERSION_HPP_
7 
8 
9 #include <memory>
10 #include <tuple>
11 #include <type_traits>
12 
13 
14 #include <ginkgo/core/base/lin_op.hpp>
15 #include <ginkgo/core/base/utils.hpp>
16 
17 
18 namespace gko {
19 namespace detail {
20 
21 
40 template <typename CopyType, typename OrigType>
41 class convert_back_deleter {
42 public:
43  using pointer = CopyType*;
44  using original_pointer = OrigType*;
45 
52  convert_back_deleter(original_pointer original) : original_{original} {}
53 
59  void operator()(pointer ptr) const
60  {
61  ptr->convert_to(original_);
62  delete ptr;
63  }
64 
65 private:
66  original_pointer original_;
67 };
68 
69 // specialization for constant objects, no need to convert back something that
70 // cannot change
71 template <typename CopyType, typename OrigType>
72 class convert_back_deleter<const CopyType, const OrigType> {
73 public:
74  using pointer = const CopyType*;
75  using original_pointer = const OrigType*;
76  convert_back_deleter(original_pointer) {}
77 
78  void operator()(pointer ptr) const { delete ptr; }
79 };
80 
81 
91 template <typename TargetType>
92 struct conversion_target_helper {
100  template <typename SourceType,
101  typename = std::enable_if_t<std::is_base_of<
102  ConvertibleTo<TargetType>, SourceType>::value>>
103  static std::unique_ptr<TargetType> create_empty(const SourceType* source)
104  {
105  return TargetType::create(source->get_executor());
106  }
107 };
108 
109 
120 template <typename... ConversionCandidates>
121 struct conversion_helper {
123  template <typename TargetType, typename MaybeConstLinOp>
124  static std::unique_ptr<TargetType, std::function<void(TargetType*)>>
125  convert(MaybeConstLinOp* obj)
126  {
127  return convert_impl<TargetType, MaybeConstLinOp,
128  ConversionCandidates...>(obj);
129  }
130 
136  template <typename TargetType, typename MaybeConstLinOp,
137  typename FirstCandidate, typename... TrailingCandidates>
138  static std::unique_ptr<TargetType, std::function<void(TargetType*)>>
139  convert_impl(MaybeConstLinOp* obj)
140  {
141  // make candidate_type conditionally const based on whether obj is const
142  using candidate_type =
143  std::conditional_t<std::is_const<MaybeConstLinOp>::value,
144  const FirstCandidate, FirstCandidate>;
145  candidate_type* cast_obj{};
146  if ((cast_obj = dynamic_cast<candidate_type*>(obj))) {
147  // if the cast is successful, obj is of dynamic type candidate_type
148  // so we can convert from this type to TargetType
149  auto converted = conversion_target_helper<
150  std::remove_cv_t<TargetType>>::create_empty(cast_obj);
151  cast_obj->convert_to(converted);
152  // Make sure ConvertibleTo<TargetType> is available and symmetric
153  static_assert(
154  std::is_base_of<ConvertibleTo<std::remove_cv_t<TargetType>>,
155  FirstCandidate>::value,
156  "ConvertibleTo not implemented");
157  static_assert(std::is_base_of<ConvertibleTo<FirstCandidate>,
158  TargetType>::value,
159  "ConvertibleTo not symmetric");
160  return {converted.release(),
161  convert_back_deleter<TargetType, candidate_type>{cast_obj}};
162  } else {
163  // else try the remaining candidates
164  return conversion_helper<TrailingCandidates...>::template convert<
165  TargetType>(obj);
166  }
167  }
168 };
169 
170 template <>
171 struct conversion_helper<> {
172  template <typename T, typename MaybeConstLinOp>
173  static std::unique_ptr<T, std::function<void(T*)>> convert(
174  MaybeConstLinOp* obj)
175  {
176  // return nullptr if no previous candidates matched
177  return {nullptr, null_deleter<T>{}};
178  }
179 };
180 
181 
194 template <typename T>
195 class temporary_conversion {
196 public:
197  using value_type = T;
198  using pointer = T*;
199  using lin_op_type =
200  std::conditional_t<std::is_const<T>::value, const LinOp, LinOp>;
201 
208  template <typename... ConversionCandidates>
209  static temporary_conversion create(ptr_param<lin_op_type> ptr)
210  {
211  T* cast_ptr{};
212  if ((cast_ptr = dynamic_cast<T*>(ptr.get()))) {
213  return handle_type{cast_ptr, null_deleter<T>{}};
214  } else {
215  return conversion_helper<ConversionCandidates...>::template convert<
216  T>(ptr.get());
217  }
218  }
219 
225  T* get() const { return handle_.get(); }
226 
232  T* operator->() const { return handle_.get(); }
233 
237  explicit operator bool() { return static_cast<bool>(handle_); }
238 
239 private:
240  // std::function deleter allows to decide the (type of) deleter at
241  // runtime
242  using handle_type = std::unique_ptr<T, std::function<void(T*)>>;
243 
244  temporary_conversion(handle_type handle) : handle_{std::move(handle)} {}
245 
246  handle_type handle_;
247 };
248 
249 
250 } // namespace detail
251 } // namespace gko
252 
253 
254 #endif // GKO_PUBLIC_CORE_BASE_TEMPORARY_CONVERSION_HPP_
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20