QtGStreamer 1.2.0
Loading...
Searching...
No Matches
value.cpp
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#include "value.h"
20#include "string.h"
21#include <cstring>
22#ifndef Q_MOC_RUN
23#include <boost/type_traits.hpp>
24#endif
25#include <glib-object.h>
26#include <QtCore/QDebug>
27#include <QtCore/QReadWriteLock>
28
29namespace QGlib {
30namespace Private {
31
32class Dispatcher
33{
34public:
35 Dispatcher();
36
37 ValueVTable getVTable(Type t) const;
38 void setVTable(Type t, const ValueVTable & vtable);
39
40private:
41 mutable QReadWriteLock lock;
42 QHash<Type, ValueVTable> dispatchTable;
43};
44
45Dispatcher::Dispatcher()
46{
47#define DECLARE_VTABLE(T, NICK, GTYPE) \
48 struct ValueVTable_##NICK \
49 { \
50 static void get(const Value & value, void *data) \
51 { \
52 *reinterpret_cast<T*>(data) = g_value_get_##NICK(value); \
53 }; \
54 \
55 static void set(Value & value, const void *data) \
56 { \
57 g_value_set_##NICK(value, *reinterpret_cast<T const *>(data)); \
58 }; \
59 }; \
60 setVTable(GTYPE, ValueVTable(ValueVTable_##NICK::set, ValueVTable_##NICK::get));
61
62 DECLARE_VTABLE(char, char, Type::Char)
63 DECLARE_VTABLE(unsigned char, uchar, Type::Uchar)
64 DECLARE_VTABLE(bool, boolean, Type::Boolean)
65 DECLARE_VTABLE(int, int, Type::Int)
66 DECLARE_VTABLE(unsigned int, uint, Type::Uint)
67 DECLARE_VTABLE(long, long, Type::Long)
68 DECLARE_VTABLE(unsigned long, ulong, Type::Ulong)
69 DECLARE_VTABLE(qint64, int64, Type::Int64)
70 DECLARE_VTABLE(quint64, uint64, Type::Uint64)
71 DECLARE_VTABLE(int, enum, Type::Enum);
72 DECLARE_VTABLE(uint, flags, Type::Flags)
73 DECLARE_VTABLE(float, float, Type::Float)
74 DECLARE_VTABLE(double, double, Type::Double)
75 DECLARE_VTABLE(QByteArray, string, Type::String)
76 DECLARE_VTABLE(void*, pointer, Type::Pointer)
77 DECLARE_VTABLE(void*, boxed, Type::Boxed)
78 DECLARE_VTABLE(GParamSpec*, param, Type::Param)
79 DECLARE_VTABLE(void*, object, Type::Object)
80 DECLARE_VTABLE(QGlib::Type, gtype, GetType<QGlib::Type>())
81
82#undef DECLARE_VTABLE
83}
84
85ValueVTable Dispatcher::getVTable(Type t) const
86{
87 //if the type is an interface, try to find its
88 //instantiatable prerequisite and get the vtable
89 //of this instantiatable type instead.
90 if (t.isInterface()) {
91 QList<Type> prerequisites = t.interfacePrerequisites();
92 Q_FOREACH(Type prereq, prerequisites) {
93 if (prereq.isInstantiatable()) {
94 t = prereq;
95 }
96 }
97
98 //Check if the prerequisite was found and
99 //bail out if not, since such interfaces
100 //are not compatible with GValue.
101 if (!t.isInstantiatable()) {
102 return ValueVTable();
103 }
104 }
105
106 QReadLocker l(&lock);
107
108 if (dispatchTable.contains(t)) {
109 return dispatchTable[t];
110 }
111
112 while (t.isDerived()) {
113 t = t.parent();
114 if (dispatchTable.contains(t)) {
115 return dispatchTable[t];
116 }
117 }
118
119 return ValueVTable();
120}
121
122void Dispatcher::setVTable(Type t, const ValueVTable & vtable)
123{
124 QWriteLocker l(&lock);
125 dispatchTable[t] = vtable;
126}
127
128} //namespace Private
129
130Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);
131
132#ifndef DOXYGEN_RUN
133
134// -- Value::Data --
135
136struct QTGLIB_NO_EXPORT Value::Data : public QSharedData
137{
138 Data();
139 Data(const Data & other);
140 ~Data();
141
142 inline Type type() const { return G_VALUE_TYPE(&m_value); }
143 inline GValue *value() { return &m_value; }
144 inline const GValue *value() const { return &m_value; }
145
146 GValue m_value;
147};
148
149Value::Data::Data()
150 : QSharedData()
151{
152 std::memset(&m_value, 0, sizeof(GValue));
153}
154
155Value::Data::Data(const Value::Data & other)
156 : QSharedData(other)
157{
158 std::memset(&m_value, 0, sizeof(GValue));
159
160 if (other.type() != Type::Invalid) {
161 g_value_init(value(), other.type());
162 g_value_copy(other.value(), value());
163 }
164}
165
166Value::Data::~Data()
167{
168 if (type() != Type::Invalid) {
169 g_value_unset(value());
170 }
171}
172
173#endif //DOXYGEN_RUN
174
175// -- Value --
176
177Value::Value()
178 : d(new Data)
179{
180}
181
182Value::Value(const GValue *gvalue)
183 : d(new Data)
184{
185 if (gvalue && G_IS_VALUE(gvalue)) {
186 init(G_VALUE_TYPE(gvalue));
187 g_value_copy(gvalue, d->value());
188 }
189}
190
192 : d(new Data)
193{
194 init(type);
195}
196
197#define VALUE_CONSTRUCTOR(T) \
198 Value::Value(T val) \
199 : d(new Data) \
200 { \
201 init< \
202 boost::remove_const< \
203 boost::remove_reference<T>::type \
204 >::type \
205 >(); \
206 set(val); \
207 }
208
209VALUE_CONSTRUCTOR(bool)
210VALUE_CONSTRUCTOR(char)
211VALUE_CONSTRUCTOR(uchar)
212VALUE_CONSTRUCTOR(int)
213VALUE_CONSTRUCTOR(uint)
214VALUE_CONSTRUCTOR(long)
215VALUE_CONSTRUCTOR(ulong)
216VALUE_CONSTRUCTOR(qint64)
217VALUE_CONSTRUCTOR(quint64)
218VALUE_CONSTRUCTOR(float)
219VALUE_CONSTRUCTOR(double)
220VALUE_CONSTRUCTOR(const char *)
221VALUE_CONSTRUCTOR(const QByteArray &)
222VALUE_CONSTRUCTOR(const QString &)
223
224#undef VALUE_CONSTRUCTOR
225
226Value::Value(const Value & other)
227 : d(other.d)
228{
229}
230
231Value & Value::operator=(const Value & other)
232{
233 d = other.d;
234 return *this;
235}
236
237Value::~Value()
238{
239}
240
242{
243 if (isValid()) {
244 g_value_unset(d->value());
245 }
246 g_value_init(d->value(), type);
247}
248
249bool Value::isValid() const
250{
251 return d->type() != Type::Invalid;
252}
253
255{
256 return d->type();
257}
258
260{
261 return isValid() ? g_value_type_transformable(type(), t) : false;
262}
263
265{
266 Value dest;
267 dest.init(t);
268 if (isValid()) {
269 g_value_transform(d->value(), dest.d->value());
270 }
271 return dest;
272}
273
275{
276 if (isValid()) {
277 g_value_reset(d->value());
278 }
279}
280
281Value::operator GValue* ()
282{
283 return d->value();
284}
285
286Value::operator const GValue * () const
287{
288 return d->value();
289}
290
291//static
293{
294 s_dispatcher()->setVTable(type, vtable);
295}
296
297static inline std::string toStdStringHelper(const QString & str)
298{
299#ifndef QT_NO_STL
300 return str.toStdString();
301#else
302 const QByteArray asc = str.toAscii();
303 return std::string(asc.constData(), asc.length());
304#endif
305}
306
307void Value::getData(Type dataType, void *data) const
308{
309 if (!isValid()) {
310 throw Private::InvalidValueException();
311 } else if (g_value_type_compatible(type(), dataType)) {
312 ValueVTable vtable = s_dispatcher()->getVTable(dataType);
313 if (vtable.get != NULL) {
314 vtable.get(*this, data);
315 } else {
316 throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
317 }
318 } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) {
319 Value v;
320 v.init(dataType);
321
322 if (!g_value_transform(d->value(), v.d->value())) {
323 throw Private::TransformationFailedException(toStdStringHelper(type().name()),
324 toStdStringHelper(dataType.name()));
325 }
326
327 v.getData(dataType, data);
328 } else {
329 throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
330 toStdStringHelper(type().name()));
331 }
332}
333
334void Value::setData(Type dataType, const void *data)
335{
336 if (!isValid()) {
337 throw Private::InvalidValueException();
338 } else if (g_value_type_compatible(dataType, type())) {
339 ValueVTable vtable = s_dispatcher()->getVTable(dataType);
340 if (vtable.set != NULL) {
341 vtable.set(*this, data);
342 } else {
343 throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
344 }
345 } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) {
346 Value v;
347 v.init(dataType);
348 v.setData(dataType, data);
349
350 if (!g_value_transform(v.d->value(), d->value())) {
351 throw Private::TransformationFailedException(toStdStringHelper(dataType.name()),
352 toStdStringHelper(type().name()));
353 }
354 } else {
355 throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
356 toStdStringHelper(type().name()));
357 }
358}
359
360
361QDebug operator<<(QDebug debug, const Value & value)
362{
363 debug.nospace() << "QGlib::Value";
364 if(!value.isValid()) {
365 debug << "(<invalid>)";
366 return debug.space();
367 } else {
368 QString str = value.toString();
369 if (str.isEmpty()) {
370 if (g_value_fits_pointer(value)) {
371 quintptr ptr = reinterpret_cast<quintptr>(g_value_peek_pointer(value));
372 str = QString(QLatin1String("0x%1")).arg(ptr, sizeof(quintptr)*2,
373 16, QLatin1Char('0'));
374 } else {
375 str = QLatin1String("<unknown value>");
376 }
377 }
378
379 debug << "(" << value.type().name() << ", " << str << ")";
380 return debug.space();
381 }
382}
383
384} //namespace QGlib
Wrapper class for GType.
Definition type.h:64
Wrapper class for GValue.
Definition value.h:77
bool canTransformTo(Type type) const
Definition value.cpp:259
Value transformTo(Type type) const
Definition value.cpp:264
static void registerValueVTable(Type type, const ValueVTable &vtable)
Definition value.cpp:292
void clear()
Definition value.cpp:274
void init()
Definition value.h:304
Type type() const
Definition value.cpp:254
bool isValid() const
Definition value.cpp:249
void init(Type type)
Definition value.cpp:241
Wrappers for Glib and GObject classes.