File indexing completed on 2024-06-16 04:50:14

0001 /*
0002     SPDX-FileCopyrightText: 2008 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QDateTime>
0010 
0011 #include "itemchangelog_p.h"
0012 #include "itempayloadinternals_p.h"
0013 #include "tag.h"
0014 
0015 #include <algorithm>
0016 #include <cassert>
0017 #include <memory>
0018 #include <vector>
0019 
0020 namespace Akonadi
0021 {
0022 namespace _detail
0023 {
0024 template<typename T>
0025 class clone_ptr
0026 {
0027     std::unique_ptr<T> t;
0028 
0029 public:
0030     explicit clone_ptr() = default;
0031     explicit clone_ptr(T *t)
0032         : t(t)
0033     {
0034     }
0035 
0036     clone_ptr(const clone_ptr &other)
0037         : t(other.t ? other.t->clone() : nullptr)
0038     {
0039     }
0040 
0041     clone_ptr(clone_ptr &&) noexcept = default;
0042 
0043     ~clone_ptr() = default;
0044 
0045     clone_ptr &operator=(const clone_ptr &other)
0046     {
0047         if (this != &other) {
0048             clone_ptr copy(other);
0049             swap(copy);
0050         }
0051         return *this;
0052     }
0053 
0054     clone_ptr &operator=(clone_ptr &&) noexcept = default;
0055 
0056     void swap(clone_ptr &other)
0057     {
0058         using std::swap;
0059         swap(t, other.t);
0060     }
0061 
0062     T *operator->() const
0063     {
0064         return get();
0065     }
0066 
0067     T &operator*() const
0068     {
0069         assert(get() != nullptr);
0070         return *get();
0071     }
0072 
0073     T *get() const
0074     {
0075         return t.get();
0076     }
0077 
0078     T *release()
0079     {
0080         return t.release();
0081     }
0082 
0083     void reset(T *other = nullptr)
0084     {
0085         t.reset(other);
0086     }
0087 
0088     explicit operator bool() const noexcept
0089     {
0090         return get() != nullptr;
0091     }
0092 };
0093 
0094 template<typename T>
0095 inline void swap(clone_ptr<T> &lhs, clone_ptr<T> &rhs) noexcept
0096 {
0097     lhs.swap(rhs);
0098 }
0099 
0100 struct TypedPayload {
0101     clone_ptr<Internal::PayloadBase> payload;
0102     int sharedPointerId;
0103     int metaTypeId;
0104 };
0105 
0106 struct BySharedPointerAndMetaTypeID {
0107     const int spid;
0108     const int mtid;
0109     BySharedPointerAndMetaTypeID(int spid, int mtid)
0110         : spid(spid)
0111         , mtid(mtid)
0112     {
0113     }
0114     bool operator()(const TypedPayload &tp) const
0115     {
0116         return (mtid == -1 || mtid == tp.metaTypeId) && (spid == -1 || spid == tp.sharedPointerId);
0117     }
0118 };
0119 
0120 }
0121 
0122 } // namespace Akonadi
0123 
0124 namespace std
0125 {
0126 template<>
0127 inline void swap<Akonadi::_detail::TypedPayload>(Akonadi::_detail::TypedPayload &lhs, Akonadi::_detail::TypedPayload &rhs) noexcept
0128 {
0129     lhs.payload.swap(rhs.payload);
0130     swap(lhs.sharedPointerId, rhs.sharedPointerId);
0131     swap(lhs.metaTypeId, rhs.metaTypeId);
0132 }
0133 }
0134 
0135 namespace Akonadi
0136 {
0137 using PayloadContainer = std::vector<_detail::TypedPayload>;
0138 }
0139 
0140 namespace Akonadi
0141 {
0142 /**
0143  * @internal
0144  */
0145 class ItemPrivate : public QSharedData
0146 {
0147 public:
0148     explicit ItemPrivate(Item::Id id = -1)
0149         : QSharedData()
0150         , mRevision(-1)
0151         , mId(id)
0152         , mPayloads()
0153         , mCollectionId(-1)
0154         , mSize(0)
0155         , mModificationTime()
0156         , mFlagsOverwritten(false)
0157         , mTagsOverwritten(false)
0158         , mSizeChanged(false)
0159         , mClearPayload(false)
0160         , mConversionInProgress(false)
0161     {
0162     }
0163 
0164     ItemPrivate(const ItemPrivate &other)
0165         : QSharedData(other)
0166         , mRevision(other.mRevision)
0167         , mId(other.mId)
0168         , mRemoteId(other.mRemoteId)
0169         , mRemoteRevision(other.mRemoteRevision)
0170         , mPayloadPath(other.mPayloadPath)
0171         , mPayloads(other.mPayloads)
0172         , mFlags(other.mFlags)
0173         , mTags(other.mTags)
0174         , mRelations(other.mRelations)
0175         , mCollectionId(other.mCollectionId)
0176         , mVirtualReferences(other.mVirtualReferences)
0177         , mSize(other.mSize)
0178         , mModificationTime(other.mModificationTime)
0179         , mMimeType(other.mMimeType)
0180         , mGid(other.mGid)
0181         , mCachedPayloadParts(other.mCachedPayloadParts)
0182         , mFlagsOverwritten(other.mFlagsOverwritten)
0183         , mTagsOverwritten(other.mTagsOverwritten)
0184         , mSizeChanged(other.mSizeChanged)
0185         , mClearPayload(other.mClearPayload)
0186         , mConversionInProgress(false)
0187     {
0188         if (other.mParent) {
0189             mParent.reset(new Collection(*(other.mParent)));
0190         }
0191 
0192         ItemChangeLog *changelog = ItemChangeLog::instance();
0193         changelog->addedFlags(this) = changelog->addedFlags(&other);
0194         changelog->deletedFlags(this) = changelog->deletedFlags(&other);
0195         changelog->addedTags(this) = changelog->addedTags(&other);
0196         changelog->deletedTags(this) = changelog->deletedTags(&other);
0197         changelog->attributeStorage(this) = changelog->attributeStorage(&other);
0198     }
0199 
0200     ~ItemPrivate()
0201     {
0202         ItemChangeLog::instance()->removeItem(this);
0203     }
0204 
0205     void resetChangeLog()
0206     {
0207         mFlagsOverwritten = false;
0208         mSizeChanged = false;
0209         mTagsOverwritten = false;
0210         ItemChangeLog::instance()->clearItemChangelog(this);
0211     }
0212 
0213     bool hasMetaTypeId(int mtid) const
0214     {
0215         return std::any_of(mPayloads.cbegin(), mPayloads.cend(), _detail::BySharedPointerAndMetaTypeID(-1, mtid));
0216     }
0217 
0218     Internal::PayloadBase *payloadBaseImpl(int spid, int mtid) const
0219     {
0220         auto it = std::find_if(mPayloads.cbegin(), mPayloads.cend(), _detail::BySharedPointerAndMetaTypeID(spid, mtid));
0221         return it == mPayloads.cend() ? nullptr : it->payload.get();
0222     }
0223 
0224     bool movePayloadFrom(ItemPrivate *other, int mtid) const /*sic!*/
0225     {
0226         assert(other);
0227         const size_t oldSize = mPayloads.size();
0228         PayloadContainer &oPayloads = other->mPayloads;
0229         const _detail::BySharedPointerAndMetaTypeID matcher(-1, mtid);
0230         const size_t numMatching = std::count_if(oPayloads.begin(), oPayloads.end(), matcher);
0231         mPayloads.resize(oldSize + numMatching);
0232         using namespace std; // for swap()
0233         for (auto dst = mPayloads.begin() + oldSize, src = oPayloads.begin(), end = oPayloads.end(); src != end; ++src) {
0234             if (matcher(*src)) {
0235                 swap(*dst, *src);
0236                 ++dst;
0237             }
0238         }
0239         return numMatching > 0;
0240     }
0241 
0242     void setPayloadBaseImpl(int spid, int mtid, std::unique_ptr<Internal::PayloadBase> &p, bool add) const /*sic!*/
0243     {
0244         if (!p.get()) {
0245             if (!add) {
0246                 mPayloads.clear();
0247             }
0248             return;
0249         }
0250 
0251         // if !add, delete all payload variants
0252         // (they're conversions of each other)
0253         mPayloadPath.clear();
0254         mPayloads.resize(add ? mPayloads.size() + 1 : 1);
0255         _detail::TypedPayload &tp = mPayloads.back();
0256         tp.payload.reset(p.release());
0257         tp.sharedPointerId = spid;
0258         tp.metaTypeId = mtid;
0259     }
0260 
0261     // Utilise the 4-bytes padding from QSharedData
0262     int mRevision;
0263     Item::Id mId;
0264     QString mRemoteId;
0265     QString mRemoteRevision;
0266     mutable QString mPayloadPath;
0267     mutable QScopedPointer<Collection> mParent;
0268     mutable PayloadContainer mPayloads;
0269     Item::Flags mFlags;
0270     Tag::List mTags;
0271     Relation::List mRelations;
0272     Item::Id mCollectionId;
0273     Collection::List mVirtualReferences;
0274     // TODO: Maybe just use uint? Would save us another 8 bytes after reordering
0275     qint64 mSize;
0276     QDateTime mModificationTime;
0277     QString mMimeType;
0278     QString mGid;
0279     QSet<QByteArray> mCachedPayloadParts;
0280     bool mFlagsOverwritten : 1;
0281     bool mTagsOverwritten : 1;
0282     bool mSizeChanged : 1;
0283     bool mClearPayload : 1;
0284     mutable bool mConversionInProgress;
0285     // 6 bytes padding here
0286 };
0287 
0288 }