00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef QGLIB_REFPOINTER_H
00020 #define QGLIB_REFPOINTER_H
00021
00022 #include "global.h"
00023 #include "type.h"
00024 #include "wrap.h"
00025 #include <cstddef>
00026 #include <boost/type_traits.hpp>
00027 #include <boost/utility/enable_if.hpp>
00028 #include <QtCore/QHash>
00029
00030 namespace QGlib {
00031
00032
00033 class Object;
00034 class Interface;
00035
00036
00037 namespace Private {
00038
00039 template <class T, class X>
00040 struct RefPointerEqualityCheck {};
00041
00042 template <class T, class X>
00043 struct RefPointerEqualityCheck<T, RefPointer<X> >
00044 {
00045 static inline bool check(const RefPointer<T> & self, const RefPointer<X> & other)
00046 {
00047 if (self.m_class && other.m_class) {
00048 return self.m_class->m_object == other.m_class->m_object;
00049 } else {
00050 return self.isNull() && other.isNull();
00051 }
00052 }
00053 };
00054
00055 template <class T, class X>
00056 struct RefPointerEqualityCheck<T, X*>
00057 {
00058 static inline bool check(const RefPointer<T> & self, X* const & other)
00059 {
00060 return self.m_class ? self.m_class->m_object == other : !other;
00061 }
00062 };
00063
00064 }
00065
00066
00087 template <class T>
00088 class RefPointer
00089 {
00090 public:
00091 inline RefPointer();
00092 inline ~RefPointer();
00093
00095 explicit inline RefPointer(T *cppClass);
00096
00097 template <class X>
00098 inline RefPointer(const RefPointer<X> & other);
00099 inline RefPointer(const RefPointer<T> & other);
00100
00101 template <class X>
00102 inline RefPointer<T> & operator=(const RefPointer<X> & other);
00103 inline RefPointer<T> & operator=(const RefPointer<T> & other);
00104
00118 template <class X>
00119 bool operator==(const X & other) const;
00120 template <class X>
00121 bool operator!=(const X & other) const;
00122
00125 void clear();
00126
00127 inline bool isNull() const;
00128 inline bool operator!() const;
00129 inline T *operator->() const;
00130
00137 inline operator typename T::CType*() const;
00138
00143 static RefPointer<T> wrap(typename T::CType *nativePtr, bool increaseRef = true);
00144
00146 template <class X>
00147 RefPointer<X> staticCast() const;
00148
00162 template <class X>
00163 RefPointer<X> dynamicCast() const;
00164
00165 private:
00166 template <class X> friend class RefPointer;
00167 template <class X, class Y> friend struct Private::RefPointerEqualityCheck;
00168
00169 template <class X>
00170 void assign(const RefPointer<X> & other);
00171
00172 T *m_class;
00173 };
00174
00179 class QTGLIB_EXPORT RefCountedObject
00180 {
00181 public:
00182 virtual ~RefCountedObject() {}
00183
00184 protected:
00185 template <class T> friend class RefPointer;
00186 template <class T, class X> friend struct Private::RefPointerEqualityCheck;
00187
00188 virtual void ref(bool increaseRef) = 0;
00189 virtual void unref() = 0;
00190
00191 template <class T>
00192 inline T* object() const;
00193
00194 void *m_object;
00195 };
00196
00197 template <class T>
00198 inline T* RefCountedObject::object() const
00199 {
00200 return static_cast<T* const>(m_object);
00201 }
00202
00203
00204 template <class T>
00205 inline RefPointer<T>::RefPointer()
00206 : m_class(NULL)
00207 {
00208 }
00209
00210 template <class T>
00211 inline RefPointer<T>::~RefPointer()
00212 {
00213 clear();
00214 }
00215
00216 template <class T>
00217 inline RefPointer<T>::RefPointer(T *cppClass)
00218 : m_class(cppClass)
00219 {
00220 static_cast<RefCountedObject*>(m_class)->ref(true);
00221 }
00222
00223 template <class T>
00224 template <class X>
00225 inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
00226 : m_class(NULL)
00227 {
00228 assign(other);
00229 }
00230
00231 template <class T>
00232 inline RefPointer<T>::RefPointer(const RefPointer<T> & other)
00233 : m_class(NULL)
00234 {
00235 assign(other);
00236 }
00237
00238 template <class T>
00239 template <class X>
00240 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<X> & other)
00241 {
00242 clear();
00243 assign(other);
00244 return *this;
00245 }
00246
00247 template <class T>
00248 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<T> & other)
00249 {
00250 clear();
00251 assign(other);
00252 return *this;
00253 }
00254
00255 template <class T>
00256 template <class X>
00257 void RefPointer<T>::assign(const RefPointer<X> & other)
00258 {
00259
00260 QGLIB_STATIC_ASSERT((boost::is_base_of<T, X>::value),
00261 "Cannot implicitly cast a RefPointer down the hierarchy");
00262
00263 if (!other.isNull()) {
00264 m_class = static_cast<T*>(other.m_class);
00265 static_cast<RefCountedObject*>(m_class)->ref(true);
00266 }
00267 }
00268
00269 template <class T>
00270 template <class X>
00271 bool RefPointer<T>::operator==(const X & other) const
00272 {
00273 return Private::RefPointerEqualityCheck<T, X>::check(*this, other);
00274 }
00275
00276 template <class T>
00277 template <class X>
00278 bool RefPointer<T>::operator!=(const X & other) const
00279 {
00280 return !Private::RefPointerEqualityCheck<T, X>::check(*this, other);
00281 }
00282
00286 template <class T, class X>
00287
00288
00289 typename boost::enable_if_c<
00290 boost::is_pointer<X>::value &&
00291 !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
00292 bool
00293 >::type
00294 operator==(const X & other, const RefPointer<T> & self)
00295 {
00296 return Private::RefPointerEqualityCheck<T, X>::check(self, other);
00297 }
00298
00302 template <class T, class X>
00303
00304
00305 typename boost::enable_if_c<
00306 boost::is_pointer<X>::value &&
00307 !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
00308 bool
00309 >::type
00310 operator!=(const X & other, const RefPointer<T> & self)
00311 {
00312 return !Private::RefPointerEqualityCheck<T, X>::check(self, other);
00313 }
00314
00315 template <class T>
00316 void RefPointer<T>::clear()
00317 {
00318 if (!isNull()) {
00319 static_cast<RefCountedObject*>(m_class)->unref();
00320 m_class = NULL;
00321 }
00322 }
00323
00324
00325 template <class T>
00326 RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef)
00327 {
00328 RefPointer<T> ptr;
00329 if (nativePtr != NULL) {
00330 RefCountedObject *cppObj = WrapImpl<T>::wrap(nativePtr);
00331 cppObj->ref(increaseRef);
00332 ptr.m_class = dynamic_cast<T*>(cppObj);
00333 Q_ASSERT(ptr.m_class);
00334 }
00335 return ptr;
00336 }
00337
00338 template <class T>
00339 inline bool RefPointer<T>::isNull() const
00340 {
00341 return m_class == NULL;
00342 }
00343
00344 template <class T>
00345 inline bool RefPointer<T>::operator!() const
00346 {
00347 return m_class == NULL;
00348 }
00349
00350 template <class T>
00351 inline T *RefPointer<T>::operator->() const
00352 {
00353 Q_ASSERT_X(!isNull(), "RefPointer::operator->() const",
00354 "Attempted to dereference a null pointer");
00355 return m_class;
00356 }
00357
00358 template <class T>
00359 inline RefPointer<T>::operator typename T::CType*() const
00360 {
00361 return m_class ? static_cast<RefCountedObject*>(m_class)->object<typename T::CType>() : NULL;
00362 }
00363
00364 template <class T>
00365 template <class X>
00366 RefPointer<X> RefPointer<T>::staticCast() const
00367 {
00368 RefPointer<X> result;
00369 if (m_class) {
00370 static_cast<RefCountedObject*>(m_class)->ref(true);
00371 result.m_class = static_cast<X*>(m_class);
00372 }
00373 return result;
00374 }
00375
00376
00377 namespace Private {
00378
00379 template <typename T, typename X, typename Enable = void>
00380 struct IfaceDynamicCastImpl
00381 {
00382 static inline X *doCast(typename X::CType *obj)
00383 {
00384 Q_UNUSED(obj);
00385 return NULL;
00386 }
00387 };
00388
00389
00390
00391 template <typename T, typename X>
00392 struct IfaceDynamicCastImpl<T, X,
00393 typename boost::enable_if_c<
00394
00395
00396 (boost::is_base_of<Interface, X>::value &&
00397 !boost::is_base_of<Object, X>::value &&
00398 boost::is_base_of<Object, T>::value)
00399 >::type
00400 >
00401 {
00402 static inline X *doCast(typename X::CType *obj)
00403 {
00404 X *targetClass = NULL;
00405
00406
00407
00408 if (Type::fromInstance(obj).isA(GetType<X>()))
00409 {
00410 targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
00411 Q_ASSERT(targetClass);
00412 }
00413
00414 return targetClass;
00415 }
00416 };
00417
00418
00419
00420 template <typename T, typename X>
00421 struct IfaceDynamicCastImpl<T, X,
00422 typename boost::enable_if_c<
00423
00424
00425 (boost::is_base_of<Interface, T>::value &&
00426 !boost::is_base_of<Object, T>::value)
00427 >::type
00428 >
00429 {
00430 static inline X *doCast(typename X::CType *obj)
00431 {
00432
00433
00434 RefCountedObject *cppClass = Private::wrapObject(obj);
00435
00436
00437 X *targetClass = dynamic_cast<X*>(cppClass);
00438
00439 if (!targetClass) {
00440
00441
00442
00443
00444 if (boost::is_base_of<Interface, X>::value &&
00445 !boost::is_base_of<Object, X>::value &&
00446 Type::fromInstance(obj).isA(GetType<X>()))
00447 {
00448 targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
00449 Q_ASSERT(targetClass);
00450 }
00451 }
00452
00453 return targetClass;
00454 }
00455 };
00456
00457 }
00458
00459
00460 template <class T>
00461 template <class X>
00462 RefPointer<X> RefPointer<T>::dynamicCast() const
00463 {
00464 RefPointer<X> result;
00465 if (m_class) {
00466 X *targetClass = dynamic_cast<X*>(m_class);
00467 if (!targetClass) {
00468
00469
00470 typename X::CType *obj = static_cast<RefCountedObject*>(m_class)->object<typename X::CType>();
00471 targetClass = Private::IfaceDynamicCastImpl<T, X>::doCast(obj);
00472 }
00473
00474 if (targetClass) {
00475 static_cast<RefCountedObject*>(targetClass)->ref(true);
00476 result.m_class = targetClass;
00477 }
00478 }
00479
00480 return result;
00481 }
00482
00483
00484 template <class T>
00485 struct GetTypeImpl< RefPointer<T> >
00486 {
00487 inline operator Type() { return GetType<T>(); }
00488 };
00489
00491 template <typename T>
00492 inline uint qHash(const RefPointer<T> & ptr)
00493 {
00494 return qHash(static_cast<typename T::CType*>(ptr));
00495 }
00496
00497 }
00498
00499 #endif