QtGStreamer  1.2.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
refpointer.h
1 /*
2  Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
3  Copyright (C) 2010 Collabora Ltd.
4  @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
5 
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation; either version 2.1 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef QGLIB_REFPOINTER_H
20 #define QGLIB_REFPOINTER_H
21 
22 #include "global.h"
23 #include "type.h"
24 #include "wrap.h"
25 #include <cstddef>
26 #include <boost/type_traits.hpp>
27 #include <boost/utility/enable_if.hpp>
28 #include <QtCore/QHash>
29 
30 namespace QGlib {
31 
32 //forward declarations
33 class Object;
34 class Interface;
35 
36 
37 namespace Private {
38 
39 template <class T, class X>
40 struct RefPointerEqualityCheck {};
41 
42 template <class T, class X>
43 struct RefPointerEqualityCheck<T, RefPointer<X> >
44 {
45  static inline bool check(const RefPointer<T> & self, const RefPointer<X> & other)
46  {
47  if (self.m_class && other.m_class) {
48  return self.m_class->m_object == other.m_class->m_object;
49  } else {
50  return self.isNull() && other.isNull();
51  }
52  }
53 };
54 
55 template <class T, class X>
56 struct RefPointerEqualityCheck<T, X*>
57 {
58  static inline bool check(const RefPointer<T> & self, X* const & other)
59  {
60  return self.m_class ? self.m_class->m_object == other : !other;
61  }
62 };
63 
64 } //namespace Private
65 
66 
87 template <class T>
88 class RefPointer
89 {
90 public:
91  inline RefPointer();
92  inline ~RefPointer();
93 
95  explicit inline RefPointer(T *cppClass);
96 
97  template <class X>
98  inline RefPointer(const RefPointer<X> & other);
99  inline RefPointer(const RefPointer<T> & other);
100 
101  template <class X>
102  inline RefPointer<T> & operator=(const RefPointer<X> & other);
103  inline RefPointer<T> & operator=(const RefPointer<T> & other);
104 
118  template <class X>
119  bool operator==(const X & other) const;
120  template <class X>
121  bool operator!=(const X & other) const;
122 
125  void clear();
126 
127  inline bool isNull() const;
128  inline bool operator!() const;
129  inline T *operator->() const;
130 
137  inline operator typename T::CType*() const;
138 
143  static RefPointer<T> wrap(typename T::CType *nativePtr, bool increaseRef = true);
144 
146  template <class X>
147  RefPointer<X> staticCast() const;
148 
162  template <class X>
163  RefPointer<X> dynamicCast() const;
164 
165 private:
166  template <class X> friend class RefPointer;
167  template <class X, class Y> friend struct Private::RefPointerEqualityCheck;
168 
169  template <class X>
170  void assign(const RefPointer<X> & other);
171 
172  T *m_class;
173 };
174 
179 class QTGLIB_EXPORT RefCountedObject
180 {
181 public:
182  virtual ~RefCountedObject() {}
183 
184 protected:
185  template <class T> friend class RefPointer;
186  template <class T, class X> friend struct Private::RefPointerEqualityCheck;
187 
188  virtual void ref(bool increaseRef) = 0;
189  virtual void unref() = 0;
190 
191  template <class T>
192  inline T* object() const;
193 
194  void *m_object;
195 };
196 
197 template <class T>
198 inline T* RefCountedObject::object() const
199 {
200  return static_cast<T* const>(m_object);
201 }
202 
203 
204 template <class T>
205 inline RefPointer<T>::RefPointer()
206  : m_class(NULL)
207 {
208 }
209 
210 template <class T>
211 inline RefPointer<T>::~RefPointer()
212 {
213  clear();
214 }
215 
216 template <class T>
217 inline RefPointer<T>::RefPointer(T *cppClass)
218  : m_class(cppClass)
219 {
220  static_cast<RefCountedObject*>(m_class)->ref(true);
221 }
222 
223 template <class T>
224 template <class X>
225 inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
226  : m_class(NULL)
227 {
228  assign(other);
229 }
230 
231 template <class T>
232 inline RefPointer<T>::RefPointer(const RefPointer<T> & other)
233  : m_class(NULL)
234 {
235  assign(other);
236 }
237 
238 template <class T>
239 template <class X>
240 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<X> & other)
241 {
242  clear();
243  assign(other);
244  return *this;
245 }
246 
247 template <class T>
248 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<T> & other)
249 {
250  clear();
251  assign(other);
252  return *this;
253 }
254 
255 template <class T>
256 template <class X>
257 void RefPointer<T>::assign(const RefPointer<X> & other)
258 {
259  //T should be a base class of X
260  QGLIB_STATIC_ASSERT((boost::is_base_of<T, X>::value),
261  "Cannot implicitly cast a RefPointer down the hierarchy");
262 
263  if (!other.isNull()) {
264  m_class = static_cast<T*>(other.m_class);
265  static_cast<RefCountedObject*>(m_class)->ref(true);
266  }
267 }
268 
269 template <class T>
270 template <class X>
271 bool RefPointer<T>::operator==(const X & other) const
272 {
273  return Private::RefPointerEqualityCheck<T, X>::check(*this, other);
274 }
275 
276 template <class T>
277 template <class X>
278 bool RefPointer<T>::operator!=(const X & other) const
279 {
280  return !Private::RefPointerEqualityCheck<T, X>::check(*this, other);
281 }
282 
286 template <class T, class X>
287 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
288 //it is ambiguous with RefPointer::operator==() and the built-in operator== for pointers.
289 typename boost::enable_if_c<
290  boost::is_pointer<X>::value &&
291  !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
292  bool
293 >::type
294 operator==(const X & other, const RefPointer<T> & self)
295 {
296  return Private::RefPointerEqualityCheck<T, X>::check(self, other);
297 }
298 
302 template <class T, class X>
303 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
304 //it is ambiguous with RefPointer::operator!=() and the built-in operator!= for pointers.
305 typename boost::enable_if_c<
306  boost::is_pointer<X>::value &&
307  !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
308  bool
309 >::type
310 operator!=(const X & other, const RefPointer<T> & self)
311 {
312  return !Private::RefPointerEqualityCheck<T, X>::check(self, other);
313 }
314 
315 template <class T>
317 {
318  if (!isNull()) {
319  static_cast<RefCountedObject*>(m_class)->unref(); //this may delete m_class at this point
320  m_class = NULL;
321  }
322 }
323 
324 //static
325 template <class T>
326 RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef)
327 {
328  RefPointer<T> ptr;
329  if (nativePtr != NULL) {
330  RefCountedObject *cppObj = WrapImpl<T>::wrap(nativePtr);
331  cppObj->ref(increaseRef);
332  ptr.m_class = dynamic_cast<T*>(cppObj);
333  Q_ASSERT(ptr.m_class);
334  }
335  return ptr;
336 }
337 
338 template <class T>
339 inline bool RefPointer<T>::isNull() const
340 {
341  return m_class == NULL;
342 }
343 
344 template <class T>
345 inline bool RefPointer<T>::operator!() const
346 {
347  return m_class == NULL;
348 }
349 
350 template <class T>
351 inline T *RefPointer<T>::operator->() const
352 {
353  Q_ASSERT_X(!isNull(), "RefPointer::operator->() const",
354  "Attempted to dereference a null pointer");
355  return m_class;
356 }
357 
358 template <class T>
359 inline RefPointer<T>::operator typename T::CType*() const
360 {
361  return m_class ? static_cast<RefCountedObject*>(m_class)->object<typename T::CType>() : NULL;
362 }
363 
364 template <class T>
365 template <class X>
367 {
368  RefPointer<X> result;
369  if (m_class) {
370  static_cast<RefCountedObject*>(m_class)->ref(true);
371  result.m_class = static_cast<X*>(m_class);
372  }
373  return result;
374 }
375 
376 
377 namespace Private {
378 
379 template <typename T, typename X, typename Enable = void>
380 struct IfaceDynamicCastImpl
381 {
382  static inline X *doCast(typename X::CType *obj)
383  {
384  Q_UNUSED(obj);
385  return NULL;
386  }
387 };
388 
389 //this version is compiled if X is an interface and T is an object,
390 //i.e. we are dynamically casting from an object to an interface.
391 template <typename T, typename X>
392 struct IfaceDynamicCastImpl<T, X,
393  typename boost::enable_if_c<
394  //to check if something is an interface, we need to also verify that it does
395  //not inherit Object, since derived object classes may also derive from interfaces.
396  (boost::is_base_of<Interface, X>::value &&
397  !boost::is_base_of<Object, X>::value &&
398  boost::is_base_of<Object, T>::value)
399  >::type
400  >
401 {
402  static inline X *doCast(typename X::CType *obj)
403  {
404  X *targetClass = NULL;
405 
406  //Check that instanceType implements (isA) the interface
407  //and if it does, return a wrapper for that interface.
408  if (Type::fromInstance(obj).isA(GetType<X>()))
409  {
410  targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
411  Q_ASSERT(targetClass);
412  }
413 
414  return targetClass;
415  }
416 };
417 
418 //this version is compiled if T is an interface,
419 //i.e. we are dynamically casting from an interface to either an object or another interface.
420 template <typename T, typename X>
421 struct IfaceDynamicCastImpl<T, X,
422  typename boost::enable_if_c<
423  //to check if something is an interface, we need to also verify that it does
424  //not inherit Object, since derived object classes may also derive from interfaces.
425  (boost::is_base_of<Interface, T>::value &&
426  !boost::is_base_of<Object, T>::value)
427  >::type
428  >
429 {
430  static inline X *doCast(typename X::CType *obj)
431  {
432  //get the instance type and try to create (or rather fetch from the GObject qdata)
433  //the C++ wrapper class for this type of object.
434  RefCountedObject *cppClass = Private::wrapObject(obj);
435 
436  //attempt to cast it to X
437  X *targetClass = dynamic_cast<X*>(cppClass);
438 
439  if (!targetClass) {
440  //Cast failed. This either means that X is something that our instance is not
441  //or that X is another interface that is not inherited by the wrapper class
442  //for this instance type, but it is possible that our instance actually
443  //implements it, so let's check it.
444  if (boost::is_base_of<Interface, X>::value &&
445  !boost::is_base_of<Object, X>::value &&
446  Type::fromInstance(obj).isA(GetType<X>()))
447  {
448  targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
449  Q_ASSERT(targetClass);
450  }
451  }
452 
453  return targetClass;
454  }
455 };
456 
457 } //namespace Private
458 
459 
460 template <class T>
461 template <class X>
463 {
464  RefPointer<X> result;
465  if (m_class) {
466  X *targetClass = dynamic_cast<X*>(m_class);
467  if (!targetClass) {
468  //in case either X or T is an interface, we need to do some extra checks.
469  //this is a template to optimize the compiled code depending on what X and T are.
470  typename X::CType *obj = static_cast<RefCountedObject*>(m_class)->object<typename X::CType>();
471  targetClass = Private::IfaceDynamicCastImpl<T, X>::doCast(obj);
472  }
473 
474  if (targetClass) {
475  static_cast<RefCountedObject*>(targetClass)->ref(true);
476  result.m_class = targetClass;
477  }
478  }
479 
480  return result;
481 }
482 
483 // trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >()
484 template <class T>
485 struct GetTypeImpl< RefPointer<T> >
486 {
487  inline operator Type() { return GetType<T>(); }
488 };
489 
491 template <typename T>
492 inline uint qHash(const RefPointer<T> & ptr)
493 {
494  return qHash(static_cast<typename T::CType*>(ptr));
495 }
496 
497 } //namespace QGlib
498 
499 #endif
boost::enable_if_c< boost::is_pointer< X >::value &&!boost::is_same< X, typename boost::add_pointer< typename T::CType >::type >::value, bool >::type operator==(const X &other, const RefPointer< T > &self)
Definition: refpointer.h:294
static RefPointer< T > wrap(typename T::CType *nativePtr, bool increaseRef=true)
Definition: refpointer.h:326
Smart pointer class for working with wrapper classes that support reference counting.
Definition: global.h:56
RefPointer< X > staticCast() const
Definition: refpointer.h:366
boost::enable_if_c< boost::is_pointer< X >::value &&!boost::is_same< X, typename boost::add_pointer< typename T::CType >::type >::value, bool >::type operator!=(const X &other, const RefPointer< T > &self)
Definition: refpointer.h:310
Base class for all the reference-counted object wrappers.
Definition: refpointer.h:179
RefPointer< X > dynamicCast() const
Definition: refpointer.h:462
bool operator!=(const X &other) const
Definition: refpointer.h:278
uint qHash(const RefPointer< T > &ptr)
Definition: refpointer.h:492
Wrapper class for GType.
Definition: type.h:63
bool operator==(const X &other) const
Definition: refpointer.h:271