Ginkgo Generated from branch based on master. Ginkgo version 1.8.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
13#include <ginkgo/core/base/executor.hpp>
14#include <ginkgo/core/base/utils.hpp>
15#include <ginkgo/core/log/logger.hpp>
16
17
18namespace gko {
19
20
44class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
45public:
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
240protected:
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
322private:
323 std::shared_ptr<const Executor> exec_;
324};
325
326
345template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
346class EnableAbstractPolymorphicObject : public PolymorphicBase {
347public:
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
470template <typename ResultType>
472public:
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
509namespace detail {
510
511
512template <typename R, typename T>
513std::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
528template <typename R, typename T>
529std::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
562template <typename R, typename T>
563std::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
576template <typename R, typename T>
577std::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
601template <typename R, typename T>
602std::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
616template <typename R, typename T>
617std::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
661template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
663 : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
664protected:
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
706private:
707 GKO_ENABLE_SELF(ConcreteObject);
708};
709
710
723template <typename ConcreteType, typename ResultType = ConcreteType>
724class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
725public:
726 using result_type = ResultType;
727 using ConvertibleTo<result_type>::convert_to;
728 using ConvertibleTo<result_type>::move_to;
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
734private:
735 GKO_ENABLE_SELF(ConcreteType);
736};
737
738
747template <typename ConcreteType>
749public:
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_
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition polymorphic_object.hpp:471
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:346
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition polymorphic_object.hpp:748
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:724
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:663
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition polymorphic_object.hpp:44
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition polymorphic_object.hpp:131
PolymorphicObject * copy_from(const std::shared_ptr< const PolymorphicObject > &other)
Copies another object into this object.
Definition polymorphic_object.hpp:192
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
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition polymorphic_object.hpp:209
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
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition polymorphic_object.hpp:115
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition polymorphic_object.hpp:235
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
std::unique_ptr< PolymorphicObject > clone(std::shared_ptr< const Executor > exec) const
Creates a clone of the object.
Definition polymorphic_object.hpp:99
PolymorphicObject * clear()
Transforms the object into its default state.
Definition polymorphic_object.hpp:228
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition logger.hpp:749
This class is used for function parameters in the place of raw pointers.
Definition utils_helper.hpp:43
T * get() const
Definition utils_helper.hpp:77
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:175
std::decay_t< T > * as(U *obj)
Performs polymorphic type conversion.
Definition utils_helper.hpp:309
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