1/*
2 Copyright (c) 2007 Till Adam <adam@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 ITEMPAYLOADINTERNALS_P_H
21#define ITEMPAYLOADINTERNALS_P_H
22
23#include <kpimutils/supertrait.h>
24
25#include <QtCore/QtGlobal>
26#include <QtCore/QSharedPointer>
27#include <QtCore/QMetaType>
28
29#include <boost/shared_ptr.hpp>
30#include <boost/type_traits/is_same.hpp>
31#include <boost/mpl/eval_if.hpp>
32#include <boost/mpl/identity.hpp>
33#include <boost/utility/enable_if.hpp>
34
35#include <typeinfo>
36
37#include "exception.h"
38
39//@cond PRIVATE Doxygen 1.7.1 hangs processing this file. so skip it.
40//for more info, see https://bugzilla.gnome.org/show_bug.cgi?id=531637
41
42/* WARNING
43 * The below is an implementation detail of the Item class. It is not to be
44 * considered public API, and subject to change without notice
45 */
46
47namespace Akonadi {
48namespace Internal {
49
50template <typename T>
51struct has_clone_method {
52private:
53 template <typename S, S * (S::*)() const> struct sfinae
54 {
55 };
56 struct No
57 {
58 };
59 struct Yes
60 {
61 No no[2];
62 };
63 template <typename S> static No test(...);
64 template <typename S> static Yes test(sfinae<S, &S::clone> *);
65public:
66 static const bool value = sizeof (test<T>(0)) == sizeof (Yes) ;
67};
68
69template <typename T, bool b>
70struct clone_traits_helper {
71 // runtime error (commented in) or compiletime error (commented out)?
72 // ### runtime error, until we check has_clone_method in the
73 // ### Item::payload<T> impl directly...
74 template <typename U>
75 static T *clone(U)
76 {
77 return 0;
78 }
79};
80
81template <typename T>
82struct clone_traits_helper<T, true>
83{
84 static T *clone(T *t)
85 {
86 return t ? t->clone() : 0 ;
87 }
88};
89
90template <typename T>
91struct clone_traits : clone_traits_helper<T, has_clone_method<T>::value> {};
92
93template <typename T>
94struct shared_pointer_traits
95{
96 static const bool defined = false;
97};
98
99template <typename T>
100struct shared_pointer_traits< boost::shared_ptr<T> >
101{
102 static const bool defined = true;
103 typedef T element_type;
104 template <typename S>
105 struct make {
106 typedef boost::shared_ptr<S> type;
107 };
108 typedef QSharedPointer<T> next_shared_ptr;
109};
110
111template <typename T>
112struct shared_pointer_traits< QSharedPointer<T> >
113{
114 static const bool defined = true;
115 typedef T element_type;
116 template <typename S>
117 struct make {
118 typedef QSharedPointer<S> type;
119 };
120 typedef boost::shared_ptr<T> next_shared_ptr;
121};
122
123template <typename T>
124struct is_shared_pointer
125{
126 static const bool value = shared_pointer_traits<T>::defined;
127};
128
129template <typename T>
130struct get_hierarchy_root;
131
132template <typename T, typename S>
133struct get_hierarchy_root_recurse
134 : get_hierarchy_root<S>
135{
136};
137
138template <typename T>
139struct get_hierarchy_root_recurse<T, T>
140 : boost::mpl::identity<T>
141{
142};
143
144template <typename T>
145struct get_hierarchy_root
146 : get_hierarchy_root_recurse< T, typename ::KPIMUtils::SuperClass<T>::Type >
147{
148};
149
150template <typename T>
151struct get_hierarchy_root< boost::shared_ptr<T> >
152{
153 typedef boost::shared_ptr< typename get_hierarchy_root<T>::type > type;
154};
155
156template <typename T>
157struct get_hierarchy_root< QSharedPointer<T> >
158{
159 typedef QSharedPointer< typename get_hierarchy_root<T>::type > type;
160};
161
162/**
163 @internal
164 Payload type traits. Implements specialized handling for polymorphic types and smart pointers.
165 The default one is never used (as isPolymorphic is always false) and only contains safe dummy
166 implementations to make the compiler happy (in practice it will always optimized away anyway).
167*/
168template <typename T> struct PayloadTrait
169{
170 /// type of the payload object contained inside a shared pointer
171 typedef T ElementType;
172 // the metatype id for the element type, or for pointer-to-element
173 // type, if in a shared pointer
174 static int elementMetaTypeId()
175 {
176 return qMetaTypeId<T>();
177 }
178 /// type of the base class of the payload object inside a shared pointer,
179 /// same as ElementType if there is no super class
180 typedef typename KPIMUtils::SuperClass<T>::Type SuperElementType;
181 /// type of this payload object
182 typedef T Type;
183 /// type of the payload to store a base class of this payload
184 /// (eg. a shared pointer containing a pointer to SuperElementType)
185 /// same as Type if there is not super class
186 typedef typename KPIMUtils::SuperClass<T>::Type SuperType;
187 /// indicates if this payload is polymorphic, that is is a shared pointer
188 /// and has a known super class
189 static const bool isPolymorphic = false;
190 /// checks an object of this payload type for being @c null
191 static inline bool isNull(const Type &p)
192 {
193 Q_UNUSED(p);
194 return true;
195 }
196 /// casts to Type from @c U
197 /// throws a PayloadException if casting failed
198 template <typename U> static inline Type castFrom(const U &)
199 {
200 throw PayloadException("you should never get here");
201 }
202 /// tests if casting from @c U to Type is possible
203 template <typename U> static inline bool canCastFrom(const U &)
204 {
205 return false;
206 }
207 /// cast to @c U from Type
208 template <typename U> static inline U castTo(const Type &)
209 {
210 throw PayloadException("you should never get here");
211 }
212 template <typename U> static T clone(const U &)
213 {
214 throw PayloadException("clone: you should never get here");
215 }
216 /// defines the type of shared pointer used (0: none, > 0: boost::shared_ptr, QSharedPointer, ...)
217 static const unsigned int sharedPointerId = 0;
218};
219
220/**
221 @internal
222 Payload type trait specialization for boost::shared_ptr
223 for documentation of the various members, see above
224*/
225template <typename T> struct PayloadTrait<boost::shared_ptr<T> >
226{
227 typedef T ElementType;
228 static int elementMetaTypeId()
229 {
230 return qMetaTypeId<T *>();
231 }
232 typedef typename KPIMUtils::SuperClass<T>::Type SuperElementType;
233 typedef boost::shared_ptr<ElementType> Type;
234 typedef boost::shared_ptr<SuperElementType> SuperType;
235 static const bool isPolymorphic = !boost::is_same<ElementType, SuperElementType>::value;
236 static inline bool isNull(const Type &p)
237 {
238 return p.get() == 0;
239 }
240 template <typename U> static inline Type castFrom(const boost::shared_ptr<U> &p)
241 {
242 const Type sp = boost::dynamic_pointer_cast<T, U>(p);
243 if (sp.get() != 0 || p.get() == 0) {
244 return sp;
245 }
246 throw PayloadException("boost::dynamic_pointer_cast failed");
247 }
248 template <typename U> static inline bool canCastFrom(const boost::shared_ptr<U> &p)
249 {
250 const Type sp = boost::dynamic_pointer_cast<T, U>(p);
251 return sp.get() != 0 || p.get() == 0;
252 }
253 template <typename U> static inline boost::shared_ptr<U> castTo(const Type &p)
254 {
255 const boost::shared_ptr<U> sp = boost::dynamic_pointer_cast<U>(p);
256 return sp;
257 }
258 static boost::shared_ptr<T> clone(const QSharedPointer<T> &t) {
259 if (T *nt = clone_traits<T>::clone(t.data())) {
260 return boost::shared_ptr<T>(nt);
261 } else {
262 return boost::shared_ptr<T>();
263 }
264 }
265 static const unsigned int sharedPointerId = 1;
266};
267
268/**
269 @internal
270 Payload type trait specialization for QSharedPointer
271 for documentation of the various members, see above
272*/
273template <typename T> struct PayloadTrait<QSharedPointer<T> >
274{
275 typedef T ElementType;
276 static int elementMetaTypeId()
277 {
278 return qMetaTypeId<T *>();
279 }
280 typedef typename KPIMUtils::SuperClass<T>::Type SuperElementType;
281 typedef QSharedPointer<T> Type;
282 typedef QSharedPointer<SuperElementType> SuperType;
283 static const bool isPolymorphic = !boost::is_same<ElementType, SuperElementType>::value;
284 static inline bool isNull(const Type &p)
285 {
286 return p.isNull();
287 }
288 template <typename U> static inline Type castFrom(const QSharedPointer<U> &p)
289 {
290 const Type sp = qSharedPointerDynamicCast<T, U>(p);
291 if (!sp.isNull() || p.isNull()) {
292 return sp;
293 }
294 throw PayloadException("qSharedPointerDynamicCast failed");
295 }
296 template <typename U> static inline bool canCastFrom(const QSharedPointer<U> &p)
297 {
298 const Type sp = qSharedPointerDynamicCast<T, U>(p);
299 return !sp.isNull() || p.isNull();
300 }
301 template <typename U> static inline QSharedPointer<U> castTo(const Type &p)
302 {
303 const QSharedPointer<U> sp = qSharedPointerDynamicCast<U, T>(p);
304 return sp;
305 }
306 static QSharedPointer<T> clone(const boost::shared_ptr<T> &t) {
307 if (T *nt = clone_traits<T>::clone(t.get())) {
308 return QSharedPointer<T>(nt);
309 } else {
310 return QSharedPointer<T>();
311 }
312 }
313 static const unsigned int sharedPointerId = 2;
314};
315
316}
317
318/**
319 * @internal
320 * Non-template base class for the payload container.
321 * @note Move to Internal namespace for KDE5
322 */
323struct PayloadBase
324{
325 virtual ~PayloadBase()
326 {
327 }
328 virtual PayloadBase *clone() const = 0;
329 virtual const char *typeName() const = 0;
330};
331
332/**
333 * @internal
334 * Container for the actual payload object.
335 * @note Move to Internal namespace for KDE5
336 */
337template <typename T>
338struct Payload : public PayloadBase
339{
340 Payload()
341 {
342 }
343 Payload(const T &p)
344 : payload(p)
345 {
346 }
347
348 PayloadBase *clone() const
349 {
350 return new Payload<T>(const_cast<Payload<T>* >(this)->payload);
351 }
352
353 const char *typeName() const
354 {
355 return typeid (const_cast<Payload<T>*>(this)).name();
356 }
357
358 T payload;
359};
360
361/**
362 * @internal
363 * abstract, will therefore always fail to compile for pointer payloads
364 */
365template <typename T>
366struct Payload<T *> : public PayloadBase
367{
368};
369
370namespace Internal {
371
372/**
373 @internal
374 Basically a dynamic_cast that also works across DSO boundaries.
375*/
376template <typename T> inline Payload<T> *payload_cast(PayloadBase *payloadBase)
377{
378 Payload<T> *p = dynamic_cast<Payload<T>*>(payloadBase);
379 // try harder to cast, workaround for some gcc issue with template instances in multiple DSO's
380 if (!p && payloadBase && strcmp(payloadBase->typeName(), typeid (p).name()) == 0) {
381 p = static_cast<Payload<T>*>(payloadBase);
382 }
383 return p;
384}
385
386}
387
388}
389//@endcond
390
391#endif
392