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 | |
47 | namespace Akonadi { |
48 | namespace Internal { |
49 | |
50 | template <typename T> |
51 | struct has_clone_method { |
52 | private: |
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> *); |
65 | public: |
66 | static const bool value = sizeof (test<T>(0)) == sizeof (Yes) ; |
67 | }; |
68 | |
69 | template <typename T, bool b> |
70 | struct 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 | |
81 | template <typename T> |
82 | struct clone_traits_helper<T, true> |
83 | { |
84 | static T *clone(T *t) |
85 | { |
86 | return t ? t->clone() : 0 ; |
87 | } |
88 | }; |
89 | |
90 | template <typename T> |
91 | struct clone_traits : clone_traits_helper<T, has_clone_method<T>::value> {}; |
92 | |
93 | template <typename T> |
94 | struct shared_pointer_traits |
95 | { |
96 | static const bool defined = false; |
97 | }; |
98 | |
99 | template <typename T> |
100 | struct 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 | |
111 | template <typename T> |
112 | struct 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 | |
123 | template <typename T> |
124 | struct is_shared_pointer |
125 | { |
126 | static const bool value = shared_pointer_traits<T>::defined; |
127 | }; |
128 | |
129 | template <typename T> |
130 | struct get_hierarchy_root; |
131 | |
132 | template <typename T, typename S> |
133 | struct get_hierarchy_root_recurse |
134 | : get_hierarchy_root<S> |
135 | { |
136 | }; |
137 | |
138 | template <typename T> |
139 | struct get_hierarchy_root_recurse<T, T> |
140 | : boost::mpl::identity<T> |
141 | { |
142 | }; |
143 | |
144 | template <typename T> |
145 | struct get_hierarchy_root |
146 | : get_hierarchy_root_recurse< T, typename ::KPIMUtils::SuperClass<T>::Type > |
147 | { |
148 | }; |
149 | |
150 | template <typename T> |
151 | struct get_hierarchy_root< boost::shared_ptr<T> > |
152 | { |
153 | typedef boost::shared_ptr< typename get_hierarchy_root<T>::type > type; |
154 | }; |
155 | |
156 | template <typename T> |
157 | struct 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 | */ |
168 | template <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 | */ |
225 | template <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 | */ |
273 | template <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 | */ |
323 | struct 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 | */ |
337 | template <typename T> |
338 | struct 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 | */ |
365 | template <typename T> |
366 | struct Payload<T *> : public PayloadBase |
367 | { |
368 | }; |
369 | |
370 | namespace Internal { |
371 | |
372 | /** |
373 | @internal |
374 | Basically a dynamic_cast that also works across DSO boundaries. |
375 | */ |
376 | template <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 | |