Ginkgo  Generated from pipelines/1589998975 branch based on develop. Ginkgo version 1.10.0
A numerical linear algebra library targeting many-core architectures
polymorphic_object.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 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 
52 class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
53 public:
54  virtual ~PolymorphicObject()
55  {
56  this->template log<log::Logger::polymorphic_object_deleted>(exec_.get(),
57  this);
58  }
59 
60  // preserve the executor of the object
61  PolymorphicObject& operator=(const PolymorphicObject&) { return *this; }
62 
73  std::unique_ptr<PolymorphicObject> create_default(
74  std::shared_ptr<const Executor> exec) const
75  {
76  this->template log<log::Logger::polymorphic_object_create_started>(
77  exec_.get(), this);
78  auto created = this->create_default_impl(std::move(exec));
79  this->template log<log::Logger::polymorphic_object_create_completed>(
80  exec_.get(), this, created.get());
81  return created;
82  }
83 
92  std::unique_ptr<PolymorphicObject> create_default() const
93  {
94  return this->create_default(exec_);
95  }
96 
107  std::unique_ptr<PolymorphicObject> clone(
108  std::shared_ptr<const Executor> exec) const
109  {
110  auto new_op = this->create_default(exec);
111  new_op->copy_from(this);
112  return new_op;
113  }
114 
123  std::unique_ptr<PolymorphicObject> clone() const
124  {
125  return this->clone(exec_);
126  }
127 
140  {
141  this->template log<log::Logger::polymorphic_object_copy_started>(
142  exec_.get(), other, this);
143  auto copied = this->copy_from_impl(other);
144  this->template log<log::Logger::polymorphic_object_copy_completed>(
145  exec_.get(), other, this);
146  return copied;
147  }
148 
164  template <typename Derived, typename Deleter>
165  GKO_DEPRECATED(
166  "This function will be removed in a future release, the replacement "
167  "will copy instead of move. If a move is intended, use move_from "
168  "instead.")
169  std::enable_if_t<
170  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
171  PolymorphicObject>* copy_from(std::unique_ptr<Derived, Deleter>&& other)
172  {
173  this->template log<log::Logger::polymorphic_object_move_started>(
174  exec_.get(), other.get(), this);
175  auto copied = this->copy_from_impl(std::move(other));
176  this->template log<log::Logger::polymorphic_object_move_completed>(
177  exec_.get(), other.get(), this);
178  return copied;
179  }
180 
188  template <typename Derived, typename Deleter>
189  std::enable_if_t<
190  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
192  copy_from(const std::unique_ptr<Derived, Deleter>& other)
193  {
194  return this->copy_from(other.get());
195  }
196 
201  const std::shared_ptr<const PolymorphicObject>& other)
202  {
203  return this->copy_from(other.get());
204  }
205 
218  {
219  this->template log<log::Logger::polymorphic_object_move_started>(
220  exec_.get(), other.get(), this);
221  auto moved = this->move_from_impl(other.get());
222  this->template log<log::Logger::polymorphic_object_move_completed>(
223  exec_.get(), other.get(), this);
224  return moved;
225  }
226 
236  PolymorphicObject* clear() { return this->clear_impl(); }
237 
243  std::shared_ptr<const Executor> get_executor() const noexcept
244  {
245  return exec_;
246  }
247 
248 protected:
249  // This method is defined as protected since a polymorphic object should not
250  // be created using their constructor directly, but by creating an
251  // std::unique_ptr to it. Defining the constructor as protected keeps these
252  // access rights when inheriting the constructor.
258  explicit PolymorphicObject(std::shared_ptr<const Executor> exec)
259  : exec_{std::move(exec)}
260  {}
261 
262  // preserve the executor of the object
263  explicit PolymorphicObject(const PolymorphicObject& other)
264  {
265  *this = other;
266  }
267 
276  virtual std::unique_ptr<PolymorphicObject> create_default_impl(
277  std::shared_ptr<const Executor> exec) const = 0;
278 
287  virtual PolymorphicObject* copy_from_impl(
288  const PolymorphicObject* other) = 0;
289 
298  virtual PolymorphicObject* copy_from_impl(
299  std::unique_ptr<PolymorphicObject> other) = 0;
300 
309  virtual PolymorphicObject* move_from_impl(PolymorphicObject* other) = 0;
310 
319  virtual PolymorphicObject* move_from_impl(
320  std::unique_ptr<PolymorphicObject> other) = 0;
321 
328  virtual PolymorphicObject* clear_impl() = 0;
329 
330 private:
331  std::shared_ptr<const Executor> exec_;
332 };
333 
334 
353 template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
354 class EnableAbstractPolymorphicObject : public PolymorphicBase {
355 public:
356  using PolymorphicBase::PolymorphicBase;
357 
358  std::unique_ptr<AbstractObject> create_default(
359  std::shared_ptr<const Executor> exec) const
360  {
361  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
362  this->PolymorphicBase::create_default(std::move(exec)).release())};
363  }
364 
365  std::unique_ptr<AbstractObject> create_default() const
366  {
367  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
368  this->PolymorphicBase::create_default().release())};
369  }
370 
371  std::unique_ptr<AbstractObject> clone(
372  std::shared_ptr<const Executor> exec) const
373  {
374  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
375  this->PolymorphicBase::clone(std::move(exec)).release())};
376  }
377 
378  std::unique_ptr<AbstractObject> clone() const
379  {
380  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
381  this->PolymorphicBase::clone().release())};
382  }
383 
384  AbstractObject* copy_from(const PolymorphicObject* other)
385  {
386  return static_cast<AbstractObject*>(
387  this->PolymorphicBase::copy_from(other));
388  }
389 
390  template <typename Derived>
391  GKO_DEPRECATED(
392  "This function will be removed in a future release, the replacement "
393  "will copy instead of move. If a move in intended, use move_to "
394  "instead.")
395  std::enable_if_t<
396  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
397  AbstractObject>* copy_from(std::unique_ptr<Derived>&& other)
398  {
399  return static_cast<AbstractObject*>(
400  this->PolymorphicBase::copy_from(std::move(other)));
401  }
402 
403  template <typename Derived>
404  std::enable_if_t<
405  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
406  AbstractObject>*
407  copy_from(const std::unique_ptr<Derived>& other)
408  {
409  return copy_from(other.get());
410  }
411 
412  AbstractObject* copy_from(
413  const std::shared_ptr<const PolymorphicObject>& other)
414  {
415  return copy_from(other.get());
416  }
417 
418  AbstractObject* move_from(ptr_param<PolymorphicObject> other)
419  {
420  return static_cast<AbstractObject*>(
421  this->PolymorphicBase::move_from(other.get()));
422  }
423 
424  AbstractObject* clear()
425  {
426  return static_cast<AbstractObject*>(this->PolymorphicBase::clear());
427  }
428 };
429 
430 
439 #define GKO_ENABLE_SELF(_type) \
440  _type* self() noexcept { return static_cast<_type*>(this); } \
441  \
442  const _type* self() const noexcept \
443  { \
444  return static_cast<const _type*>(this); \
445  }
446 
447 
478 template <typename ResultType>
480 public:
481  using result_type = ResultType;
482 
483  virtual ~ConvertibleTo() = default;
484 
490  virtual void convert_to(result_type* result) const = 0;
491 
492  void convert_to(ptr_param<result_type> result) const
493  {
494  convert_to(result.get());
495  }
496 
511  virtual void move_to(result_type* result) = 0;
512 
513  void move_to(ptr_param<result_type> result) { move_to(result.get()); }
514 };
515 
516 
517 namespace detail {
518 
519 
520 template <typename R, typename T>
521 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to_impl(
522  std::shared_ptr<const Executor> exec, T* obj)
523 {
524  auto obj_as_r = dynamic_cast<R*>(obj);
525  if (obj_as_r != nullptr && obj->get_executor() == exec) {
526  // FIXME: this breaks lifetimes
527  return {obj_as_r, [](R*) {}};
528  } else {
529  auto copy = R::create(exec);
530  as<ConvertibleTo<std::decay_t<R>>>(obj)->convert_to(copy);
531  return {copy.release(), std::default_delete<R>{}};
532  }
533 }
534 
535 
536 template <typename R, typename T>
537 std::shared_ptr<R> copy_and_convert_to_impl(
538  std::shared_ptr<const Executor> exec, std::shared_ptr<T> obj)
539 {
540  auto obj_as_r = std::dynamic_pointer_cast<R>(obj);
541  if (obj_as_r != nullptr && obj->get_executor() == exec) {
542  return obj_as_r;
543  } else {
544  auto copy = R::create(exec);
545  as<ConvertibleTo<std::decay_t<R>>>(obj.get())->convert_to(copy);
546  return {std::move(copy)};
547  }
548 }
549 
550 
551 } // namespace detail
552 
553 
570 template <typename R, typename T>
571 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to(
572  std::shared_ptr<const Executor> exec, T* obj)
573 {
574  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
575 }
576 
577 
584 template <typename R, typename T>
585 std::unique_ptr<const R, std::function<void(const R*)>> copy_and_convert_to(
586  std::shared_ptr<const Executor> exec, const T* obj)
587 {
588  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
589 }
590 
591 
609 template <typename R, typename T>
610 std::shared_ptr<R> copy_and_convert_to(std::shared_ptr<const Executor> exec,
611  std::shared_ptr<T> obj)
612 {
613  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
614 }
615 
616 
624 template <typename R, typename T>
625 std::shared_ptr<const R> copy_and_convert_to(
626  std::shared_ptr<const Executor> exec, std::shared_ptr<const T> obj)
627 {
628  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
629 }
630 
631 
666 template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
668  : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
669 protected:
671  ConcreteObject, PolymorphicBase>::EnableAbstractPolymorphicObject;
672 
673  std::unique_ptr<PolymorphicObject> create_default_impl(
674  std::shared_ptr<const Executor> exec) const override
675  {
676  if constexpr (std::is_base_of_v<
678  ConcreteObject>) {
679  return std::unique_ptr<ConcreteObject>{
680  new ConcreteObject(exec, self()->get_communicator())};
681  } else {
682  return std::unique_ptr<ConcreteObject>{new ConcreteObject(exec)};
683  }
684  }
685 
686  PolymorphicObject* copy_from_impl(const PolymorphicObject* other) override
687  {
688  as<ConvertibleTo<ConcreteObject>>(other)->convert_to(self());
689  return this;
690  }
691 
692  PolymorphicObject* copy_from_impl(
693  std::unique_ptr<PolymorphicObject> other) override
694  {
695  as<ConvertibleTo<ConcreteObject>>(other.get())->move_to(self());
696  return this;
697  }
698 
699  PolymorphicObject* move_from_impl(PolymorphicObject* other) override
700  {
701  as<ConvertibleTo<ConcreteObject>>(other)->move_to(self());
702  return this;
703  }
704 
705  PolymorphicObject* move_from_impl(
706  std::unique_ptr<PolymorphicObject> other) override
707  {
708  as<ConvertibleTo<ConcreteObject>>(other.get())->move_to(self());
709  return this;
710  }
711 
712  PolymorphicObject* clear_impl() override
713  {
714  if constexpr (std::is_base_of_v<
716  ConcreteObject>) {
717  *self() = ConcreteObject{this->get_executor(),
718  self()->get_communicator()};
719  } else {
720  *self() = ConcreteObject{this->get_executor()};
721  }
722  return this;
723  }
724 
725 private:
726  GKO_ENABLE_SELF(ConcreteObject);
727 };
728 
729 
742 template <typename ConcreteType, typename ResultType = ConcreteType>
743 class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
744 public:
745  using result_type = ResultType;
748 
749  void convert_to(result_type* result) const override { *result = *self(); }
750 
751  void move_to(result_type* result) override { *result = std::move(*self()); }
752 
753 private:
754  GKO_ENABLE_SELF(ConcreteType);
755 };
756 
757 
766 template <typename ConcreteType>
768 public:
769  template <typename... Args>
770  static std::unique_ptr<ConcreteType> create(Args&&... args)
771  {
772  return std::unique_ptr<ConcreteType>(
773  new ConcreteType(std::forward<Args>(args)...));
774  }
775 };
776 
777 
778 } // namespace gko
779 
780 
781 #endif // GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
gko::EnablePolymorphicAssignment::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:751
gko::EnablePolymorphicAssignment::convert_to
void convert_to(result_type *result) const override
Converts the implementer to an object of type result_type.
Definition: polymorphic_object.hpp:749
gko::Perturbation
The Perturbation class can be used to construct a LinOp to represent the operation (identity + scalar...
Definition: perturbation.hpp:38
gko::EnableCreateMethod
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition: polymorphic_object.hpp:767
gko::PolymorphicObject
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition: polymorphic_object.hpp:52
gko::EnableAbstractPolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:354
gko::PolymorphicObject::copy_from
PolymorphicObject * copy_from(const std::shared_ptr< const PolymorphicObject > &other)
Copies another object into this object.
Definition: polymorphic_object.hpp:200
gko::PolymorphicObject::clone
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition: polymorphic_object.hpp:123
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:571
gko::ptr_param::get
T * get() const
Definition: utils_helper.hpp:75
gko::EnablePolymorphicAssignment
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition: polymorphic_object.hpp:743
gko::ConvertibleTo::move_to
virtual void move_to(result_type *result)=0
Converts the implementer to an object of type result_type by moving data from this object.
gko::PolymorphicObject::create_default
std::unique_ptr< PolymorphicObject > create_default() const
Creates a new "default" object of the same dynamic type as this object.
Definition: polymorphic_object.hpp:92
gko::clone
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition: utils_helper.hpp:173
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::PolymorphicObject::copy_from
std::enable_if_t< std::is_base_of< PolymorphicObject, std::decay_t< Derived > >::value, PolymorphicObject > * copy_from(const std::unique_ptr< Derived, Deleter > &other)
Copies another object into this object.
Definition: polymorphic_object.hpp:192
gko::PolymorphicObject::clone
std::unique_ptr< PolymorphicObject > clone(std::shared_ptr< const Executor > exec) const
Creates a clone of the object.
Definition: polymorphic_object.hpp:107
gko::log::EnableLogging
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition: logger.hpp:760
gko::ptr_param
This class is used for function parameters in the place of raw pointers.
Definition: utils_helper.hpp:41
gko::PolymorphicObject::clear
PolymorphicObject * clear()
Transforms the object into its default state.
Definition: polymorphic_object.hpp:236
gko::PolymorphicObject::copy_from
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition: polymorphic_object.hpp:139
gko::PolymorphicObject::create_default
std::unique_ptr< PolymorphicObject > create_default(std::shared_ptr< const Executor > exec) const
Creates a new "default" object of the same dynamic type as this object.
Definition: polymorphic_object.hpp:73
gko::ConvertibleTo
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition: polymorphic_object.hpp:479
gko::PolymorphicObject::move_from
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition: polymorphic_object.hpp:217
gko::experimental::distributed::DistributedBase
A base class for distributed objects.
Definition: base.hpp:32
gko::PolymorphicObject::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition: polymorphic_object.hpp:243
gko::EnablePolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:667
gko::ConvertibleTo::convert_to
virtual void convert_to(result_type *result) const =0
Converts the implementer to an object of type result_type.