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 }