Ginkgo Generated from branch based on main. Ginkgo version 1.9.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
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
17namespace gko {
18namespace detail {
19
20
39template <typename CopyType, typename OrigType>
40class convert_back_deleter {
41public:
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
64private:
65 original_pointer original_;
66};
67
68// specialization for constant objects, no need to convert back something that
69// cannot change
70template <typename CopyType, typename OrigType>
71class convert_back_deleter<const CopyType, const OrigType> {
72public:
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
90template <typename TargetType>
91struct 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
119template <typename... ConversionCandidates>
120struct 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
169template <>
170struct 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
193template <typename T>
194class temporary_conversion {
195public:
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
238private:
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_
The Ginkgo namespace.
Definition abstract_factory.hpp:20
STL namespace.