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