1 | /* |
2 | Copyright (c) 2008 Tobias Koenig <tokoe@kde.org> |
3 | |
4 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by |
6 | the Free Software Foundation; either version 2 of the License, or (at your |
7 | option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
12 | License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to the |
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17 | 02110-1301, USA. |
18 | */ |
19 | |
20 | #ifndef AKONADI_ITEM_P_H |
21 | #define AKONADI_ITEM_P_H |
22 | |
23 | #include <QtCore/QDateTime> |
24 | #include <QtCore/QMap> |
25 | #include <QtCore/QVarLengthArray> |
26 | |
27 | #include "entity_p.h" |
28 | #include "itempayloadinternals_p.h" |
29 | #include "tag.h" |
30 | |
31 | #include <boost/bind.hpp> |
32 | |
33 | #include <memory> |
34 | #include <algorithm> |
35 | #include <cassert> |
36 | #include <vector> |
37 | |
38 | namespace Akonadi { |
39 | |
40 | namespace _detail { |
41 | |
42 | template <typename T> |
43 | class clone_ptr { |
44 | T *t; |
45 | public: |
46 | clone_ptr() |
47 | : t(0) |
48 | { |
49 | } |
50 | explicit clone_ptr(T *t) |
51 | : t(t) |
52 | {} |
53 | clone_ptr(const clone_ptr &other) |
54 | : t(other.t ? other.t->clone() : 0) |
55 | {} |
56 | ~clone_ptr() |
57 | { |
58 | delete t; |
59 | } |
60 | clone_ptr &operator=(const clone_ptr &other) |
61 | { |
62 | if (this != &other) { |
63 | clone_ptr copy(other); |
64 | swap(copy); |
65 | } |
66 | return *this; |
67 | } |
68 | void swap(clone_ptr &other) |
69 | { |
70 | using std::swap; |
71 | swap(t, other.t); |
72 | } |
73 | T *operator->() const |
74 | { |
75 | return get(); |
76 | } |
77 | T &operator*() const |
78 | { |
79 | assert(get() != 0); |
80 | return *get(); |
81 | } |
82 | T *get() const |
83 | { |
84 | return t; |
85 | } |
86 | T *release() |
87 | { |
88 | T *const r = t; |
89 | t = 0; |
90 | return r; |
91 | } |
92 | void reset(T *other = 0) |
93 | { |
94 | delete t; |
95 | t = other; |
96 | } |
97 | |
98 | private: |
99 | struct _save_bool |
100 | { |
101 | void f() |
102 | { |
103 | }; |
104 | }; |
105 | typedef void (_save_bool::*save_bool)(); |
106 | public: |
107 | operator save_bool() const |
108 | { |
109 | return get() ? &_save_bool::f : 0; |
110 | } |
111 | }; |
112 | |
113 | template <typename T> |
114 | inline void swap(clone_ptr<T> &lhs, clone_ptr<T> &rhs) |
115 | { |
116 | lhs.swap(rhs); |
117 | } |
118 | |
119 | template <typename T, size_t N> |
120 | class VarLengthArray { |
121 | QVarLengthArray<T, N> impl; // ###should be replaced by self-written container that doesn't waste so much space |
122 | public: |
123 | typedef T value_type; |
124 | typedef T *iterator; |
125 | typedef const T *const_iterator; |
126 | typedef T *pointer; |
127 | typedef const T *const_pointer; |
128 | typedef T &reference; |
129 | typedef const T &const_reference; |
130 | |
131 | explicit VarLengthArray(int size = 0) |
132 | : impl(size) |
133 | { |
134 | } |
135 | // compiler-generated dtor, copy ctor, copy assignment are ok |
136 | // swap() makes little sense |
137 | |
138 | void push_back(const T &t) |
139 | { |
140 | impl.append(t); |
141 | } |
142 | int capacity() const |
143 | { |
144 | return impl.capacity(); |
145 | } |
146 | void clear() |
147 | { |
148 | impl.clear(); |
149 | } |
150 | size_t size() const |
151 | { |
152 | return impl.count(); |
153 | } |
154 | bool empty() const |
155 | { |
156 | return impl.isEmpty(); |
157 | } |
158 | void pop_back() |
159 | { |
160 | return impl.removeLast(); |
161 | } |
162 | void reserve(size_t n) |
163 | { |
164 | impl.reserve(n); |
165 | } |
166 | void resize(size_t n) |
167 | { |
168 | impl.resize(n); |
169 | } |
170 | |
171 | iterator begin() |
172 | { |
173 | return impl.data(); |
174 | } |
175 | iterator end() |
176 | { |
177 | return impl.data() + impl.size(); |
178 | } |
179 | const_iterator begin() const |
180 | { |
181 | return impl.data(); |
182 | } |
183 | const_iterator end() const |
184 | { |
185 | return impl.data() + impl.size(); |
186 | } |
187 | const_iterator cbegin() const |
188 | { |
189 | return begin(); |
190 | } |
191 | const_iterator cend() const |
192 | { |
193 | return end(); |
194 | } |
195 | |
196 | reference front() |
197 | { |
198 | return *impl.data(); |
199 | } |
200 | reference back() |
201 | { |
202 | return *(impl.data() + impl.size()); |
203 | } |
204 | const_reference front() const |
205 | { |
206 | return *impl.data(); |
207 | } |
208 | const_reference back() const |
209 | { |
210 | return *(impl.data() + impl.size()); |
211 | } |
212 | |
213 | reference operator[](size_t n) |
214 | { |
215 | return impl[n]; |
216 | } |
217 | const_reference operator[](size_t n) const |
218 | { |
219 | return impl[n]; |
220 | } |
221 | }; |
222 | |
223 | struct TypedPayload |
224 | { |
225 | clone_ptr<PayloadBase> payload; |
226 | int sharedPointerId; |
227 | int metaTypeId; |
228 | }; |
229 | |
230 | struct BySharedPointerAndMetaTypeID : std::unary_function<TypedPayload, bool> |
231 | { |
232 | const int spid; |
233 | const int mtid; |
234 | BySharedPointerAndMetaTypeID(int spid, int mtid) |
235 | : spid(spid) |
236 | , mtid(mtid) |
237 | { |
238 | } |
239 | bool operator()(const TypedPayload &tp) const |
240 | { |
241 | return (mtid == -1 || mtid == tp.metaTypeId) |
242 | && (spid == -1 || spid == tp.sharedPointerId) ; |
243 | } |
244 | }; |
245 | |
246 | } |
247 | |
248 | } // namespace Akonadi |
249 | |
250 | namespace std { |
251 | template <> |
252 | inline void swap<Akonadi::_detail::TypedPayload>(Akonadi::_detail::TypedPayload &lhs, Akonadi::_detail::TypedPayload &rhs) |
253 | { |
254 | lhs.payload.swap(rhs.payload); |
255 | swap(lhs.sharedPointerId, rhs.sharedPointerId); |
256 | swap(lhs.metaTypeId, rhs.metaTypeId); |
257 | } |
258 | } |
259 | |
260 | namespace Akonadi { |
261 | //typedef _detail::VarLengthArray<_detail::TypedPayload,2> PayloadContainer; |
262 | typedef std::vector<_detail::TypedPayload> PayloadContainer; |
263 | } |
264 | |
265 | // disable Q_FOREACH on PayloadContainer (b/c it likes to take copies and clone_ptr doesn't like that) |
266 | template <> |
267 | class QForeachContainer<Akonadi::PayloadContainer> {}; |
268 | |
269 | namespace Akonadi { |
270 | |
271 | /** |
272 | * @internal |
273 | */ |
274 | class ItemPrivate : public EntityPrivate |
275 | { |
276 | public: |
277 | explicit ItemPrivate(Item::Id id = -1) |
278 | : EntityPrivate(id) |
279 | , mLegacyPayload() |
280 | , mPayloads() |
281 | , mConversionInProgress(false) |
282 | , mRevision(-1) |
283 | , mCollectionId(-1) |
284 | , mSize(0) |
285 | , mModificationTime() |
286 | , mFlagsOverwritten(false) |
287 | , mTagsOverwritten(false) |
288 | , mSizeChanged(false) |
289 | , mClearPayload(false) |
290 | { |
291 | } |
292 | |
293 | #if 0 |
294 | ItemPrivate(const ItemPrivate &other) |
295 | : EntityPrivate(other) |
296 | { |
297 | mFlags = other.mFlags; |
298 | mRevision = other.mRevision; |
299 | mSize = other.mSize; |
300 | mModificationTime = other.mModificationTime; |
301 | mMimeType = other.mMimeType; |
302 | mLegacyPayload = other.mLegacyPayload; |
303 | mPayloads = other.mPayloads; |
304 | mConversionInProgress = false; |
305 | mAddedFlags = other.mAddedFlags; |
306 | mDeletedFlags = other.mDeletedFlags; |
307 | mFlagsOverwritten = other.mFlagsOverwritten; |
308 | mSizeChanged = other.mSizeChanged; |
309 | mCollectionId = other.mCollectionId; |
310 | mClearPayload = other.mClearPayload; |
311 | } |
312 | #endif |
313 | |
314 | ~ItemPrivate() |
315 | { |
316 | } |
317 | |
318 | void resetChangeLog() |
319 | { |
320 | mFlagsOverwritten = false; |
321 | mAddedFlags.clear(); |
322 | mDeletedFlags.clear(); |
323 | mSizeChanged = false; |
324 | mTagsOverwritten = false; |
325 | mAddedTags.clear(); |
326 | mDeletedTags.clear(); |
327 | } |
328 | |
329 | EntityPrivate *clone() const |
330 | { |
331 | return new ItemPrivate(*this); |
332 | } |
333 | |
334 | bool hasMetaTypeId(int mtid) const |
335 | { |
336 | return std::find_if(mPayloads.begin(), mPayloads.end(), |
337 | _detail::BySharedPointerAndMetaTypeID(-1, mtid)) |
338 | != mPayloads.end(); |
339 | } |
340 | |
341 | PayloadBase *payloadBaseImpl(int spid, int mtid) const |
342 | { |
343 | const PayloadContainer::const_iterator it |
344 | = std::find_if(mPayloads.begin(), mPayloads.end(), |
345 | _detail::BySharedPointerAndMetaTypeID(spid, mtid)); |
346 | return it == mPayloads.end() ? 0 : it->payload.get() ; |
347 | } |
348 | |
349 | bool movePayloadFrom(ItemPrivate *other, int mtid) const /*sic!*/ |
350 | { |
351 | assert(other); |
352 | const size_t oldSize = mPayloads.size(); |
353 | PayloadContainer &oPayloads = other->mPayloads; |
354 | const _detail::BySharedPointerAndMetaTypeID matcher(-1, mtid); |
355 | const size_t numMatching = std::count_if(oPayloads.begin(), oPayloads.end(), matcher); |
356 | mPayloads.resize(oldSize + numMatching); |
357 | using namespace std; // for swap() |
358 | for (PayloadContainer::iterator |
359 | dst = mPayloads.begin() + oldSize, |
360 | src = oPayloads.begin(), end = oPayloads.end() ; src != end ; ++src) { |
361 | if (matcher(*src)) { |
362 | swap(*dst, *src); |
363 | ++dst; |
364 | } |
365 | } |
366 | return numMatching > 0 ; |
367 | } |
368 | |
369 | #if 0 |
370 | std::auto_ptr<PayloadBase> takePayloadBaseImpl(int spid, int mtid) |
371 | { |
372 | PayloadContainer::iterator it |
373 | = std::find_if(mPayloads.begin(), mPayloads.end(), |
374 | _detail::BySharedPointerAndMetaTypeID(spid, mtid)); |
375 | if (it == mPayloads.end()) { |
376 | return std::auto_ptr<PayloadBase>(); |
377 | } |
378 | std::rotate(it, it + 1, mPayloads.end()); |
379 | std::auto_ptr<PayloadBase> result(it->payload.release()); |
380 | mPayloads.pop_back(); |
381 | return result; |
382 | } |
383 | #endif |
384 | |
385 | void setPayloadBaseImpl(int spid, int mtid, std::auto_ptr<PayloadBase> p, bool add) const /*sic!*/ |
386 | { |
387 | |
388 | if (!add) { |
389 | mLegacyPayload.reset(); |
390 | } |
391 | |
392 | if (!p.get()) { |
393 | if (!add) { |
394 | mPayloads.clear(); |
395 | } |
396 | return; |
397 | } |
398 | |
399 | // if !add, delete all payload variants |
400 | // (they're conversions of each other) |
401 | mPayloads.resize(add ? mPayloads.size() + 1 : 1); |
402 | _detail::TypedPayload &tp = mPayloads.back(); |
403 | tp.payload.reset(p.release()); |
404 | tp.sharedPointerId = spid; |
405 | tp.metaTypeId = mtid; |
406 | } |
407 | |
408 | void setLegacyPayloadBaseImpl(std::auto_ptr<PayloadBase> p); |
409 | void tryEnsureLegacyPayload() const; |
410 | |
411 | mutable _detail::clone_ptr<PayloadBase> mLegacyPayload; |
412 | mutable PayloadContainer mPayloads; |
413 | mutable bool mConversionInProgress; |
414 | int mRevision; |
415 | Item::Flags mFlags; |
416 | Tag::List mTags; |
417 | Entity::Id mCollectionId; |
418 | Collection::List mVirtualReferences; |
419 | qint64 mSize; |
420 | QDateTime mModificationTime; |
421 | QString mMimeType; |
422 | QString mGid; |
423 | Item::Flags mAddedFlags; |
424 | Item::Flags mDeletedFlags; |
425 | Tag::List mAddedTags; |
426 | Tag::List mDeletedTags; |
427 | QSet<QByteArray> mCachedPayloadParts; |
428 | bool mFlagsOverwritten : 1; |
429 | bool mTagsOverwritten : 1; |
430 | bool mSizeChanged : 1; |
431 | bool mClearPayload : 1; |
432 | }; |
433 | |
434 | } |
435 | |
436 | #endif |
437 | |