Ginkgo Generated from branch based on main. Ginkgo version 1.9.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 {
18
19
43class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
44public:
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
239protected:
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
321private:
322 std::shared_ptr<const Executor> exec_;
323};
324
325
344template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
345class EnableAbstractPolymorphicObject : public PolymorphicBase {
346public:
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
469template <typename ResultType>
471public:
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
508namespace detail {
509
510
511template <typename R, typename T>
512std::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
527template <typename R, typename T>
528std::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
561template <typename R, typename T>
562std::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
575template <typename R, typename T>
576std::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
600template <typename R, typename T>
601std::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
615template <typename R, typename T>
616std::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
660template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
662 : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
663protected:
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
705private:
706 GKO_ENABLE_SELF(ConcreteObject);
707};
708
709
722template <typename ConcreteType, typename ResultType = ConcreteType>
723class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
724public:
725 using result_type = ResultType;
726 using ConvertibleTo<result_type>::convert_to;
727 using ConvertibleTo<result_type>::move_to;
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
733private:
734 GKO_ENABLE_SELF(ConcreteType);
735};
736
737
746template <typename ConcreteType>
748public:
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_
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition polymorphic_object.hpp:470
virtual void convert_to(result_type *result) const =0
Converts the implementer to an object of type result_type.
virtual void move_to(result_type *result)=0
Converts the implementer to an object of type result_type by moving data from this object.
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:345
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition polymorphic_object.hpp:747
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:723
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:662
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition polymorphic_object.hpp:43
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition polymorphic_object.hpp:130
PolymorphicObject * copy_from(const std::shared_ptr< const PolymorphicObject > &other)
Copies another object into this object.
Definition polymorphic_object.hpp:191
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
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition polymorphic_object.hpp:208
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
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition polymorphic_object.hpp:114
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition polymorphic_object.hpp:234
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
std::unique_ptr< PolymorphicObject > clone(std::shared_ptr< const Executor > exec) const
Creates a clone of the object.
Definition polymorphic_object.hpp:98
PolymorphicObject * clear()
Transforms the object into its default state.
Definition polymorphic_object.hpp:227
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition logger.hpp:760
This class is used for function parameters in the place of raw pointers.
Definition utils_helper.hpp:41
T * get() const
Definition utils_helper.hpp:75
The Ginkgo namespace.
Definition abstract_factory.hpp:20
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition utils_helper.hpp:173
std::decay_t< T > * as(U *obj)
Performs polymorphic type conversion.
Definition utils_helper.hpp:307
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
STL namespace.