Ginkgo  Generated from tags/v1.0.0^0 branch based on master. Ginkgo version 1.0.0
A numerical linear algebra library targeting many-core architectures
utils.hpp
1 /*******************************<GINKGO LICENSE>******************************
2 Copyright (c) 2017-2019, the Ginkgo authors
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ******************************<GINKGO LICENSE>*******************************/
32 
33 #ifndef GKO_CORE_BASE_UTILS_HPP_
34 #define GKO_CORE_BASE_UTILS_HPP_
35 
36 
37 #include <ginkgo/core/base/exception.hpp>
38 #include <ginkgo/core/base/std_extensions.hpp>
39 #include <ginkgo/core/base/types.hpp>
40 
41 
42 #include <functional>
43 #include <memory>
44 #include <type_traits>
45 
46 
47 #ifndef NDEBUG
48 #include <cstdio>
49 #endif // NDEBUG
50 
51 
52 namespace gko {
53 
54 
55 class Executor;
56 
57 
58 namespace detail {
59 
60 
61 template <typename T>
62 struct pointee_impl {};
63 
64 template <typename T>
65 struct pointee_impl<T *> {
66  using type = T;
67 };
68 
69 template <typename T, typename Deleter>
70 struct pointee_impl<std::unique_ptr<T, Deleter>> {
71  using type = T;
72 };
73 
74 template <typename T>
75 struct pointee_impl<std::shared_ptr<T>> {
76  using type = T;
77 };
78 
79 template <typename T>
80 using pointee = typename pointee_impl<typename std::decay<T>::type>::type;
81 
82 
83 template <typename T, typename = void>
84 struct is_clonable_impl : std::false_type {};
85 
86 template <typename T>
87 struct is_clonable_impl<T, xstd::void_t<decltype(std::declval<T>().clone())>>
88  : std::true_type {};
89 
90 template <typename T>
91 constexpr bool is_clonable()
92 {
93  return is_clonable_impl<typename std::decay<T>::type>::value;
94 }
95 
96 
97 template <typename T, typename = void>
98 struct is_clonable_to_impl : std::false_type {};
99 
100 template <typename T>
101 struct is_clonable_to_impl<
102  T, xstd::void_t<decltype(std::declval<T>().clone(
103  std::declval<std::shared_ptr<const Executor>>()))>>
104  : std::true_type {};
105 
106 template <typename T>
107 constexpr bool is_clonable_to()
108 {
109  return is_clonable_to_impl<typename std::decay<T>::type>::value;
110 }
111 
112 
113 template <typename T>
114 struct have_ownership_impl : std::false_type {};
115 
116 template <typename T, typename Deleter>
117 struct have_ownership_impl<std::unique_ptr<T, Deleter>> : std::true_type {};
118 
119 template <typename T>
120 struct have_ownership_impl<std::shared_ptr<T>> : std::true_type {};
121 
122 template <typename T>
123 constexpr bool have_ownership()
124 {
125  return have_ownership_impl<typename std::decay<T>::type>::value;
126 }
127 
128 
129 template <typename Pointer>
130 using cloned_type =
131  std::unique_ptr<typename std::remove_cv<pointee<Pointer>>::type>;
132 
133 
134 template <typename Pointer>
135 using shared_type = std::shared_ptr<pointee<Pointer>>;
136 
137 
138 } // namespace detail
139 
140 
155 template <typename Pointer>
156 inline detail::cloned_type<Pointer> clone(const Pointer &p)
157 {
158  static_assert(detail::is_clonable<detail::pointee<Pointer>>(),
159  "Object is not clonable");
160  return detail::cloned_type<Pointer>(
161  static_cast<typename std::remove_cv<detail::pointee<Pointer>>::type *>(
162  p->clone().release()));
163 }
164 
165 
181 template <typename Pointer>
182 inline detail::cloned_type<Pointer> clone(std::shared_ptr<const Executor> exec,
183  const Pointer &p)
184 {
185  static_assert(detail::is_clonable_to<detail::pointee<Pointer>>(),
186  "Object is not clonable");
187  return detail::cloned_type<Pointer>(
188  static_cast<typename std::remove_cv<detail::pointee<Pointer>>::type *>(
189  p->clone(std::move(exec)).release()));
190 }
191 
192 
205 template <typename OwningPointer>
206 inline detail::shared_type<OwningPointer> share(OwningPointer &&p)
207 {
208  static_assert(detail::have_ownership<OwningPointer>(),
209  "OwningPointer does not have ownership of the object");
210  return detail::shared_type<OwningPointer>(std::move(p));
211 }
212 
213 
226 template <typename OwningPointer>
227 inline typename std::remove_reference<OwningPointer>::type &&give(
228  OwningPointer &&p)
229 {
230  static_assert(detail::have_ownership<OwningPointer>(),
231  "OwningPointer does not have ownership of the object");
232  return std::move(p);
233 }
234 
235 
246 template <typename Pointer>
247 inline typename std::enable_if<detail::have_ownership<Pointer>(),
248  detail::pointee<Pointer> *>::type
249 lend(const Pointer &p)
250 {
251  return p.get();
252 }
253 
264 template <typename Pointer>
265 inline typename std::enable_if<!detail::have_ownership<Pointer>(),
266  detail::pointee<Pointer> *>::type
267 lend(const Pointer &p)
268 {
269  return p;
270 }
271 
272 
284 template <typename T, typename U>
285 inline typename std::decay<T>::type *as(U *obj)
286 {
287  if (auto p = dynamic_cast<typename std::decay<T>::type *>(obj)) {
288  return p;
289  } else {
290  throw NotSupported(__FILE__, __LINE__, __func__, typeid(obj).name());
291  }
292 }
293 
307 template <typename T, typename U>
308 inline const typename std::decay<T>::type *as(const U *obj)
309 {
310  if (auto p = dynamic_cast<const typename std::decay<T>::type *>(obj)) {
311  return p;
312  } else {
313  throw NotSupported(__FILE__, __LINE__, __func__, typeid(obj).name());
314  }
315 }
316 
317 
324 template <typename T>
326 public:
327  using pointer = T *;
328 
334  void operator()(pointer) const noexcept {}
335 };
336 
337 // a specialization for arrays
338 template <typename T>
339 class null_deleter<T[]> {
340 public:
341  using pointer = T[];
342 
343  void operator()(pointer) const noexcept {}
344 };
345 
346 
361 template <typename T>
363 public:
364  using pointer = T *;
365 
372  copy_back_deleter(pointer original) : original_{original} {}
373 
379  void operator()(pointer ptr) const
380  {
381  original_->copy_from(ptr);
382  delete ptr;
383  }
384 
385 private:
386  pointer original_;
387 };
388 
389 
390 // specialization for constant objects, no need to copy back something that
391 // cannot change
392 template <typename T>
393 class copy_back_deleter<const T> {
394 public:
395  using pointer = const T *;
396  copy_back_deleter(pointer original) : original_{original} {}
397 
398  void operator()(pointer ptr) const { delete ptr; }
399 
400 private:
401  pointer original_;
402 };
403 
404 
416 template <typename T>
418 public:
419  using value_type = T;
420  using pointer = T *;
421 
428  explicit temporary_clone(std::shared_ptr<const Executor> exec, pointer ptr)
429  {
430  if (ptr->get_executor() == exec) {
431  // just use the object we already have
432  handle_ = handle_type(ptr, [](pointer) {});
433  } else {
434  // clone the object to the new executor and make sure it's copied
435  // back before we delete it
436  handle_ = handle_type(gko::clone(std::move(exec), ptr).release(),
437  copy_back_deleter<T>(ptr));
438  }
439  }
440 
446  T *get() const { return handle_.get(); }
447 
453  T *operator->() const { return handle_.get(); }
454 
455 private:
456  // std::function deleter allows to decide the (type of) deleter at runtime
457  using handle_type = std::unique_ptr<T, std::function<void(T *)>>;
458 
459  handle_type handle_;
460 };
461 
462 
473 template <typename T>
474 temporary_clone<T> make_temporary_clone(std::shared_ptr<const Executor> exec,
475  T *ptr)
476 {
477  return temporary_clone<T>(std::move(exec), ptr);
478 }
479 
480 
481 } // namespace gko
482 
483 
484 #endif // GKO_CORE_BASE_UTILS_HPP_
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition: utils.hpp:156
temporary_clone(std::shared_ptr< const Executor > exec, pointer ptr)
Creates a temporary_clone.
Definition: utils.hpp:428
STL namespace.
void operator()(pointer ptr) const
Deletes the object.
Definition: utils.hpp:379
A copy_back_deleter is a type of deleter that copies the data to an internally referenced object befo...
Definition: utils.hpp:362
The Ginkgo namespace.
Definition: abstract_factory.hpp:45
T * operator->() const
Calls a method on the underlying object.
Definition: utils.hpp:453
detail::shared_type< OwningPointer > share(OwningPointer &&p)
Marks the object pointed to by p as shared.
Definition: utils.hpp:206
This is a deleter that does not delete the object.
Definition: utils.hpp:325
std::remove_reference< OwningPointer >::type && give(OwningPointer &&p)
Marks that the object pointed to by p can be given to the callee.
Definition: utils.hpp:227
std::enable_if< detail::have_ownership< Pointer >), detail::pointee< Pointer > * >::type lend(const Pointer &p)
Returns a non-owning (plain) pointer to the object pointed to by p.
Definition: utils.hpp:249
void operator()(pointer) const noexcept
Deletes the object.
Definition: utils.hpp:334
std::decay< T >::type * as(U *obj)
Performs polymorphic type conversion.
Definition: utils.hpp:285
copy_back_deleter(pointer original)
Creates a new deleter object.
Definition: utils.hpp:372
A temporary_clone is a special smart pointer-like object that is designed to hold an object temporari...
Definition: utils.hpp:417
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition: exception.hpp:153
temporary_clone< T > make_temporary_clone(std::shared_ptr< const Executor > exec, T *ptr)
Creates a temporary_clone.
Definition: utils.hpp:474