QtGStreamer 0.10.1

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 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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator