Ginkgo  Generated from pipelines/1556235455 branch based on develop. Ginkgo version 1.9.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 
19 
43 class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
44 public:
45  virtual ~PolymorphicObject()
46  {
47  this->template log<log::Logger::polymorphic_object_deleted>(exec_.get(),
48  this);
49  }
50 
51  // preserve the executor of the object
52  PolymorphicObject& operator=(const PolymorphicObject&) { return *this; }
53 
64  std::unique_ptr<PolymorphicObject> create_default(
65  std::shared_ptr<const Executor> exec) const
66  {
67  this->template log<log::Logger::polymorphic_object_create_started>(
68  exec_.get(), this);
69  auto created = this->create_default_impl(std::move(exec));
70  this->template log<log::Logger::polymorphic_object_create_completed>(
71  exec_.get(), this, created.get());
72  return created;
73  }
74 
83  std::unique_ptr<PolymorphicObject> create_default() const
84  {
85  return this->create_default(exec_);
86  }
87 
98  std::unique_ptr<PolymorphicObject> clone(
99  std::shared_ptr<const Executor> exec) const
100  {
101  auto new_op = this->create_default(exec);
102  new_op->copy_from(this);
103  return new_op;
104  }
105 
114  std::unique_ptr<PolymorphicObject> clone() const
115  {
116  return this->clone(exec_);
117  }
118 
131  {
132  this->template log<log::Logger::polymorphic_object_copy_started>(
133  exec_.get(), other, this);
134  auto copied = this->copy_from_impl(other);
135  this->template log<log::Logger::polymorphic_object_copy_completed>(
136  exec_.get(), other, this);
137  return copied;
138  }
139 
155  template <typename Derived, typename Deleter>
156  GKO_DEPRECATED(
157  "This function will be removed in a future release, the replacement "
158  "will copy instead of move. If a move is intended, use move_from "
159  "instead.")
160  std::enable_if_t<
161  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
162  PolymorphicObject>* copy_from(std::unique_ptr<Derived, Deleter>&& other)
163  {
164  this->template log<log::Logger::polymorphic_object_move_started>(
165  exec_.get(), other.get(), this);
166  auto copied = this->copy_from_impl(std::move(other));
167  this->template log<log::Logger::polymorphic_object_move_completed>(
168  exec_.get(), other.get(), this);
169  return copied;
170  }
171 
179  template <typename Derived, typename Deleter>
180  std::enable_if_t<
181  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
183  copy_from(const std::unique_ptr<Derived, Deleter>& other)
184  {
185  return this->copy_from(other.get());
186  }
187 
192  const std::shared_ptr<const PolymorphicObject>& other)
193  {
194  return this->copy_from(other.get());
195  }
196 
209  {
210  this->template log<log::Logger::polymorphic_object_move_started>(
211  exec_.get(), other.get(), this);
212  auto moved = this->move_from_impl(other.get());
213  this->template log<log::Logger::polymorphic_object_move_completed>(
214  exec_.get(), other.get(), this);
215  return moved;
216  }
217 
227  PolymorphicObject* clear() { return this->clear_impl(); }
228 
234  std::shared_ptr<const Executor> get_executor() const noexcept
235  {
236  return exec_;
237  }
238 
239 protected:
240  // This method is defined as protected since a polymorphic object should not
241  // be created using their constructor directly, but by creating an
242  // std::unique_ptr to it. Defining the constructor as protected keeps these
243  // access rights when inheriting the constructor.
249  explicit PolymorphicObject(std::shared_ptr<const Executor> exec)
250  : exec_{std::move(exec)}
251  {}
252 
253  // preserve the executor of the object
254  explicit PolymorphicObject(const PolymorphicObject& other)
255  {
256  *this = other;
257  }
258 
267  virtual std::unique_ptr<PolymorphicObject> create_default_impl(
268  std::shared_ptr<const Executor> exec) const = 0;
269 
278  virtual PolymorphicObject* copy_from_impl(
279  const PolymorphicObject* other) = 0;
280 
289  virtual PolymorphicObject* copy_from_impl(
290  std::unique_ptr<PolymorphicObject> other) = 0;
291 
300  virtual PolymorphicObject* move_from_impl(PolymorphicObject* other) = 0;
301 
310  virtual PolymorphicObject* move_from_impl(
311  std::unique_ptr<PolymorphicObject> other) = 0;
312 
319  virtual PolymorphicObject* clear_impl() = 0;
320 
321 private:
322  std::shared_ptr<const Executor> exec_;
323 };
324 
325 
344 template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
345 class EnableAbstractPolymorphicObject : public PolymorphicBase {
346 public:
347  using PolymorphicBase::PolymorphicBase;
348 
349  std::unique_ptr<AbstractObject> create_default(
350  std::shared_ptr<const Executor> exec) const
351  {
352  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
353  this->PolymorphicBase::create_default(std::move(exec)).release())};
354  }
355 
356  std::unique_ptr<AbstractObject> create_default() const
357  {
358  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
359  this->PolymorphicBase::create_default().release())};
360  }
361 
362  std::unique_ptr<AbstractObject> clone(
363  std::shared_ptr<const Executor> exec) const
364  {
365  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
366  this->PolymorphicBase::clone(std::move(exec)).release())};
367  }
368 
369  std::unique_ptr<AbstractObject> clone() const
370  {
371  return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
372  this->PolymorphicBase::clone().release())};
373  }
374 
375  AbstractObject* copy_from(const PolymorphicObject* other)
376  {
377  return static_cast<AbstractObject*>(
378  this->PolymorphicBase::copy_from(other));
379  }
380 
381  template <typename Derived>
382  GKO_DEPRECATED(
383  "This function will be removed in a future release, the replacement "
384  "will copy instead of move. If a move in intended, use move_to "
385  "instead.")
386  std::enable_if_t<
387  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
388  AbstractObject>* copy_from(std::unique_ptr<Derived>&& other)
389  {
390  return static_cast<AbstractObject*>(
391  this->PolymorphicBase::copy_from(std::move(other)));
392  }
393 
394  template <typename Derived>
395  std::enable_if_t<
396  std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
397  AbstractObject>*
398  copy_from(const std::unique_ptr<Derived>& other)
399  {
400  return copy_from(other.get());
401  }
402 
403  AbstractObject* copy_from(
404  const std::shared_ptr<const PolymorphicObject>& other)
405  {
406  return copy_from(other.get());
407  }
408 
409  AbstractObject* move_from(ptr_param<PolymorphicObject> other)
410  {
411  return static_cast<AbstractObject*>(
412  this->PolymorphicBase::move_from(other.get()));
413  }
414 
415  AbstractObject* clear()
416  {
417  return static_cast<AbstractObject*>(this->PolymorphicBase::clear());
418  }
419 };
420 
421 
430 #define GKO_ENABLE_SELF(_type) \
431  _type* self() noexcept { return static_cast<_type*>(this); } \
432  \
433  const _type* self() const noexcept \
434  { \
435  return static_cast<const _type*>(this); \
436  }
437 
438 
469 template <typename ResultType>
471 public:
472  using result_type = ResultType;
473 
474  virtual ~ConvertibleTo() = default;
475 
481  virtual void convert_to(result_type* result) const = 0;
482 
483  void convert_to(ptr_param<result_type> result) const
484  {
485  convert_to(result.get());
486  }
487 
502  virtual void move_to(result_type* result) = 0;
503 
504  void move_to(ptr_param<result_type> result) { move_to(result.get()); }
505 };
506 
507 
508 namespace detail {
509 
510 
511 template <typename R, typename T>
512 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to_impl(
513  std::shared_ptr<const Executor> exec, T* obj)
514 {
515  auto obj_as_r = dynamic_cast<R*>(obj);
516  if (obj_as_r != nullptr && obj->get_executor() == exec) {
517  // FIXME: this breaks lifetimes
518  return {obj_as_r, [](R*) {}};
519  } else {
520  auto copy = R::create(exec);
521  as<ConvertibleTo<std::decay_t<R>>>(obj)->convert_to(copy);
522  return {copy.release(), std::default_delete<R>{}};
523  }
524 }
525 
526 
527 template <typename R, typename T>
528 std::shared_ptr<R> copy_and_convert_to_impl(
529  std::shared_ptr<const Executor> exec, std::shared_ptr<T> obj)
530 {
531  auto obj_as_r = std::dynamic_pointer_cast<R>(obj);
532  if (obj_as_r != nullptr && obj->get_executor() == exec) {
533  return obj_as_r;
534  } else {
535  auto copy = R::create(exec);
536  as<ConvertibleTo<std::decay_t<R>>>(obj.get())->convert_to(copy);
537  return {std::move(copy)};
538  }
539 }
540 
541 
542 } // namespace detail
543 
544 
561 template <typename R, typename T>
562 std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to(
563  std::shared_ptr<const Executor> exec, T* obj)
564 {
565  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
566 }
567 
568 
575 template <typename R, typename T>
576 std::unique_ptr<const R, std::function<void(const R*)>> copy_and_convert_to(
577  std::shared_ptr<const Executor> exec, const T* obj)
578 {
579  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
580 }
581 
582 
600 template <typename R, typename T>
601 std::shared_ptr<R> copy_and_convert_to(std::shared_ptr<const Executor> exec,
602  std::shared_ptr<T> obj)
603 {
604  return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
605 }
606 
607 
615 template <typename R, typename T>
616 std::shared_ptr<const R> copy_and_convert_to(
617  std::shared_ptr<const Executor> exec, std::shared_ptr<const T> obj)
618 {
619  return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
620 }
621 
622 
660 template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
662  : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
663 protected:
665  ConcreteObject, PolymorphicBase>::EnableAbstractPolymorphicObject;
666 
667  std::unique_ptr<PolymorphicObject> create_default_impl(
668  std::shared_ptr<const Executor> exec) const override
669  {
670  return std::unique_ptr<ConcreteObject>{new ConcreteObject(exec)};
671  }
672 
673  PolymorphicObject* copy_from_impl(const PolymorphicObject* other) override
674  {
675  as<ConvertibleTo<ConcreteObject>>(other)->convert_to(self());
676  return this;
677  }
678 
679  PolymorphicObject* copy_from_impl(
680  std::unique_ptr<PolymorphicObject> other) override
681  {
682  as<ConvertibleTo<ConcreteObject>>(other.get())->move_to(self());
683  return this;
684  }
685 
686  PolymorphicObject* move_from_impl(PolymorphicObject* other) override
687  {
688  as<ConvertibleTo<ConcreteObject>>(other)->move_to(self());
689  return this;
690  }
691 
692  PolymorphicObject* move_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* clear_impl() override
700  {
701  *self() = ConcreteObject{this->get_executor()};
702  return this;
703  }
704 
705 private:
706  GKO_ENABLE_SELF(ConcreteObject);
707 };
708 
709 
722 template <typename ConcreteType, typename ResultType = ConcreteType>
723 class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
724 public:
725  using result_type = ResultType;
728 
729  void convert_to(result_type* result) const override { *result = *self(); }
730 
731  void move_to(result_type* result) override { *result = std::move(*self()); }
732 
733 private:
734  GKO_ENABLE_SELF(ConcreteType);
735 };
736 
737 
746 template <typename ConcreteType>
748 public:
749  template <typename... Args>
750  static std::unique_ptr<ConcreteType> create(Args&&... args)
751  {
752  return std::unique_ptr<ConcreteType>(
753  new ConcreteType(std::forward<Args>(args)...));
754  }
755 };
756 
757 
758 } // namespace gko
759 
760 
761 #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:731
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:729
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:747
gko::PolymorphicObject
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition: polymorphic_object.hpp:43
gko::EnableAbstractPolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:345
gko::PolymorphicObject::copy_from
PolymorphicObject * copy_from(const std::shared_ptr< const PolymorphicObject > &other)
Copies another object into this object.
Definition: polymorphic_object.hpp:191
gko::PolymorphicObject::clone
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition: polymorphic_object.hpp:114
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:562
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:723
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:83
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:183
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:98
gko::log::EnableLogging
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition: logger.hpp:748
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:227
gko::PolymorphicObject::copy_from
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition: polymorphic_object.hpp:130
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:64
gko::ConvertibleTo
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition: polymorphic_object.hpp:470
gko::PolymorphicObject::move_from
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition: polymorphic_object.hpp:208
gko::PolymorphicObject::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition: polymorphic_object.hpp:234
gko::EnablePolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:661
gko::ConvertibleTo::convert_to
virtual void convert_to(result_type *result) const =0
Converts the implementer to an object of type result_type.