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