QtGStreamer 0.10.1
|
00001 /* 00002 Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com> 00003 Copyright (C) 2010 Collabora Ltd. 00004 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> 00005 00006 This library is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU Lesser General Public License as published 00008 by the Free Software Foundation; either version 2.1 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU Lesser General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 #include "value.h" 00020 #include "string.h" 00021 #include <cstring> 00022 #include <boost/type_traits.hpp> 00023 #include <glib-object.h> 00024 #include <QtCore/QDebug> 00025 #include <QtCore/QReadWriteLock> 00026 00027 namespace QGlib { 00028 namespace Private { 00029 00030 class Dispatcher 00031 { 00032 public: 00033 Dispatcher(); 00034 00035 ValueVTable getVTable(Type t) const; 00036 void setVTable(Type t, const ValueVTable & vtable); 00037 00038 private: 00039 mutable QReadWriteLock lock; 00040 QHash<Type, ValueVTable> dispatchTable; 00041 }; 00042 00043 Dispatcher::Dispatcher() 00044 { 00045 #define DECLARE_VTABLE(T, NICK, GTYPE) \ 00046 struct ValueVTable_##NICK \ 00047 { \ 00048 static void get(const Value & value, void *data) \ 00049 { \ 00050 *reinterpret_cast<T*>(data) = g_value_get_##NICK(value); \ 00051 }; \ 00052 \ 00053 static void set(Value & value, const void *data) \ 00054 { \ 00055 g_value_set_##NICK(value, *reinterpret_cast<T const *>(data)); \ 00056 }; \ 00057 }; \ 00058 setVTable(GTYPE, ValueVTable(ValueVTable_##NICK::set, ValueVTable_##NICK::get)); 00059 00060 DECLARE_VTABLE(char, char, Type::Char) 00061 DECLARE_VTABLE(unsigned char, uchar, Type::Uchar) 00062 DECLARE_VTABLE(bool, boolean, Type::Boolean) 00063 DECLARE_VTABLE(int, int, Type::Int) 00064 DECLARE_VTABLE(unsigned int, uint, Type::Uint) 00065 DECLARE_VTABLE(long, long, Type::Long) 00066 DECLARE_VTABLE(unsigned long, ulong, Type::Ulong) 00067 DECLARE_VTABLE(qint64, int64, Type::Int64) 00068 DECLARE_VTABLE(quint64, uint64, Type::Uint64) 00069 DECLARE_VTABLE(int, enum, Type::Enum); 00070 DECLARE_VTABLE(uint, flags, Type::Flags) 00071 DECLARE_VTABLE(float, float, Type::Float) 00072 DECLARE_VTABLE(double, double, Type::Double) 00073 DECLARE_VTABLE(QByteArray, string, Type::String) 00074 DECLARE_VTABLE(void*, pointer, Type::Pointer) 00075 DECLARE_VTABLE(void*, boxed, Type::Boxed) 00076 DECLARE_VTABLE(GParamSpec*, param, Type::Param) 00077 DECLARE_VTABLE(void*, object, Type::Object) 00078 DECLARE_VTABLE(QGlib::Type, gtype, GetType<QGlib::Type>()) 00079 00080 #undef DECLARE_VTABLE 00081 } 00082 00083 ValueVTable Dispatcher::getVTable(Type t) const 00084 { 00085 //if the type is an interface, try to find its 00086 //instantiatable prerequisite and get the vtable 00087 //of this instantiatable type instead. 00088 if (t.isInterface()) { 00089 QList<Type> prerequisites = t.interfacePrerequisites(); 00090 Q_FOREACH(Type prereq, prerequisites) { 00091 if (prereq.isInstantiatable()) { 00092 t = prereq; 00093 } 00094 } 00095 00096 //Check if the prerequisite was found and 00097 //bail out if not, since such interfaces 00098 //are not compatible with GValue. 00099 if (!t.isInstantiatable()) { 00100 return ValueVTable(); 00101 } 00102 } 00103 00104 QReadLocker l(&lock); 00105 00106 if (dispatchTable.contains(t)) { 00107 return dispatchTable[t]; 00108 } 00109 00110 while (t.isDerived()) { 00111 t = t.parent(); 00112 if (dispatchTable.contains(t)) { 00113 return dispatchTable[t]; 00114 } 00115 } 00116 00117 return ValueVTable(); 00118 } 00119 00120 void Dispatcher::setVTable(Type t, const ValueVTable & vtable) 00121 { 00122 QWriteLocker l(&lock); 00123 dispatchTable[t] = vtable; 00124 } 00125 00126 } //namespace Private 00127 00128 Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher); 00129 00130 #ifndef DOXYGEN_RUN 00131 00132 // -- Value::Data -- 00133 00134 struct QTGLIB_NO_EXPORT Value::Data : public QSharedData 00135 { 00136 Data(); 00137 Data(const Data & other); 00138 ~Data(); 00139 00140 inline Type type() const { return G_VALUE_TYPE(&m_value); } 00141 inline GValue *value() { return &m_value; } 00142 inline const GValue *value() const { return &m_value; } 00143 00144 GValue m_value; 00145 }; 00146 00147 Value::Data::Data() 00148 : QSharedData() 00149 { 00150 std::memset(&m_value, 0, sizeof(GValue)); 00151 } 00152 00153 Value::Data::Data(const Value::Data & other) 00154 : QSharedData(other) 00155 { 00156 std::memset(&m_value, 0, sizeof(GValue)); 00157 00158 if (other.type() != Type::Invalid) { 00159 g_value_init(value(), other.type()); 00160 g_value_copy(other.value(), value()); 00161 } 00162 } 00163 00164 Value::Data::~Data() 00165 { 00166 if (type() != Type::Invalid) { 00167 g_value_unset(value()); 00168 } 00169 } 00170 00171 #endif //DOXYGEN_RUN 00172 00173 // -- Value -- 00174 00175 Value::Value() 00176 : d(new Data) 00177 { 00178 } 00179 00180 Value::Value(const GValue *gvalue) 00181 : d(new Data) 00182 { 00183 if (gvalue && G_IS_VALUE(gvalue)) { 00184 init(G_VALUE_TYPE(gvalue)); 00185 g_value_copy(gvalue, d->value()); 00186 } 00187 } 00188 00189 Value::Value(Type type) 00190 : d(new Data) 00191 { 00192 init(type); 00193 } 00194 00195 #define VALUE_CONSTRUCTOR(T) \ 00196 Value::Value(T val) \ 00197 : d(new Data) \ 00198 { \ 00199 init< \ 00200 boost::remove_const< \ 00201 boost::remove_reference<T>::type \ 00202 >::type \ 00203 >(); \ 00204 set(val); \ 00205 } 00206 00207 VALUE_CONSTRUCTOR(bool) 00208 VALUE_CONSTRUCTOR(char) 00209 VALUE_CONSTRUCTOR(uchar) 00210 VALUE_CONSTRUCTOR(int) 00211 VALUE_CONSTRUCTOR(uint) 00212 VALUE_CONSTRUCTOR(long) 00213 VALUE_CONSTRUCTOR(ulong) 00214 VALUE_CONSTRUCTOR(qint64) 00215 VALUE_CONSTRUCTOR(quint64) 00216 VALUE_CONSTRUCTOR(float) 00217 VALUE_CONSTRUCTOR(double) 00218 VALUE_CONSTRUCTOR(const char *) 00219 VALUE_CONSTRUCTOR(const QByteArray &) 00220 VALUE_CONSTRUCTOR(const QString &) 00221 00222 #undef VALUE_CONSTRUCTOR 00223 00224 Value::Value(const Value & other) 00225 : d(other.d) 00226 { 00227 } 00228 00229 Value & Value::operator=(const Value & other) 00230 { 00231 d = other.d; 00232 return *this; 00233 } 00234 00235 Value::~Value() 00236 { 00237 } 00238 00239 void Value::init(Type type) 00240 { 00241 if (isValid()) { 00242 g_value_unset(d->value()); 00243 } 00244 g_value_init(d->value(), type); 00245 } 00246 00247 bool Value::isValid() const 00248 { 00249 return d->type() != Type::Invalid; 00250 } 00251 00252 Type Value::type() const 00253 { 00254 return d->type(); 00255 } 00256 00257 bool Value::canTransformTo(Type t) const 00258 { 00259 return isValid() ? g_value_type_transformable(type(), t) : false; 00260 } 00261 00262 Value Value::transformTo(Type t) const 00263 { 00264 Value dest; 00265 dest.init(t); 00266 if (isValid()) { 00267 g_value_transform(d->value(), dest.d->value()); 00268 } 00269 return dest; 00270 } 00271 00272 void Value::clear() 00273 { 00274 if (isValid()) { 00275 g_value_reset(d->value()); 00276 } 00277 } 00278 00279 Value::operator GValue* () 00280 { 00281 return d->value(); 00282 } 00283 00284 Value::operator const GValue * () const 00285 { 00286 return d->value(); 00287 } 00288 00289 //static 00290 void Value::registerValueVTable(Type type, const ValueVTable & vtable) 00291 { 00292 s_dispatcher()->setVTable(type, vtable); 00293 } 00294 00295 void Value::getData(Type dataType, void *data) const 00296 { 00297 if (!isValid()) { 00298 throw Private::InvalidValueException(); 00299 } else if (g_value_type_compatible(type(), dataType)) { 00300 ValueVTable vtable = s_dispatcher()->getVTable(dataType); 00301 if (vtable.get != NULL) { 00302 vtable.get(*this, data); 00303 } else { 00304 throw Private::UnregisteredTypeException(dataType.name().toStdString()); 00305 } 00306 } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) { 00307 Value v; 00308 v.init(dataType); 00309 00310 if (!g_value_transform(d->value(), v.d->value())) { 00311 throw Private::TransformationFailedException(type().name().toStdString(), 00312 dataType.name().toStdString()); 00313 } 00314 00315 v.getData(dataType, data); 00316 } else { 00317 throw Private::InvalidTypeException(dataType.name().toStdString(), 00318 type().name().toStdString()); 00319 } 00320 } 00321 00322 void Value::setData(Type dataType, const void *data) 00323 { 00324 if (!isValid()) { 00325 throw Private::InvalidValueException(); 00326 } else if (g_value_type_compatible(dataType, type())) { 00327 ValueVTable vtable = s_dispatcher()->getVTable(dataType); 00328 if (vtable.set != NULL) { 00329 vtable.set(*this, data); 00330 } else { 00331 throw Private::UnregisteredTypeException(dataType.name().toStdString()); 00332 } 00333 } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) { 00334 Value v; 00335 v.init(dataType); 00336 v.setData(dataType, data); 00337 00338 if (!g_value_transform(v.d->value(), d->value())) { 00339 throw Private::TransformationFailedException(dataType.name().toStdString(), 00340 type().name().toStdString()); 00341 } 00342 } else { 00343 throw Private::InvalidTypeException(dataType.name().toStdString(), 00344 type().name().toStdString()); 00345 } 00346 } 00347 00348 00349 QDebug operator<<(QDebug debug, const Value & value) 00350 { 00351 debug.nospace() << "QGlib::Value"; 00352 if(!value.isValid()) { 00353 debug << "(<invalid>)"; 00354 return debug.space(); 00355 } else { 00356 QString str = value.toString(); 00357 if (str.isEmpty()) { 00358 if (g_value_fits_pointer(value)) { 00359 quintptr ptr = reinterpret_cast<quintptr>(g_value_peek_pointer(value)); 00360 str = QString(QLatin1String("0x%1")).arg(ptr, sizeof(quintptr)*2, 00361 16, QLatin1Char('0')); 00362 } else { 00363 str = QLatin1String("<unknown value>"); 00364 } 00365 } 00366 00367 debug << "(" << value.type().name() << ", " << str << ")"; 00368 return debug.space(); 00369 } 00370 } 00371 00372 } //namespace QGlib