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