Ginkgo: ginkgo/core/base/polymorphic_object.hpp Source File

| Ginkgo Generated from branch based on main. Ginkgo version 1.11.0 A numerical linear algebra library targeting many-core architectures

Loading...
Searching...
No Matches
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
17namespace gko {
18namespace experimental {
19 namespace distributed {
20
21
22class DistributedBase;
23
24
25} // namespace distributed
26} // namespace experimental
27
28
52 class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
53public:
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
139 PolymorphicObject* copy_from(const PolymorphicObject* other)
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,
191 PolymorphicObject>*
192 copy_from(const std::unique_ptr<Derived, Deleter>& other)
193 {
194 return this->copy_from(other.get());
195 }
196
200 PolymorphicObject* copy_from(
201 const std::shared_ptr<const PolymorphicObject>& other)
202 {
203 return this->copy_from(other.get());
204 }
205
217 PolymorphicObject* move_from(ptr_param<PolymorphicObject> other)
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
248protected:
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
330private:
331 std::shared_ptr<const Executor> exec_;
332};
333
334
353template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
354class EnableAbstractPolymorphicObject : public PolymorphicBase {
355public:
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
478template <typename ResultType>
479class ConvertibleTo {
480public:
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
517namespace detail {
518
519
520template <typename R, typename T>
521std::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
536template <typename R, typename T>
537std::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
570template <typename R, typename T>
571std::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
584template <typename R, typename T>
585std::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
609template <typename R, typename T>
610std::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
624template <typename R, typename T>
625std::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
666template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
667 class EnablePolymorphicObject
668 : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
669protected:
670 using EnableAbstractPolymorphicObject<
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<
677 experimental::distributed::DistributedBase,
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<
715 experimental::distributed::DistributedBase,
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
725private:
726 GKO_ENABLE_SELF(ConcreteObject);
727};
728
729
742template <typename ConcreteType, typename ResultType = ConcreteType>
743 class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
744public:
745 using result_type = ResultType;
746 using ConvertibleTo<result_type>::convert_to;
747 using ConvertibleTo<result_type>::move_to;
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
753private:
754 GKO_ENABLE_SELF(ConcreteType);
755};
756
757
766template <typename ConcreteType>
767 class EnableCreateMethod {
768public:
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::EnableCreateMethod
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition polymorphic_object.hpp:767
gko::EnablePolymorphicAssignment
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:743
gko::EnablePolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:668
gko::PolymorphicObject
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition polymorphic_object.hpp:52
gko::PolymorphicObject::copy_from
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition polymorphic_object.hpp:139
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::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::move_from
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition polymorphic_object.hpp:217
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::PolymorphicObject::clone
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition polymorphic_object.hpp:123
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::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::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::PolymorphicObject::clear
PolymorphicObject * clear()
Transforms the object into its default state.
Definition polymorphic_object.hpp:236
gko::experimental::distributed::DistributedBase
A base class for distributed objects.
Definition base.hpp:32
gko::log::EnableLogging
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition logger.hpp:786
gko::ptr_param
This class is used for function parameters in the place of raw pointers.
Definition utils_helper.hpp:41
gko::ptr_param::get
T * get() const
Definition utils_helper.hpp:75
gko::experimental::distributed
The distributed namespace.
Definition polymorphic_object.hpp:19
gko
The Ginkgo namespace.
Definition abstract_factory.hpp:20
gko::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::convert_to
virtual void convert_to(result_type *result) const =0
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
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::as
std::decay_t< T > * as(U *obj)
Performs polymorphic type conversion.
Definition utils_helper.hpp:307
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
std
STL namespace.