Add methods in RefPointer to allow casting RefPointers of derived classes to RefPoint...
[qtgstreamer:qtgstreamer.git] / src / QGlib / refpointer.h
1 /*
2     Copyright (C) 2009-2010  George Kiagiadakis <kiagiadakis.george@gmail.com>
3
4     This library is free software; you can redistribute it and/or modify
5     it under the terms of the GNU Lesser General Public License as published
6     by the Free Software Foundation; either version 2.1 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU Lesser General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #ifndef QGLIB_REFPOINTER_H
18 #define QGLIB_REFPOINTER_H
19
20 #include "type.h"
21 #include <stddef.h>
22 #include <boost/static_assert.hpp>
23 #include <boost/type_traits.hpp>
24
25 namespace QGlib {
26
27 template <class T>
28 class RefPointer
29 {
30 public:
31     inline RefPointer();
32     inline ~RefPointer();
33
34     inline RefPointer(const RefPointer<T> & other);
35     template <class X>
36     inline RefPointer(const RefPointer<X> & other);
37     inline RefPointer<T> & operator=(const RefPointer<T> & other);
38     template <class X>
39     inline RefPointer<T> & operator=(const RefPointer<X> & other);
40
41     void clear();
42
43     inline bool isNull() const;
44     inline operator bool() const;
45     inline bool operator!() const;
46     inline T *operator->() const;
47     inline operator typename T::CType*() const;
48
49     static RefPointer<T> wrap(typename T::CType *nativePtr, bool increaseRef = true);
50
51     template <class X>
52     RefPointer<X> staticCast() const;
53
54     template <class X>
55     RefPointer<X> dynamicCast() const;
56
57 private:
58     template <class X> friend class RefPointer;
59     template <class X>
60     void assign(const RefPointer<X> & other);
61
62     T *m_class;
63 };
64
65
66 class RefCountedObject
67 {
68 protected:
69     template <class T> friend class RefPointer;
70
71     virtual ~RefCountedObject() {}
72
73     virtual void ref() = 0;
74     virtual void unref() = 0;
75
76     void *m_object;
77 };
78
79
80 template <class T>
81 inline RefPointer<T>::RefPointer()
82     : m_class(NULL)
83 {
84 }
85
86 template <class T>
87 inline RefPointer<T>::~RefPointer()
88 {
89     clear();
90 }
91
92 template <class T>
93 template <class X>
94 inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
95     : m_class(NULL)
96 {
97     assign(other);
98 }
99
100 template <class T>
101 inline RefPointer<T>::RefPointer(const RefPointer<T> & other)
102     : m_class(NULL)
103 {
104     assign(other);
105 }
106
107 template <class T>
108 template <class X>
109 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<X> & other)
110 {
111     clear();
112     assign(other);
113     return *this;
114 }
115
116 template <class T>
117 inline RefPointer<T> & RefPointer<T>::operator=(const RefPointer<T> & other)
118 {
119     clear();
120     assign(other);
121     return *this;
122 }
123
124 template <class T>
125 template <class X>
126 void RefPointer<T>::assign(const RefPointer<X> & other)
127 {
128     //T should be a base class of X
129     BOOST_STATIC_ASSERT((boost::is_base_of<T, X>::value));
130
131     if (!other.isNull()) {
132         m_class = new T();
133         m_class->m_object = other.m_class->m_object;
134         static_cast<RefCountedObject*>(m_class)->ref();
135     }
136 }
137
138 template <class T>
139 void RefPointer<T>::clear()
140 {
141     if (!isNull()) {
142         static_cast<RefCountedObject*>(m_class)->unref();
143         delete m_class;
144         m_class = NULL;
145     }
146 }
147
148 //static
149 template <class T>
150 RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef)
151 {
152     RefPointer<T> ptr;
153     if (nativePtr != NULL) {
154         ptr.m_class = new T();
155         ptr.m_class->m_object = nativePtr;
156         if (increaseRef) {
157             static_cast<RefCountedObject*>(ptr.m_class)->ref();
158         }
159     }
160     return ptr;
161 }
162
163 template <class T>
164 inline bool RefPointer<T>::isNull() const
165 {
166     return m_class == NULL;
167 }
168
169 template <class T>
170 inline RefPointer<T>::operator bool() const
171 {
172     return m_class != NULL;
173 }
174
175 template <class T>
176 inline bool RefPointer<T>::operator!() const
177 {
178     return m_class == NULL;
179 }
180
181 template <class T>
182 inline T *RefPointer<T>::operator->() const
183 {
184     return m_class;
185 }
186
187 template <class T>
188 inline RefPointer<T>::operator typename T::CType*() const
189 {
190     return m_class ? static_cast<typename T::CType*>(m_class->m_object) : NULL;
191 }
192
193 template <class T>
194 template <class X>
195 RefPointer<X> RefPointer<T>::staticCast() const
196 {
197     return isNull() ? RefPointer<X>()
198                     : RefPointer<X>::wrap(static_cast<typename X::CType*>(m_class->m_object));
199 }
200
201 template <class T> struct GetType;
202
203 template <class T>
204 template <class X>
205 RefPointer<X> RefPointer<T>::dynamicCast() const
206 {
207     if (!isNull() && Type::fromInstance(m_class->m_object).isA(GetType<X>())) {
208         return RefPointer<X>::wrap(static_cast<typename X::CType*>(m_class->m_object));
209     } else {
210         return RefPointer<X>();
211     }
212 }
213
214 }
215
216 #endif