QtGStreamer  0.10.2
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
refpointer.h
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 Lesser 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 #include <QtCore/QHash>
00029 
00030 namespace QGlib {
00031 
00032 //forward declarations
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 } //namespace Private
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     //T should be a base class of X
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 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
00288 //it is ambiguous with RefPointer::operator==() and the built-in operator== for pointers.
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 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
00304 //it is ambiguous with RefPointer::operator!=() and the built-in operator!= for pointers.
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(); //this may delete m_class at this point
00320         m_class = NULL;
00321     }
00322 }
00323 
00324 //static
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 //this version is compiled if X is an interface and T is an object,
00390 //i.e. we are dynamically casting from an object to an interface.
00391 template <typename T, typename X>
00392 struct IfaceDynamicCastImpl<T, X,
00393         typename boost::enable_if_c<
00394             //to check if something is an interface, we need to also verify that it does
00395             //not inherit Object, since derived object classes may also derive from interfaces.
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         //Check that instanceType implements (isA) the interface
00407         //and if it does, return a wrapper for that interface.
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 //this version is compiled if T is an interface,
00419 //i.e. we are dynamically casting from an interface to either an object or another interface.
00420 template <typename T, typename X>
00421 struct IfaceDynamicCastImpl<T, X,
00422         typename boost::enable_if_c<
00423             //to check if something is an interface, we need to also verify that it does
00424             //not inherit Object, since derived object classes may also derive from interfaces.
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         //get the instance type and try to create (or rather fetch from the GObject qdata)
00433         //the C++ wrapper class for this type of object.
00434         RefCountedObject *cppClass = Private::wrapObject(obj);
00435 
00436         //attempt to cast it to X
00437         X *targetClass = dynamic_cast<X*>(cppClass);
00438 
00439         if (!targetClass) {
00440             //Cast failed. This either means that X is something that our instance is not
00441             //or that X is another interface that is not inherited by the wrapper class
00442             //for this instance type, but it is possible that our instance actually
00443             //implements it, so let's check it.
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 } //namespace Private
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             //in case either X or T is an interface, we need to do some extra checks.
00469             //this is a template to optimize the compiled code depending on what X and T are.
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 // trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >()
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 } //namespace QGlib
00498 
00499 #endif