00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00086
00087
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
00097
00098
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 }
00127
00128 Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);
00129
00130 #ifndef DOXYGEN_RUN
00131
00132
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
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
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 }