Ginkgo Generated from branch based on master. Ginkgo version 1.7.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
polymorphic_object.hpp
1/*******************************<GINKGO LICENSE>******************************
2Copyright (c) 2017-2023, the Ginkgo authors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
91. Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its
17contributors may be used to endorse or promote products derived from
18this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31******************************<GINKGO LICENSE>*******************************/
32
33#ifndef GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
34#define GKO_PUBLIC_CORE_BASE_POLYMORPHIC_OBJECT_HPP_
35
36
37#include <memory>
38#include <type_traits>
39
40
41#include <ginkgo/core/base/executor.hpp>
42#include <ginkgo/core/base/utils.hpp>
43#include <ginkgo/core/log/logger.hpp>
44
45
46namespace gko {
47
48
72class PolymorphicObject : public log::EnableLogging<PolymorphicObject> {
73public:
74 virtual ~PolymorphicObject()
75 {
76 this->template log<log::Logger::polymorphic_object_deleted>(exec_.get(),
77 this);
78 }
79
80 // preserve the executor of the object
81 PolymorphicObject& operator=(const PolymorphicObject&) { return *this; }
82
93 std::unique_ptr<PolymorphicObject> create_default(
94 std::shared_ptr<const Executor> exec) const
95 {
97 exec_.get(), this);
98 auto created = this->create_default_impl(std::move(exec));
100 exec_.get(), this, created.get());
101 return created;
102 }
103
112 std::unique_ptr<PolymorphicObject> create_default() const
113 {
114 return this->create_default(exec_);
115 }
116
127 std::unique_ptr<PolymorphicObject> clone(
128 std::shared_ptr<const Executor> exec) const
129 {
130 auto new_op = this->create_default(exec);
131 new_op->copy_from(this);
132 return new_op;
133 }
134
143 std::unique_ptr<PolymorphicObject> clone() const
144 {
145 return this->clone(exec_);
146 }
147
160 {
162 exec_.get(), other, this);
163 auto copied = this->copy_from_impl(other);
165 exec_.get(), other, this);
166 return copied;
167 }
168
184 template <typename Derived, typename Deleter>
185 GKO_DEPRECATED(
186 "This function will be removed in a future release, the replacement "
187 "will copy instead of move. If a move is intended, use move_from "
188 "instead.")
189 std::enable_if_t<
190 std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
192 {
194 exec_.get(), other.get(), this);
195 auto copied = this->copy_from_impl(std::move(other));
197 exec_.get(), other.get(), this);
198 return copied;
199 }
200
208 template <typename Derived, typename Deleter>
209 std::enable_if_t<
210 std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
212 copy_from(const std::unique_ptr<Derived, Deleter>& other)
213 {
214 return this->copy_from(other.get());
215 }
216
221 const std::shared_ptr<const PolymorphicObject>& other)
222 {
223 return this->copy_from(other.get());
224 }
225
238 {
240 exec_.get(), other.get(), this);
241 auto moved = this->move_from_impl(other.get());
243 exec_.get(), other.get(), this);
244 return moved;
245 }
246
256 PolymorphicObject* clear() { return this->clear_impl(); }
257
263 std::shared_ptr<const Executor> get_executor() const noexcept
264 {
265 return exec_;
266 }
267
268protected:
269 // This method is defined as protected since a polymorphic object should not
270 // be created using their constructor directly, but by creating an
271 // std::unique_ptr to it. Defining the constructor as protected keeps these
272 // access rights when inheriting the constructor.
278 explicit PolymorphicObject(std::shared_ptr<const Executor> exec)
279 : exec_{std::move(exec)}
280 {}
281
282 // preserve the executor of the object
283 explicit PolymorphicObject(const PolymorphicObject& other)
284 {
285 *this = other;
286 }
287
296 virtual std::unique_ptr<PolymorphicObject> create_default_impl(
297 std::shared_ptr<const Executor> exec) const = 0;
298
307 virtual PolymorphicObject* copy_from_impl(
308 const PolymorphicObject* other) = 0;
309
318 virtual PolymorphicObject* copy_from_impl(
319 std::unique_ptr<PolymorphicObject> other) = 0;
320
329 virtual PolymorphicObject* move_from_impl(PolymorphicObject* other) = 0;
330
339 virtual PolymorphicObject* move_from_impl(
340 std::unique_ptr<PolymorphicObject> other) = 0;
341
348 virtual PolymorphicObject* clear_impl() = 0;
349
350private:
351 std::shared_ptr<const Executor> exec_;
352};
353
354
373template <typename AbstractObject, typename PolymorphicBase = PolymorphicObject>
374class EnableAbstractPolymorphicObject : public PolymorphicBase {
375public:
376 using PolymorphicBase::PolymorphicBase;
377
378 std::unique_ptr<AbstractObject> create_default(
379 std::shared_ptr<const Executor> exec) const
380 {
381 return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
382 this->PolymorphicBase::create_default(std::move(exec)).release())};
383 }
384
385 std::unique_ptr<AbstractObject> create_default() const
386 {
387 return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
388 this->PolymorphicBase::create_default().release())};
389 }
390
391 std::unique_ptr<AbstractObject> clone(
392 std::shared_ptr<const Executor> exec) const
393 {
394 return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
395 this->PolymorphicBase::clone(std::move(exec)).release())};
396 }
397
398 std::unique_ptr<AbstractObject> clone() const
399 {
400 return std::unique_ptr<AbstractObject>{static_cast<AbstractObject*>(
401 this->PolymorphicBase::clone().release())};
402 }
403
404 AbstractObject* copy_from(const PolymorphicObject* other)
405 {
406 return static_cast<AbstractObject*>(
407 this->PolymorphicBase::copy_from(other));
408 }
409
410 template <typename Derived>
411 GKO_DEPRECATED(
412 "This function will be removed in a future release, the replacement "
413 "will copy instead of move. If a move in intended, use move_to "
414 "instead.")
415 std::enable_if_t<
416 std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
417 AbstractObject>* copy_from(std::unique_ptr<Derived>&& other)
418 {
419 return static_cast<AbstractObject*>(
420 this->PolymorphicBase::copy_from(std::move(other)));
421 }
422
423 template <typename Derived>
424 std::enable_if_t<
425 std::is_base_of<PolymorphicObject, std::decay_t<Derived>>::value,
427 copy_from(const std::unique_ptr<Derived>& other)
428 {
429 return copy_from(other.get());
430 }
431
432 AbstractObject* copy_from(
433 const std::shared_ptr<const PolymorphicObject>& other)
434 {
435 return copy_from(other.get());
436 }
437
439 {
440 return static_cast<AbstractObject*>(
441 this->PolymorphicBase::move_from(other.get()));
442 }
443
444 AbstractObject* clear()
445 {
446 return static_cast<AbstractObject*>(this->PolymorphicBase::clear());
447 }
448};
449
450
459#define GKO_ENABLE_SELF(_type) \
460 _type* self() noexcept { return static_cast<_type*>(this); } \
461 \
462 const _type* self() const noexcept \
463 { \
464 return static_cast<const _type*>(this); \
465 }
466
467
498template <typename ResultType>
500public:
501 using result_type = ResultType;
502
503 virtual ~ConvertibleTo() = default;
504
510 virtual void convert_to(result_type* result) const = 0;
511
513 {
514 convert_to(result.get());
515 }
516
531 virtual void move_to(result_type* result) = 0;
532
534};
535
536
537namespace detail {
538
539
540template <typename R, typename T>
541std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to_impl(
542 std::shared_ptr<const Executor> exec, T* obj)
543{
544 auto obj_as_r = dynamic_cast<R*>(obj);
545 if (obj_as_r != nullptr && obj->get_executor() == exec) {
546 // FIXME: this breaks lifetimes
547 return {obj_as_r, [](R*) {}};
548 } else {
549 auto copy = R::create(exec);
550 as<ConvertibleTo<std::decay_t<R>>>(obj)->convert_to(copy);
551 return {copy.release(), std::default_delete<R>{}};
552 }
553}
554
555
556template <typename R, typename T>
557std::shared_ptr<R> copy_and_convert_to_impl(
558 std::shared_ptr<const Executor> exec, std::shared_ptr<T> obj)
559{
560 auto obj_as_r = std::dynamic_pointer_cast<R>(obj);
561 if (obj_as_r != nullptr && obj->get_executor() == exec) {
562 return obj_as_r;
563 } else {
564 auto copy = R::create(exec);
565 as<ConvertibleTo<std::decay_t<R>>>(obj.get())->convert_to(copy);
566 return {std::move(copy)};
567 }
568}
569
570
571} // namespace detail
572
573
590template <typename R, typename T>
591std::unique_ptr<R, std::function<void(R*)>> copy_and_convert_to(
592 std::shared_ptr<const Executor> exec, T* obj)
593{
594 return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
595}
596
597
604template <typename R, typename T>
605std::unique_ptr<const R, std::function<void(const R*)>> copy_and_convert_to(
606 std::shared_ptr<const Executor> exec, const T* obj)
607{
608 return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
609}
610
611
629template <typename R, typename T>
630std::shared_ptr<R> copy_and_convert_to(std::shared_ptr<const Executor> exec,
631 std::shared_ptr<T> obj)
632{
633 return detail::copy_and_convert_to_impl<R>(std::move(exec), obj);
634}
635
636
644template <typename R, typename T>
645std::shared_ptr<const R> copy_and_convert_to(
646 std::shared_ptr<const Executor> exec, std::shared_ptr<const T> obj)
647{
648 return detail::copy_and_convert_to_impl<const R>(std::move(exec), obj);
649}
650
651
689template <typename ConcreteObject, typename PolymorphicBase = PolymorphicObject>
691 : public EnableAbstractPolymorphicObject<ConcreteObject, PolymorphicBase> {
692protected:
694 ConcreteObject, PolymorphicBase>::EnableAbstractPolymorphicObject;
695
696 std::unique_ptr<PolymorphicObject> create_default_impl(
697 std::shared_ptr<const Executor> exec) const override
698 {
699 return std::unique_ptr<ConcreteObject>{new ConcreteObject(exec)};
700 }
701
702 PolymorphicObject* copy_from_impl(const PolymorphicObject* other) override
703 {
704 as<ConvertibleTo<ConcreteObject>>(other)->convert_to(self());
705 return this;
706 }
707
708 PolymorphicObject* copy_from_impl(
709 std::unique_ptr<PolymorphicObject> other) override
710 {
711 as<ConvertibleTo<ConcreteObject>>(other.get())->move_to(self());
712 return this;
713 }
714
715 PolymorphicObject* move_from_impl(PolymorphicObject* other) override
716 {
717 as<ConvertibleTo<ConcreteObject>>(other)->move_to(self());
718 return this;
719 }
720
721 PolymorphicObject* move_from_impl(
722 std::unique_ptr<PolymorphicObject> other) override
723 {
724 as<ConvertibleTo<ConcreteObject>>(other.get())->move_to(self());
725 return this;
726 }
727
728 PolymorphicObject* clear_impl() override
729 {
730 *self() = ConcreteObject{this->get_executor()};
731 return this;
732 }
733
734private:
735 GKO_ENABLE_SELF(ConcreteObject);
736};
737
738
751template <typename ConcreteType, typename ResultType = ConcreteType>
752class EnablePolymorphicAssignment : public ConvertibleTo<ResultType> {
753public:
754 using result_type = ResultType;
755 using ConvertibleTo<result_type>::convert_to;
756 using ConvertibleTo<result_type>::move_to;
757
758 void convert_to(result_type* result) const override { *result = *self(); }
759
760 void move_to(result_type* result) override { *result = std::move(*self()); }
761
762private:
763 GKO_ENABLE_SELF(ConcreteType);
764};
765
766
775template <typename ConcreteType>
777public:
778 template <typename... Args>
779 static std::unique_ptr<ConcreteType> create(Args&&... args)
780 {
781 return std::unique_ptr<ConcreteType>(
782 new ConcreteType(std::forward<Args>(args)...));
783 }
784};
785
786
787} // namespace gko
788
789
790#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:499
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:374
This mixin implements a static create() method on ConcreteType that dynamically allocates the memory,...
Definition polymorphic_object.hpp:776
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:752
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:760
void convert_to(result_type *result) const override
Converts the implementer to an object of type result_type.
Definition polymorphic_object.hpp:758
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:691
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition polymorphic_object.hpp:72
PolymorphicObject * copy_from(const PolymorphicObject *other)
Copies another object into this object.
Definition polymorphic_object.hpp:159
PolymorphicObject * copy_from(const std::shared_ptr< const PolymorphicObject > &other)
Copies another object into this object.
Definition polymorphic_object.hpp:220
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:212
PolymorphicObject * move_from(ptr_param< PolymorphicObject > other)
Moves another object into this object.
Definition polymorphic_object.hpp:237
std::unique_ptr< PolymorphicObject > create_default() const
Creates a new "default" object of the same dynamic type as this object.
Definition polymorphic_object.hpp:112
std::unique_ptr< PolymorphicObject > clone() const
Creates a clone of the object.
Definition polymorphic_object.hpp:143
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition polymorphic_object.hpp:263
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:93
std::unique_ptr< PolymorphicObject > clone(std::shared_ptr< const Executor > exec) const
Creates a clone of the object.
Definition polymorphic_object.hpp:127
PolymorphicObject * clear()
Transforms the object into its default state.
Definition polymorphic_object.hpp:256
EnableLogging is a mixin which should be inherited by any class which wants to enable logging.
Definition logger.hpp:777
This class is used for function parameters in the place of raw pointers.
Definition utils_helper.hpp:71
The Ginkgo namespace.
Definition abstract_factory.hpp:48
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:803
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:591
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition utils_helper.hpp:203