QtGStreamer 0.10.1
|
00001 /* 00002 Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com> 00003 Copyright (C) 2010 Collabora Ltd. 00004 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> 00005 00006 This library is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU Lesser General Public License as published 00008 by the Free Software Foundation; either version 2.1 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU Lesser General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 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 //forward declarations 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 } //namespace Private 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 //T should be a base class of X 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 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise 00287 //it is ambiguous with RefPointer::operator==() and the built-in operator== for pointers. 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 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise 00303 //it is ambiguous with RefPointer::operator!=() and the built-in operator!= for pointers. 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(); //this may delete m_class at this point 00319 m_class = NULL; 00320 } 00321 } 00322 00323 //static 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 //this version is compiled if X is an interface and T is an object, 00389 //i.e. we are dynamically casting from an object to an interface. 00390 template <typename T, typename X> 00391 struct IfaceDynamicCastImpl<T, X, 00392 typename boost::enable_if_c< 00393 //to check if something is an interface, we need to also verify that it does 00394 //not inherit Object, since derived object classes may also derive from interfaces. 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 //Check that instanceType implements (isA) the interface 00406 //and if it does, return a wrapper for that interface. 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 //this version is compiled if T is an interface, 00418 //i.e. we are dynamically casting from an interface to either an object or another interface. 00419 template <typename T, typename X> 00420 struct IfaceDynamicCastImpl<T, X, 00421 typename boost::enable_if_c< 00422 //to check if something is an interface, we need to also verify that it does 00423 //not inherit Object, since derived object classes may also derive from interfaces. 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 //get the instance type and try to create (or rather fetch from the GObject qdata) 00432 //the C++ wrapper class for this type of object. 00433 RefCountedObject *cppClass = Private::wrapObject(obj); 00434 00435 //attempt to cast it to X 00436 X *targetClass = dynamic_cast<X*>(cppClass); 00437 00438 if (!targetClass) { 00439 //Cast failed. This either means that X is something that our instance is not 00440 //or that X is another interface that is not inherited by the wrapper class 00441 //for this instance type, but it is possible that our instance actually 00442 //implements it, so let's check it. 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 } //namespace Private 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 //in case either X or T is an interface, we need to do some extra checks. 00468 //this is a template to optimize the compiled code depending on what X and T are. 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 // trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >() 00483 template <class T> 00484 struct GetTypeImpl< RefPointer<T> > 00485 { 00486 inline operator Type() { return GetType<T>(); } 00487 }; 00488 00489 } 00490 00491 #endif