diff --git a/libs/global/KisDescendent.h b/libs/global/KisDescendent.h new file mode 100644 index 0000000000..ce868e68a9 --- /dev/null +++ b/libs/global/KisDescendent.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 Tusooa Zhu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_DESCENDENT_H_ +#define KIS_DESCENDENT_H_ + +#include +#include + +/** + * KisDescendent holds an instance of any subclass U of T. + * + * Its copy/move constructor will call the respective constructor in class U. + * Same for assignments. + * + * After moving, the original KisDescendent will be invalidated. + * + * Example: (suppose Derived is a subclass of Base) + * KisDescendent ins1 = Derived(); + * ins1->someMethod(); + * KisDescendent ins2 = ins1; // ins2 is a clone of ins1, created by Derived's copy constructor + * KisDescendent ins3 = std::move(ins2); // move-constructs ins3; ins2 is now invalidated. + */ +template +class KisDescendent +{ + struct concept + { + virtual ~concept() = default; + virtual const T *ptr() const = 0; + virtual T *ptr() = 0; + virtual std::unique_ptr clone() const = 0; + }; + + template + struct model : public concept + { + model(U x) : instance(std::move(x)) {} + const T *ptr() const { return &instance; } + T *ptr() { return &instance; } + std::unique_ptr clone() const { return std::unique_ptr >(new model(U(instance))); } + U instance; + }; + + std::unique_ptr m_d; +public: + template + KisDescendent(U x) : m_d(std::unique_ptr >(new model(std::move(x)))) {} + + /** + * Copy-constructs the instance stored by that. The constructor of type U will be used. + */ + KisDescendent(const KisDescendent &that) : m_d(std::move(that.m_d->clone())) {} + /** + * Transfers the ownership of the instance from that to this. + * This will NOT move-construct any instance of U nor T. + */ + KisDescendent(KisDescendent &&that) : m_d(std::move(that.m_d)) {} + + KisDescendent & operator=(const KisDescendent &that) { Descendent t(that); *this = std::move(t); return *this; } + KisDescendent & operator=(KisDescendent &&that) { m_d = std::move(that.m_d); return *this; } + + /** + * Returns a const pointer to the stored instance. The pointer can be cast to const U*. + */ + const T *data() const { return m_d->ptr(); } + const T *constData() const { return m_d->ptr(); } + /** + * Returns a non-const pointer to the stored instance. The pointer can be cast to U*. + */ + T *data() { return m_d->ptr(); } + const T *operator->() const { return m_d->ptr(); } + T *operator->() { return m_d->ptr(); } +}; + +#endif // KIS_DESCENDENT_H_ diff --git a/libs/global/KisSharedDescendent.h b/libs/global/KisSharedDescendent.h new file mode 100644 index 0000000000..2872c49906 --- /dev/null +++ b/libs/global/KisSharedDescendent.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Tusooa Zhu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SHARED_DESCENDENT_H_ +#define KIS_SHARED_DESCENDENT_H_ + +#include "KisDescendent.h" + +#include + +/** + * To implement copy-on-write for your class: + * (1) If it is a class without subclasses, or the subclasses do + * not share a d-pointer with the base class: + * + * Make YourClass::Private inherit from QSharedData. + * Replace `QScopedPointer d;` with `QSharedDataPointer d;`. + * + * (2) If it is a class with subclasses, and the subclasses share + * a (inherited) d-pointer with the base class: + * + * Replace `QScopedPointer d_ptr;` with + * `QSharedDataPointer > d_ptr;` in your base class. + * Remove all `Q_DECLARE_PRIVATE()`s. + * Remove all `Q_DISABLE_COPY()`s. (To obtain copy-on-write you must first allow copies.) + * Replace `explicit DerivedClass(BaseClassPrivate &dd) : BaseClass(dd) {}` with + * `explicit DerivedClass(KisSharedDescendent &dd) : BaseClass(dd) {}`. + * Replace `DerivedClass() : BaseClass(*(new DerivedClassPrivate())) {}` with + * `DerivedClass() : BaseClass(KisSharedDescendent::of(DerivedClassPrivate())) {}`. + * Replace all `Q_D()` macros that get non-const d-pointers with `SHARED_D(YourClass)`. + * Replace all `Q_D()` macros that get const d-pointers with `CONST_SHARED_D(YourClass)`. + */ + +#define CONST_SHARED_D(Class) const Class##Private *const d = reinterpret_cast(d_ptr.constData()->constData()) +#define SHARED_D(Class) Class##Private *const d = reinterpret_cast(d_ptr.data()->data()) + +template +class KisSharedDescendent : public KisDescendent, public QSharedData +{ +public: + template + KisSharedDescendent(U x) : KisDescendent(std::move(x)) {} + + template + constexpr static KisSharedDescendent &of(U x) { return *(new KisSharedDescendent(std::move(x))); } + + template + constexpr static KisSharedDescendent *pointerOf(U x) { return *(new KisSharedDescendent(std::move(x))); } +}; + + +#endif // KIS_SHARED_DESCENDENT_H_