Ginkgo  Generated from pipelines/2662685947 branch based on develop. Ginkgo version 2.0.0
A numerical linear algebra library targeting many-core architectures
polymorphic_object.hpp
1 // SPDX-FileCopyrightText: 2017 - 2026 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
6 #define GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
7 
8 
9 #include <memory>
10 #include <type_traits>
11 
12 #include <ginkgo/core/base/executor.hpp>
13 #include <ginkgo/core/base/utils.hpp>
14 #include <ginkgo/core/log/logger.hpp>
15 
16 
17 namespace gko {
18 namespace experimental {
19 namespace distributed {
20 
21 
22 class DistributedBase;
23 
24 
25 } // namespace distributed
26 } // namespace experimental
27 
28 
46 class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
47 public:
48  virtual ~PolymorphicObject()
49  {
50  this->template log<log::Logger::polymorphic_object_deleted>(exec_.get(),
51  this);
52  }
53 
54  // preserve the executor of the object
55  PolymorphicObject& operator=(const PolymorphicObject&) { return *this; }
56 
62  std::shared_ptr<const Executor> get_executor() const noexcept
63  {
64  return exec_;
65  }
66 
67 protected:
68  // This method is defined as protected since a polymorphic object should not
69  // be created using their constructor directly, but by creating an
70  // std::unique_ptr to it. Defining the constructor as protected keeps these
71  // access rights when inheriting the constructor.
77  explicit PolymorphicObject(std::shared_ptr<const Executor> exec)
78  : exec_{std::move(exec)}
79  {}
80 
81  // preserve the executor of the object
82  explicit PolymorphicObject(const PolymorphicObject& other)
83  {
84  *this = other;
85  }
86 
87 private:
88  std::shared_ptr<const Executor> exec_;
89 };
90 
91 
100 #define GKO_ENABLE_SELF(_type) \
101  _type* self() noexcept { return static_cast<_type*>(this); } \
102  \
103  const _type* self() const noexcept \
104  { \
105  return static_cast<const _type*>(this); \
106  }
107 
108 
139 template <typename ResultType>
141 public:
142  using result_type = ResultType;
143 
144  virtual ~ConvertibleTo() = default;
145 
151  virtual void convert_to(result_type* result) const = 0;
152 
153  void convert_to(ptr_param<result_type> result) const
154  {
155  convert_to(result.get());
156  }
157 
172  virtual void move_to(result_type* result) = 0;
173 
174  void move_to(ptr_param<result_type> result) { move_to(result.get()); }
175 };
176 
177 
178 namespace detail {
179 
180 
181 template <typename R, typename T>
182 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to_impl(
183  std::shared_ptr<const Executor> exec, T* obj)
184 {
185  auto obj_as_r = dynamic_cast<R*>(obj);
186  if (obj_as_r != nullptr && obj->get_executor() == exec) {
187  // FIXME: this breaks lifetimes
188  return {obj_as_r, [](R*) {}};
189  } else {
190  auto copy = R::create(exec);
191  as<ConvertibleTo<std::decay_t<R>>>(obj)->convert_to(copy);
192  return {copy.release(), std::default_delete<R>{}};
193  }
194 }
195 
196 
197 template <typename R, typename T>
198 std::shared_ptr<R> copy_and_convert_to_impl(
199  std::shared_ptr<const Executor> exec, std::shared_ptr<T> obj)
200 {
201  auto obj_as_r = std::dynamic_pointer_cast<R>(obj);
202  if (obj_as_r != nullptr && obj->get_executor() == exec) {
203  return obj_as_r;
204  } else {
205  auto copy = R::create(exec);
206  as<ConvertibleTo<std::decay_t<R>>>(obj.get())->convert_to(copy);
207  return {std::move(copy)};
208  }
209 }
210 
211 
212 } // namespace detail
213 
214 
231 template <typename R, typename T>
232 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to(
233  std::shared_ptr<const Executor> exec, T* obj)
234 {
235  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
236 }
237 
238 
245 template <typename R, typename T>
246 std::unique_ptr<const R, std::function<void(const R*)>> copy_and_convert_to(
247  std::shared_ptr<const Executor> exec, const T* obj)
248 {
249  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
250 }
251 
252 
270 template <typename R, typename T>
271 std::shared_ptr<R> copy_and_convert_to(std::shared_ptr<const Executor> exec,
272  std::shared_ptr<T> obj)
273 {
274  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
275 }
276 
277 
285 template <typename R, typename T>
286 std::shared_ptr<const R> copy_and_convert_to(
287  std::shared_ptr<const Executor> exec, std::shared_ptr<const T> obj)
288 {
289  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
290 }
291 
292 
298 class Cloneable {
299 public:
300  virtual ~Cloneable() = default;
301 
302  [[nodiscard]] std::unique_ptr<Cloneable> clone(
303  std::shared_ptr<const Executor> exec) const
304  {
305  return this->clone_impl(std::move(exec));
306  }
307 
308  [[nodiscard]] std::unique_ptr<Cloneable> clone() const
309  {
310  return this->clone_impl();
311  }
312 
313  Cloneable* copy_from(ptr_param<const Cloneable> other)
314  {
315  auto copied = this->copy_from_impl(other.get());
316  return copied;
317  }
318 
319  Cloneable* move_from(ptr_param<Cloneable> other)
320  {
321  auto moved = this->move_from_impl(other.get());
322  return moved;
323  }
324 
325  [[nodiscard]] std::unique_ptr<Cloneable> create_default(
326  std::shared_ptr<const Executor> exec) const
327  {
328  return this->create_default_impl(std::move(exec));
329  }
330 
331  [[nodiscard]] std::unique_ptr<Cloneable> create_default() const
332  {
333  return this->create_default_impl();
334  }
335 
336 protected:
337  virtual Cloneable* copy_from_impl(const Cloneable* other) = 0;
338 
339  virtual Cloneable* copy_from_impl(std::unique_ptr<Cloneable> other) = 0;
340 
341  virtual Cloneable* move_from_impl(Cloneable* other) = 0;
342 
343  virtual Cloneable* move_from_impl(std::unique_ptr<Cloneable> other) = 0;
344 
345  [[nodiscard]] virtual std::unique_ptr<Cloneable> clone_impl(
346  std::shared_ptr<const Executor> exec) const = 0;
347 
348  [[nodiscard]] virtual std::unique_ptr<Cloneable> clone_impl() const = 0;
349 
350  [[nodiscard]] virtual std::unique_ptr<Cloneable> create_default_impl()
351  const = 0;
352 
353  [[nodiscard]] virtual std::unique_ptr<Cloneable> create_default_impl(
354  std::shared_ptr<const Executor> exec) const = 0;
355 };
356 
357 
368 template <typename ConcreteType>
369 class EnableCloneable : public ConvertibleTo<ConcreteType>, public Cloneable {
370 public:
371  using result_type = ConcreteType;
374 
385  [[nodiscard]] std::unique_ptr<ConcreteType> clone(
386  std::shared_ptr<const Executor> exec) const
387  {
388  return as<ConcreteType>(this->clone_impl(std::move(exec)));
389  }
390 
399  [[nodiscard]] std::unique_ptr<ConcreteType> clone() const
400  {
401  return as<ConcreteType>(this->clone_impl());
402  }
403 
404  void convert_to(result_type* result) const override { *result = *self(); }
405 
406  void move_to(result_type* result) override { *result = std::move(*self()); }
407 
408  [[nodiscard]] std::unique_ptr<ConcreteType> create_default() const
409  {
410  return as<ConcreteType>(this->create_default_impl());
411  }
412 
413  [[nodiscard]] std::unique_ptr<ConcreteType> create_default(
414  std::shared_ptr<const Executor> exec) const
415  {
416  return as<ConcreteType>(this->create_default_impl(std::move(exec)));
417  }
418 
419 protected:
420  Cloneable* copy_from_impl(const Cloneable* other) override
421  {
422  self()->template log<log::Logger::polymorphic_object_copy_started>(
423  self()->get_executor().get(),
424  dynamic_cast<const PolymorphicObject*>(other),
425  dynamic_cast<const PolymorphicObject*>(this));
426  as<ConvertibleTo<ConcreteType>>(other)->convert_to(self());
427  self()->template log<log::Logger::polymorphic_object_copy_completed>(
428  self()->get_executor().get(),
429  dynamic_cast<const PolymorphicObject*>(other),
430  dynamic_cast<const PolymorphicObject*>(this));
431  return this;
432  }
433 
434  Cloneable* copy_from_impl(std::unique_ptr<Cloneable> other) override
435  {
436  self()->template log<log::Logger::polymorphic_object_copy_started>(
437  self()->get_executor().get(),
438  dynamic_cast<const PolymorphicObject*>(other.get()),
439  dynamic_cast<const PolymorphicObject*>(this));
440  as<ConvertibleTo<ConcreteType>>(other.get())->convert_to(self());
441  self()->template log<log::Logger::polymorphic_object_copy_completed>(
442  self()->get_executor().get(),
443  dynamic_cast<const PolymorphicObject*>(other.get()),
444  dynamic_cast<const PolymorphicObject*>(this));
445  return this;
446  }
447 
448  Cloneable* move_from_impl(Cloneable* other) override
449  {
450  self()->template log<log::Logger::polymorphic_object_move_started>(
451  self()->get_executor().get(),
452  dynamic_cast<const PolymorphicObject*>(other),
453  dynamic_cast<const PolymorphicObject*>(this));
454  as<ConvertibleTo<ConcreteType>>(other)->move_to(self());
455  self()->template log<log::Logger::polymorphic_object_move_completed>(
456  self()->get_executor().get(),
457  dynamic_cast<const PolymorphicObject*>(other),
458  dynamic_cast<const PolymorphicObject*>(this));
459  return this;
460  }
461 
462  Cloneable* move_from_impl(std::unique_ptr<Cloneable> other) override
463  {
464  self()->template log<log::Logger::polymorphic_object_move_started>(
465  self()->get_executor().get(),
466  dynamic_cast<const PolymorphicObject*>(other.get()),
467  dynamic_cast<const PolymorphicObject*>(this));
468  as<ConvertibleTo<ConcreteType>>(other.get())->move_to(self());
469  self()->template log<log::Logger::polymorphic_object_move_completed>(
470  self()->get_executor().get(),
471  dynamic_cast<const PolymorphicObject*>(other.get()),
472  dynamic_cast<const PolymorphicObject*>(this));
473  return this;
474  }
475 
476  [[nodiscard]] std::unique_ptr<Cloneable> clone_impl(
477  std::shared_ptr<const Executor> exec) const override
478  {
479  auto new_op = self()->create_default(exec);
480  new_op->copy_from(this);
481  return new_op;
482  }
483 
484  [[nodiscard]] std::unique_ptr<Cloneable> clone_impl() const override
485  {
486  return this->clone_impl(self()->get_executor());
487  }
488 
489  [[nodiscard]] std::unique_ptr<Cloneable> create_default_impl()
490  const override
491  {
492  return this->create_default_impl(self()->get_executor());
493  }
494 
495  [[nodiscard]] std::unique_ptr<Cloneable> create_default_impl(
496  std::shared_ptr<const Executor> exec) const override
497  {
498  if constexpr (std::is_base_of_v<
499  experimental::distributed::DistributedBase,
500  ConcreteType>) {
501  return std::unique_ptr<ConcreteType>(
502  new ConcreteType(std::move(exec), self()->get_communicator()));
503  } else {
504  return std::unique_ptr<ConcreteType>(
505  new ConcreteType(std::move(exec)));
506  }
507  }
508 
509  GKO_ENABLE_SELF(ConcreteType);
510 };
511 
512 
521 template <typename ConcreteType>
523 public:
524  template <typename... Args>
525  static std::unique_ptr<ConcreteType> create(Args&&... args)
526  {
527  return std::unique_ptr<ConcreteType>(
528  new ConcreteType(std::forward<Args>(args)...));
529  }
530 };
531 
532 
533 } // namespace gko
534 
535 
536 #endif // GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
gko::EnableCreateMethod
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition: polymorphic_object.hpp:522
gko::PolymorphicObject
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition: polymorphic_object.hpp:46
gko::EnableCloneable::clone
std::unique_ptr< ConcreteType > clone() const
Creates a clone of the object.
Definition: polymorphic_object.hpp:399
gko::copy_and_convert_to
std::unique_ptr< R, std::function< void(R *)> > copy_and_convert_to(std::shared_ptr< const Executor > exec, T *obj)
Converts the object to R and places it on Executor exec.
Definition: polymorphic_object.hpp:232
gko::ptr_param::get
T * get() const
Definition: utils_helper.hpp:77
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::log::EnableLogging
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition: logger.hpp:788
gko::ptr_param
This class is used for function parameters in the place of raw pointers.
Definition: utils_helper.hpp:43
gko::EnableCloneable::convert_to
void convert_to(result_type *result) const override
Converts the implementer to an object of type result_type.
Definition: polymorphic_object.hpp:404
gko::Cloneable
Interface for objects that can be cloned.
Definition: polymorphic_object.hpp:298
gko::EnableCloneable
This mixin is used to enable a default Cloneable::clone() implementation and similar for objects that...
Definition: polymorphic_object.hpp:369
gko::ConvertibleTo
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition: polymorphic_object.hpp:140
gko::experimental::distributed::DistributedBase
A base class for distributed objects.
Definition: base.hpp:32
gko::EnableCloneable::move_to
void move_to(result_type *result) override
Converts the implementer to an object of type result_type by moving data from this object.
Definition: polymorphic_object.hpp:406
gko::PolymorphicObject::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition: polymorphic_object.hpp:62
gko::EnableCloneable::clone
std::unique_ptr< ConcreteType > clone(std::shared_ptr< const Executor > exec) const
Creates a clone of the object.
Definition: polymorphic_object.hpp:385