QtGStreamer  0.10.1
 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 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 #ifdef Q_MOC_RUN
00023 #define BOOST_TT_HAS_OPERATOR_HPP_INCLUDED
00024 #endif
00025 
00026 #include "global.h"
00027 #include "type.h"
00028 #include "wrap.h"
00029 #include <cstddef>
00030 #include <boost/type_traits.hpp>
00031 #include <boost/utility/enable_if.hpp>
00032 
00033 namespace QGlib {
00034 
00035 //forward declarations
00036 class Object;
00037 class Interface;
00038 
00039 
00040 namespace Private {
00041 
00042 template <class T, class X>
00043 struct RefPointerEqualityCheck {};
00044 
00045 template <class T, class X>
00046 struct RefPointerEqualityCheck<T, RefPointer<X> >
00047 {
00048     static inline bool check(const RefPointer<T> & self, const RefPointer<X> & other)
00049     {
00050         if (self.m_class && other.m_class) {
00051             return self.m_class->m_object == other.m_class->m_object;
00052         } else {
00053             return self.isNull() && other.isNull();
00054         }
00055     }
00056 };
00057 
00058 template <class T, class X>
00059 struct RefPointerEqualityCheck<T, X*>
00060 {
00061     static inline bool check(const RefPointer<T> & self, X* const & other)
00062     {
00063         return self.m_class ? self.m_class->m_object == other : !other;
00064     }
00065 };
00066 
00067 } //namespace Private
00068 
00069 
00090 template <class T>
00091 class RefPointer
00092 {
00093 public:
00094     inline RefPointer();
00095     inline ~RefPointer();
00096 
00098     explicit inline RefPointer(T *cppClass);
00099 
00100     template <class X>
00101     inline RefPointer(const RefPointer<X> & other);
00102     inline RefPointer(const RefPointer<T> & other);
00103 
00104     template <class X>
00105     inline RefPointer<T> & operator=(const RefPointer<X> & other);
00106     inline RefPointer<T> & operator=(const RefPointer<T> & other);
00107 
00121     template <class X>
00122     bool operator==(const X & other) const;
00123     template <class X>
00124     bool operator!=(const X & other) const; 
00125 
00128     void clear();
00129 
00130     inline bool isNull() const;
00131     inline bool operator!() const;
00132     inline T *operator->() const;
00133 
00140     inline operator typename T::CType*() const;
00141 
00146     static RefPointer<T> wrap(typename T::CType *nativePtr, bool increaseRef = true);
00147 
00149     template <class X>
00150     RefPointer<X> staticCast() const;
00151 
00165     template <class X>
00166     RefPointer<X> dynamicCast() const;
00167 
00168 private:
00169     template <class X> friend class RefPointer;
00170     template <class X, class Y> friend struct Private::RefPointerEqualityCheck;
00171 
00172     template <class X>
00173     void assign(const RefPointer<X> & other);
00174 
00175     T *m_class;
00176 };
00177 
00182 class QTGLIB_EXPORT RefCountedObject
00183 {
00184 public:
00185     virtual ~RefCountedObject() {}
00186 
00187 protected:
00188     template <class T> friend class RefPointer;
00189     template <class T, class X> friend struct Private::RefPointerEqualityCheck;
00190 
00191     virtual void ref(bool increaseRef) = 0;
00192     virtual void unref() = 0;
00193 
00194     template <class T>
00195     inline T* object() const;
00196 
00197     void *m_object;
00198 };
00199 
00200 template <class T>
00201 inline T* RefCountedObject::object() const
00202 {
00203     return static_cast<T* const>(m_object);
00204 }
00205 
00206 
00207 template <class T>
00208 inline RefPointer<T>::RefPointer()
00209     : m_class(NULL)
00210 {
00211 }
00212 
00213 template <class T>
00214 inline RefPointer<T>::~RefPointer()
00215 {
00216     clear();
00217 }
00218 
00219 template <class T>
00220 inline RefPointer<T>::RefPointer(T *cppClass)
00221     : m_class(cppClass)
00222 {
00223     static_cast<RefCountedObject*>(m_class)->ref(true);
00224 }
00225 
00226 template <class T>
00227 template <class X>
00228 inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
00229     : m_class(NULL)
00230 {
00231     assign(other);
00232 }
00233 
00234 template <class T>
00235 inline RefPointer<T>::RefPointer(const RefPointer<T> & other)
00236     : m_class(NULL)
00237 {
00238     assign(other);
00239 }
00240 
00241 template <class T>
00242 template <class X>
00243 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<X> & other)
00244 {
00245     clear();
00246     assign(other);
00247     return *this;
00248 }
00249 
00250 template <class T>
00251 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<T> & other)
00252 {
00253     clear();
00254     assign(other);
00255     return *this;
00256 }
00257 
00258 template <class T>
00259 template <class X>
00260 void RefPointer<T>::assign(const RefPointer<X> & other)
00261 {
00262     //T should be a base class of X
00263     QGLIB_STATIC_ASSERT((boost::is_base_of<T, X>::value),
00264                         "Cannot implicitly cast a RefPointer down the hierarchy");
00265 
00266     if (!other.isNull()) {
00267         m_class = static_cast<T*>(other.m_class);
00268         static_cast<RefCountedObject*>(m_class)->ref(true);
00269     }
00270 }
00271 
00272 template <class T>
00273 template <class X>
00274 bool RefPointer<T>::operator==(const X & other) const
00275 {
00276     return Private::RefPointerEqualityCheck<T, X>::check(*this, other);
00277 }
00278 
00279 template <class T>
00280 template <class X>
00281 bool RefPointer<T>::operator!=(const X & other) const
00282 {
00283     return !Private::RefPointerEqualityCheck<T, X>::check(*this, other);
00284 }
00285 
00289 template <class T, class X>
00290 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
00291 //it is ambiguous with RefPointer::operator==() and the built-in operator== for pointers.
00292 typename boost::enable_if_c<
00293     boost::is_pointer<X>::value &&
00294     !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
00295     bool
00296 >::type
00297 operator==(const X & other, const RefPointer<T> & self)
00298 {
00299     return Private::RefPointerEqualityCheck<T, X>::check(self, other);
00300 }
00301 
00305 template <class T, class X>
00306 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
00307 //it is ambiguous with RefPointer::operator!=() and the built-in operator!= for pointers.
00308 typename boost::enable_if_c<
00309     boost::is_pointer<X>::value &&
00310     !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
00311     bool
00312 >::type
00313 operator!=(const X & other, const RefPointer<T> & self)
00314 {
00315     return !Private::RefPointerEqualityCheck<T, X>::check(self, other);
00316 }
00317 
00318 template <class T>
00319 void RefPointer<T>::clear()
00320 {
00321     if (!isNull()) {
00322         static_cast<RefCountedObject*>(m_class)->unref(); //this may delete m_class at this point
00323         m_class = NULL;
00324     }
00325 }
00326 
00327 //static
00328 template <class T>
00329 RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef)
00330 {
00331     RefPointer<T> ptr;
00332     if (nativePtr != NULL) {
00333         RefCountedObject *cppObj = WrapImpl<T>::wrap(nativePtr);
00334         cppObj->ref(increaseRef);
00335         ptr.m_class = dynamic_cast<T*>(cppObj);
00336         Q_ASSERT(ptr.m_class);
00337     }
00338     return ptr;
00339 }
00340 
00341 template <class T>
00342 inline bool RefPointer<T>::isNull() const
00343 {
00344     return m_class == NULL;
00345 }
00346 
00347 template <class T>
00348 inline bool RefPointer<T>::operator!() const
00349 {
00350     return m_class == NULL;
00351 }
00352 
00353 template <class T>
00354 inline T *RefPointer<T>::operator->() const
00355 {
00356     Q_ASSERT_X(!isNull(), "RefPointer::operator->() const",
00357                "Attempted to dereference a null pointer");
00358     return m_class;
00359 }
00360 
00361 template <class T>
00362 inline RefPointer<T>::operator typename T::CType*() const
00363 {
00364     return m_class ? static_cast<RefCountedObject*>(m_class)->object<typename T::CType>() : NULL;
00365 }
00366 
00367 template <class T>
00368 template <class X>
00369 RefPointer<X> RefPointer<T>::staticCast() const
00370 {
00371     RefPointer<X> result;
00372     if (m_class) {
00373         static_cast<RefCountedObject*>(m_class)->ref(true);
00374         result.m_class = static_cast<X*>(m_class);
00375     }
00376     return result;
00377 }
00378 
00379 
00380 namespace Private {
00381 
00382 template <typename T, typename X, typename Enable = void>
00383 struct IfaceDynamicCastImpl
00384 {
00385     static inline X *doCast(typename X::CType *obj)
00386     {
00387         Q_UNUSED(obj);
00388         return NULL;
00389     }
00390 };
00391 
00392 //this version is compiled if X is an interface and T is an object,
00393 //i.e. we are dynamically casting from an object to an interface.
00394 template <typename T, typename X>
00395 struct IfaceDynamicCastImpl<T, X,
00396         typename boost::enable_if_c<
00397             //to check if something is an interface, we need to also verify that it does
00398             //not inherit Object, since derived object classes may also derive from interfaces.
00399             (boost::is_base_of<Interface, X>::value &&
00400              !boost::is_base_of<Object, X>::value &&
00401              boost::is_base_of<Object, T>::value)
00402         >::type
00403     >
00404 {
00405     static inline X *doCast(typename X::CType *obj)
00406     {
00407         X *targetClass = NULL;
00408 
00409         //Check that instanceType implements (isA) the interface
00410         //and if it does, return a wrapper for that interface.
00411         if (Type::fromInstance(obj).isA(GetType<X>()))
00412         {
00413             targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
00414             Q_ASSERT(targetClass);
00415         }
00416 
00417         return targetClass;
00418     }
00419 };
00420 
00421 //this version is compiled if T is an interface,
00422 //i.e. we are dynamically casting from an interface to either an object or another interface.
00423 template <typename T, typename X>
00424 struct IfaceDynamicCastImpl<T, X,
00425         typename boost::enable_if_c<
00426             //to check if something is an interface, we need to also verify that it does
00427             //not inherit Object, since derived object classes may also derive from interfaces.
00428             (boost::is_base_of<Interface, T>::value &&
00429              !boost::is_base_of<Object, T>::value)
00430         >::type
00431     >
00432 {
00433     static inline X *doCast(typename X::CType *obj)
00434     {
00435         //get the instance type and try to create (or rather fetch from the GObject qdata)
00436         //the C++ wrapper class for this type of object.
00437         RefCountedObject *cppClass = Private::wrapObject(obj);
00438 
00439         //attempt to cast it to X
00440         X *targetClass = dynamic_cast<X*>(cppClass);
00441 
00442         if (!targetClass) {
00443             //Cast failed. This either means that X is something that our instance is not
00444             //or that X is another interface that is not inherited by the wrapper class
00445             //for this instance type, but it is possible that our instance actually
00446             //implements it, so let's check it.
00447             if (boost::is_base_of<Interface, X>::value &&
00448                 !boost::is_base_of<Object, X>::value &&
00449                 Type::fromInstance(obj).isA(GetType<X>()))
00450             {
00451                 targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
00452                 Q_ASSERT(targetClass);
00453             }
00454         }
00455 
00456         return targetClass;
00457     }
00458 };
00459 
00460 } //namespace Private
00461 
00462 
00463 template <class T>
00464 template <class X>
00465 RefPointer<X> RefPointer<T>::dynamicCast() const
00466 {
00467     RefPointer<X> result;
00468     if (m_class) {
00469         X *targetClass = dynamic_cast<X*>(m_class);
00470         if (!targetClass) {
00471             //in case either X or T is an interface, we need to do some extra checks.
00472             //this is a template to optimize the compiled code depending on what X and T are.
00473             typename X::CType *obj = static_cast<RefCountedObject*>(m_class)->object<typename X::CType>();
00474             targetClass = Private::IfaceDynamicCastImpl<T, X>::doCast(obj);
00475         }
00476 
00477         if (targetClass) {
00478             static_cast<RefCountedObject*>(targetClass)->ref(true);
00479             result.m_class = targetClass;
00480         }
00481     }
00482 
00483     return result;
00484 }
00485 
00486 // trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >()
00487 template <class T>
00488 struct GetTypeImpl< RefPointer<T> >
00489 {
00490     inline operator Type() { return GetType<T>(); }
00491 };
00492 
00493 }
00494 
00495 #endif
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator