QtGStreamer  1.2.0
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 
29 namespace QGlib {
30 namespace Private {
31 
32 class Dispatcher
33 {
34 public:
35  Dispatcher();
36 
37  ValueVTable getVTable(Type t) const;
38  void setVTable(Type t, const ValueVTable & vtable);
39 
40 private:
41  mutable QReadWriteLock lock;
42  QHash<Type, ValueVTable> dispatchTable;
43 };
44 
45 Dispatcher::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 
85 ValueVTable 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 
122 void Dispatcher::setVTable(Type t, const ValueVTable & vtable)
123 {
124  QWriteLocker l(&lock);
125  dispatchTable[t] = vtable;
126 }
127 
128 } //namespace Private
129 
130 Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);
131 
132 #ifndef DOXYGEN_RUN
133 
134 // -- Value::Data --
135 
136 struct 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 
149 Value::Data::Data()
150  : QSharedData()
151 {
152  std::memset(&m_value, 0, sizeof(GValue));
153 }
154 
155 Value::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 
166 Value::Data::~Data()
167 {
168  if (type() != Type::Invalid) {
169  g_value_unset(value());
170  }
171 }
172 
173 #endif //DOXYGEN_RUN
174 
175 // -- Value --
176 
177 Value::Value()
178  : d(new Data)
179 {
180 }
181 
182 Value::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 
209 VALUE_CONSTRUCTOR(bool)
210 VALUE_CONSTRUCTOR(char)
211 VALUE_CONSTRUCTOR(uchar)
212 VALUE_CONSTRUCTOR(int)
213 VALUE_CONSTRUCTOR(uint)
214 VALUE_CONSTRUCTOR(long)
215 VALUE_CONSTRUCTOR(ulong)
216 VALUE_CONSTRUCTOR(qint64)
217 VALUE_CONSTRUCTOR(quint64)
218 VALUE_CONSTRUCTOR(float)
219 VALUE_CONSTRUCTOR(double)
220 VALUE_CONSTRUCTOR(const char *)
221 VALUE_CONSTRUCTOR(const QByteArray &)
222 VALUE_CONSTRUCTOR(const QString &)
223 
224 #undef VALUE_CONSTRUCTOR
225 
226 Value::Value(const Value & other)
227  : d(other.d)
228 {
229 }
230 
231 Value & Value::operator=(const Value & other)
232 {
233  d = other.d;
234  return *this;
235 }
236 
237 Value::~Value()
238 {
239 }
240 
241 void Value::init(Type type)
242 {
243  if (isValid()) {
244  g_value_unset(d->value());
245  }
246  g_value_init(d->value(), type);
247 }
248 
249 bool 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 
281 Value::operator GValue* ()
282 {
283  return d->value();
284 }
285 
286 Value::operator const GValue * () const
287 {
288  return d->value();
289 }
290 
291 //static
292 void Value::registerValueVTable(Type type, const ValueVTable & vtable)
293 {
294  s_dispatcher()->setVTable(type, vtable);
295 }
296 
297 static 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 
307 void 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 
334 void 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 
361 QDebug 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.