Ginkgo Generated from branch based on master. Ginkgo version 1.8.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
14#include <ginkgo/core/base/lin_op.hpp>
15#include <ginkgo/core/base/utils.hpp>
16
17
18namespace gko {
19namespace detail {
20
21
40template <typename CopyType, typename OrigType>
41class convert_back_deleter {
42public:
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
65private:
66 original_pointer original_;
67};
68
69// specialization for constant objects, no need to convert back something that
70// cannot change
71template <typename CopyType, typename OrigType>
72class convert_back_deleter<const CopyType, const OrigType> {
73public:
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
91template <typename TargetType>
92struct 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
120template <typename... ConversionCandidates>
121struct 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
170template <>
171struct 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
194template <typename T>
195class temporary_conversion {
196public:
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
239private:
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_
The Ginkgo namespace.
Definition abstract_factory.hpp:20