QtGStreamer  1.2.0
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 #ifndef Q_MOC_RUN
27 #include <boost/type_traits.hpp>
28 #endif
29 #include <boost/utility/enable_if.hpp>
30 #include <QtCore/QHash>
31 
32 namespace QGlib {
33 
34 //forward declarations
35 class Object;
36 class Interface;
37 
38 
39 namespace Private {
40 
41 template <class T, class X>
42 struct RefPointerEqualityCheck {};
43 
44 template <class T, class X>
45 struct RefPointerEqualityCheck<T, RefPointer<X> >
46 {
47  static inline bool check(const RefPointer<T> & self, const RefPointer<X> & other)
48  {
49  if (self.m_class && other.m_class) {
50  return self.m_class->m_object == other.m_class->m_object;
51  } else {
52  return self.isNull() && other.isNull();
53  }
54  }
55 };
56 
57 template <class T, class X>
58 struct RefPointerEqualityCheck<T, X*>
59 {
60  static inline bool check(const RefPointer<T> & self, X* const & other)
61  {
62  return self.m_class ? self.m_class->m_object == other : !other;
63  }
64 };
65 
66 } //namespace Private
67 
68 
89 template <class T>
91 {
92 public:
93  inline RefPointer();
94  inline ~RefPointer();
95 
97  explicit inline RefPointer(T *cppClass);
98 
99  template <class X>
100  inline RefPointer(const RefPointer<X> & other);
101  inline RefPointer(const RefPointer<T> & other);
102 
103  template <class X>
104  inline RefPointer<T> & operator=(const RefPointer<X> & other);
105  inline RefPointer<T> & operator=(const RefPointer<T> & other);
106 
120  template <class X>
121  bool operator==(const X & other) const;
122  template <class X>
123  bool operator!=(const X & other) const;
124 
127  void clear();
128 
129  inline bool isNull() const;
130  inline bool operator!() const;
131  inline T *operator->() const;
132 
139  inline operator typename T::CType*() const;
140 
145  static RefPointer<T> wrap(typename T::CType *nativePtr, bool increaseRef = true);
146 
148  template <class X>
150 
164  template <class X>
166 
167 private:
168  template <class X> friend class RefPointer;
169  template <class X, class Y> friend struct Private::RefPointerEqualityCheck;
170 
171  template <class X>
172  void assign(const RefPointer<X> & other);
173 
174  T *m_class;
175 };
176 
181 class QTGLIB_EXPORT RefCountedObject
182 {
183 public:
184  virtual ~RefCountedObject() {}
185 
186 protected:
187  template <class T> friend class RefPointer;
188  template <class T, class X> friend struct Private::RefPointerEqualityCheck;
189 
190  virtual void ref(bool increaseRef) = 0;
191  virtual void unref() = 0;
192 
193  template <class T>
194  inline T* object() const;
195 
196  void *m_object;
197 };
198 
199 template <class T>
200 inline T* RefCountedObject::object() const
201 {
202  return static_cast<T* const>(m_object);
203 }
204 
205 
206 template <class T>
207 inline RefPointer<T>::RefPointer()
208  : m_class(NULL)
209 {
210 }
211 
212 template <class T>
213 inline RefPointer<T>::~RefPointer()
214 {
215  clear();
216 }
217 
218 template <class T>
219 inline RefPointer<T>::RefPointer(T *cppClass)
220  : m_class(cppClass)
221 {
222  static_cast<RefCountedObject*>(m_class)->ref(true);
223 }
224 
225 template <class T>
226 template <class X>
227 inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
228  : m_class(NULL)
229 {
230  assign(other);
231 }
232 
233 template <class T>
234 inline RefPointer<T>::RefPointer(const RefPointer<T> & other)
235  : m_class(NULL)
236 {
237  assign(other);
238 }
239 
240 template <class T>
241 template <class X>
242 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<X> & other)
243 {
244  clear();
245  assign(other);
246  return *this;
247 }
248 
249 template <class T>
250 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<T> & other)
251 {
252  clear();
253  assign(other);
254  return *this;
255 }
256 
257 template <class T>
258 template <class X>
259 void RefPointer<T>::assign(const RefPointer<X> & other)
260 {
261  //T should be a base class of X
262  QGLIB_STATIC_ASSERT((boost::is_base_of<T, X>::value),
263  "Cannot implicitly cast a RefPointer down the hierarchy");
264 
265  if (!other.isNull()) {
266  m_class = static_cast<T*>(other.m_class);
267  static_cast<RefCountedObject*>(m_class)->ref(true);
268  }
269 }
270 
271 template <class T>
272 template <class X>
273 bool RefPointer<T>::operator==(const X & other) const
274 {
275  return Private::RefPointerEqualityCheck<T, X>::check(*this, other);
276 }
277 
278 template <class T>
279 template <class X>
280 bool RefPointer<T>::operator!=(const X & other) const
281 {
282  return !Private::RefPointerEqualityCheck<T, X>::check(*this, other);
283 }
284 
288 template <class T, class X>
289 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
290 //it is ambiguous with RefPointer::operator==() and the built-in operator== for pointers.
291 typename boost::enable_if_c<
292  boost::is_pointer<X>::value &&
293  !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
294  bool
295 >::type
296 operator==(const X & other, const RefPointer<T> & self)
297 {
298  return Private::RefPointerEqualityCheck<T, X>::check(self, other);
299 }
300 
304 template <class T, class X>
305 //use this function only if X is a pointer and is NOT the same as T::CType*, otherwise
306 //it is ambiguous with RefPointer::operator!=() and the built-in operator!= for pointers.
307 typename boost::enable_if_c<
308  boost::is_pointer<X>::value &&
309  !boost::is_same<X, typename boost::add_pointer<typename T::CType>::type>::value,
310  bool
311 >::type
312 operator!=(const X & other, const RefPointer<T> & self)
313 {
314  return !Private::RefPointerEqualityCheck<T, X>::check(self, other);
315 }
316 
317 template <class T>
319 {
320  if (!isNull()) {
321  static_cast<RefCountedObject*>(m_class)->unref(); //this may delete m_class at this point
322  m_class = NULL;
323  }
324 }
325 
326 //static
327 template <class T>
328 RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef)
329 {
330  RefPointer<T> ptr;
331  if (nativePtr != NULL) {
332  RefCountedObject *cppObj = WrapImpl<T>::wrap(nativePtr);
333  cppObj->ref(increaseRef);
334  ptr.m_class = dynamic_cast<T*>(cppObj);
335  Q_ASSERT(ptr.m_class);
336  }
337  return ptr;
338 }
339 
340 template <class T>
341 inline bool RefPointer<T>::isNull() const
342 {
343  return m_class == NULL;
344 }
345 
346 template <class T>
347 inline bool RefPointer<T>::operator!() const
348 {
349  return m_class == NULL;
350 }
351 
352 template <class T>
353 inline T *RefPointer<T>::operator->() const
354 {
355  Q_ASSERT_X(!isNull(), "RefPointer::operator->() const",
356  "Attempted to dereference a null pointer");
357  return m_class;
358 }
359 
360 template <class T>
361 inline RefPointer<T>::operator typename T::CType*() const
362 {
363  return m_class ? static_cast<RefCountedObject*>(m_class)->object<typename T::CType>() : NULL;
364 }
365 
366 template <class T>
367 template <class X>
369 {
370  RefPointer<X> result;
371  if (m_class) {
372  static_cast<RefCountedObject*>(m_class)->ref(true);
373  result.m_class = static_cast<X*>(m_class);
374  }
375  return result;
376 }
377 
378 
379 namespace Private {
380 
381 template <typename T, typename X, typename Enable = void>
382 struct IfaceDynamicCastImpl
383 {
384  static inline X *doCast(typename X::CType *obj)
385  {
386  Q_UNUSED(obj);
387  return NULL;
388  }
389 };
390 
391 //this version is compiled if X is an interface and T is an object,
392 //i.e. we are dynamically casting from an object to an interface.
393 template <typename T, typename X>
394 struct IfaceDynamicCastImpl<T, X,
395  typename boost::enable_if_c<
396  //to check if something is an interface, we need to also verify that it does
397  //not inherit Object, since derived object classes may also derive from interfaces.
398  (boost::is_base_of<Interface, X>::value &&
399  !boost::is_base_of<Object, X>::value &&
400  boost::is_base_of<Object, T>::value)
401  >::type
402  >
403 {
404  static inline X *doCast(typename X::CType *obj)
405  {
406  X *targetClass = NULL;
407 
408  //Check that instanceType implements (isA) the interface
409  //and if it does, return a wrapper for that interface.
410  if (Type::fromInstance(obj).isA(GetType<X>()))
411  {
412  targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
413  Q_ASSERT(targetClass);
414  }
415 
416  return targetClass;
417  }
418 };
419 
420 //this version is compiled if T is an interface,
421 //i.e. we are dynamically casting from an interface to either an object or another interface.
422 template <typename T, typename X>
423 struct IfaceDynamicCastImpl<T, X,
424  typename boost::enable_if_c<
425  //to check if something is an interface, we need to also verify that it does
426  //not inherit Object, since derived object classes may also derive from interfaces.
427  (boost::is_base_of<Interface, T>::value &&
428  !boost::is_base_of<Object, T>::value)
429  >::type
430  >
431 {
432  static inline X *doCast(typename X::CType *obj)
433  {
434  //get the instance type and try to create (or rather fetch from the GObject qdata)
435  //the C++ wrapper class for this type of object.
436  RefCountedObject *cppClass = Private::wrapObject(obj);
437 
438  //attempt to cast it to X
439  X *targetClass = dynamic_cast<X*>(cppClass);
440 
441  if (!targetClass) {
442  //Cast failed. This either means that X is something that our instance is not
443  //or that X is another interface that is not inherited by the wrapper class
444  //for this instance type, but it is possible that our instance actually
445  //implements it, so let's check it.
446  if (boost::is_base_of<Interface, X>::value &&
447  !boost::is_base_of<Object, X>::value &&
448  Type::fromInstance(obj).isA(GetType<X>()))
449  {
450  targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
451  Q_ASSERT(targetClass);
452  }
453  }
454 
455  return targetClass;
456  }
457 };
458 
459 } //namespace Private
460 
461 
462 template <class T>
463 template <class X>
465 {
466  RefPointer<X> result;
467  if (m_class) {
468  X *targetClass = dynamic_cast<X*>(m_class);
469  if (!targetClass) {
470  //in case either X or T is an interface, we need to do some extra checks.
471  //this is a template to optimize the compiled code depending on what X and T are.
472  typename X::CType *obj = static_cast<RefCountedObject*>(m_class)->object<typename X::CType>();
473  targetClass = Private::IfaceDynamicCastImpl<T, X>::doCast(obj);
474  }
475 
476  if (targetClass) {
477  static_cast<RefCountedObject*>(targetClass)->ref(true);
478  result.m_class = targetClass;
479  }
480  }
481 
482  return result;
483 }
484 
485 // trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >()
486 template <class T>
487 struct GetTypeImpl< RefPointer<T> >
488 {
489  inline operator Type() { return GetType<T>(); }
490 };
491 
493 template <typename T>
494 inline uint qHash(const RefPointer<T> & ptr)
495 {
496  return qHash(static_cast<typename T::CType*>(ptr));
497 }
498 
499 } //namespace QGlib
500 
501 #endif
Base class for all the reference-counted object wrappers.
Definition: refpointer.h:182
Smart pointer class for working with wrapper classes that support reference counting.
Definition: refpointer.h:91
RefPointer< X > staticCast() const
Definition: refpointer.h:368
RefPointer(T *cppClass)
Definition: refpointer.h:219
RefPointer< X > dynamicCast() const
Definition: refpointer.h:464
static RefPointer< T > wrap(typename T::CType *nativePtr, bool increaseRef=true)
Definition: refpointer.h:328
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:312
bool operator==(const X &other) const
Definition: refpointer.h:273
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:296
bool operator!=(const X &other) const
Definition: refpointer.h:280
Wrapper class for GType.
Definition: type.h:64
Wrappers for Glib and GObject classes.