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