/* Copyright (c) 2008 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_ITEM_P_H #define AKONADI_ITEM_P_H #include #include #include #include "entity_p.h" #include "itempayloadinternals_p.h" #include "tag.h" #include #include #include #include #include namespace Akonadi { namespace _detail { template class clone_ptr { T *t; public: clone_ptr() : t(0) { } explicit clone_ptr(T *t) : t(t) {} clone_ptr(const clone_ptr &other) : t(other.t ? other.t->clone() : 0) {} ~clone_ptr() { delete t; } clone_ptr &operator=(const clone_ptr &other) { if (this != &other) { clone_ptr copy(other); swap(copy); } return *this; } void swap(clone_ptr &other) { using std::swap; swap(t, other.t); } T *operator->() const { return get(); } T &operator*() const { assert(get() != 0); return *get(); } T *get() const { return t; } T *release() { T *const r = t; t = 0; return r; } void reset(T *other = 0) { delete t; t = other; } private: struct _save_bool { void f() { }; }; typedef void (_save_bool::*save_bool)(); public: operator save_bool() const { return get() ? &_save_bool::f : 0; } }; template inline void swap(clone_ptr &lhs, clone_ptr &rhs) { lhs.swap(rhs); } template class VarLengthArray { QVarLengthArray impl; // ###should be replaced by self-written container that doesn't waste so much space public: typedef T value_type; typedef T *iterator; typedef const T *const_iterator; typedef T *pointer; typedef const T *const_pointer; typedef T &reference; typedef const T &const_reference; explicit VarLengthArray(int size = 0) : impl(size) { } // compiler-generated dtor, copy ctor, copy assignment are ok // swap() makes little sense void push_back(const T &t) { impl.append(t); } int capacity() const { return impl.capacity(); } void clear() { impl.clear(); } size_t size() const { return impl.count(); } bool empty() const { return impl.isEmpty(); } void pop_back() { return impl.removeLast(); } void reserve(size_t n) { impl.reserve(n); } void resize(size_t n) { impl.resize(n); } iterator begin() { return impl.data(); } iterator end() { return impl.data() + impl.size(); } const_iterator begin() const { return impl.data(); } const_iterator end() const { return impl.data() + impl.size(); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } reference front() { return *impl.data(); } reference back() { return *(impl.data() + impl.size()); } const_reference front() const { return *impl.data(); } const_reference back() const { return *(impl.data() + impl.size()); } reference operator[](size_t n) { return impl[n]; } const_reference operator[](size_t n) const { return impl[n]; } }; struct TypedPayload { clone_ptr payload; int sharedPointerId; int metaTypeId; }; struct BySharedPointerAndMetaTypeID : std::unary_function { const int spid; const int mtid; BySharedPointerAndMetaTypeID(int spid, int mtid) : spid(spid) , mtid(mtid) { } bool operator()(const TypedPayload &tp) const { return (mtid == -1 || mtid == tp.metaTypeId) && (spid == -1 || spid == tp.sharedPointerId) ; } }; } } // namespace Akonadi namespace std { template <> inline void swap(Akonadi::_detail::TypedPayload &lhs, Akonadi::_detail::TypedPayload &rhs) { lhs.payload.swap(rhs.payload); swap(lhs.sharedPointerId, rhs.sharedPointerId); swap(lhs.metaTypeId, rhs.metaTypeId); } } namespace Akonadi { //typedef _detail::VarLengthArray<_detail::TypedPayload,2> PayloadContainer; typedef std::vector<_detail::TypedPayload> PayloadContainer; } // disable Q_FOREACH on PayloadContainer (b/c it likes to take copies and clone_ptr doesn't like that) template <> class QForeachContainer {}; namespace Akonadi { /** * @internal */ class ItemPrivate : public EntityPrivate { public: explicit ItemPrivate(Item::Id id = -1) : EntityPrivate(id) , mLegacyPayload() , mPayloads() , mConversionInProgress(false) , mRevision(-1) , mCollectionId(-1) , mSize(0) , mModificationTime() , mFlagsOverwritten(false) , mTagsOverwritten(false) , mSizeChanged(false) , mClearPayload(false) { } #if 0 ItemPrivate(const ItemPrivate &other) : EntityPrivate(other) { mFlags = other.mFlags; mRevision = other.mRevision; mSize = other.mSize; mModificationTime = other.mModificationTime; mMimeType = other.mMimeType; mLegacyPayload = other.mLegacyPayload; mPayloads = other.mPayloads; mConversionInProgress = false; mAddedFlags = other.mAddedFlags; mDeletedFlags = other.mDeletedFlags; mFlagsOverwritten = other.mFlagsOverwritten; mSizeChanged = other.mSizeChanged; mCollectionId = other.mCollectionId; mClearPayload = other.mClearPayload; } #endif ~ItemPrivate() { } void resetChangeLog() { mFlagsOverwritten = false; mAddedFlags.clear(); mDeletedFlags.clear(); mSizeChanged = false; mTagsOverwritten = false; mAddedTags.clear(); mDeletedTags.clear(); } EntityPrivate *clone() const { return new ItemPrivate(*this); } bool hasMetaTypeId(int mtid) const { return std::find_if(mPayloads.begin(), mPayloads.end(), _detail::BySharedPointerAndMetaTypeID(-1, mtid)) != mPayloads.end(); } PayloadBase *payloadBaseImpl(int spid, int mtid) const { const PayloadContainer::const_iterator it = std::find_if(mPayloads.begin(), mPayloads.end(), _detail::BySharedPointerAndMetaTypeID(spid, mtid)); return it == mPayloads.end() ? 0 : it->payload.get() ; } bool movePayloadFrom(ItemPrivate *other, int mtid) const /*sic!*/ { assert(other); const size_t oldSize = mPayloads.size(); PayloadContainer &oPayloads = other->mPayloads; const _detail::BySharedPointerAndMetaTypeID matcher(-1, mtid); const size_t numMatching = std::count_if(oPayloads.begin(), oPayloads.end(), matcher); mPayloads.resize(oldSize + numMatching); using namespace std; // for swap() for (PayloadContainer::iterator dst = mPayloads.begin() + oldSize, src = oPayloads.begin(), end = oPayloads.end() ; src != end ; ++src) { if (matcher(*src)) { swap(*dst, *src); ++dst; } } return numMatching > 0 ; } #if 0 std::auto_ptr takePayloadBaseImpl(int spid, int mtid) { PayloadContainer::iterator it = std::find_if(mPayloads.begin(), mPayloads.end(), _detail::BySharedPointerAndMetaTypeID(spid, mtid)); if (it == mPayloads.end()) { return std::auto_ptr(); } std::rotate(it, it + 1, mPayloads.end()); std::auto_ptr result(it->payload.release()); mPayloads.pop_back(); return result; } #endif void setPayloadBaseImpl(int spid, int mtid, std::auto_ptr p, bool add) const /*sic!*/ { if (!add) { mLegacyPayload.reset(); } if (!p.get()) { if (!add) { mPayloads.clear(); } return; } // if !add, delete all payload variants // (they're conversions of each other) mPayloads.resize(add ? mPayloads.size() + 1 : 1); _detail::TypedPayload &tp = mPayloads.back(); tp.payload.reset(p.release()); tp.sharedPointerId = spid; tp.metaTypeId = mtid; } void setLegacyPayloadBaseImpl(std::auto_ptr p); void tryEnsureLegacyPayload() const; mutable _detail::clone_ptr mLegacyPayload; mutable PayloadContainer mPayloads; mutable bool mConversionInProgress; int mRevision; Item::Flags mFlags; Tag::List mTags; Entity::Id mCollectionId; Collection::List mVirtualReferences; qint64 mSize; QDateTime mModificationTime; QString mMimeType; QString mGid; Item::Flags mAddedFlags; Item::Flags mDeletedFlags; Tag::List mAddedTags; Tag::List mDeletedTags; QSet mCachedPayloadParts; bool mFlagsOverwritten : 1; bool mTagsOverwritten : 1; bool mSizeChanged : 1; bool mClearPayload : 1; }; } #endif