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 static inline std::string toStdStringHelper(const QString & str)
00296 {
00297 #ifndef QT_NO_STL
00298 return str.toStdString();
00299 #else
00300 const QByteArray asc = str.toAscii();
00301 return std::string(asc.constData(), asc.length());
00302 #endif
00303 }
00304
00305 void Value::getData(Type dataType, void *data) const
00306 {
00307 if (!isValid()) {
00308 throw Private::InvalidValueException();
00309 } else if (g_value_type_compatible(type(), dataType)) {
00310 ValueVTable vtable = s_dispatcher()->getVTable(dataType);
00311 if (vtable.get != NULL) {
00312 vtable.get(*this, data);
00313 } else {
00314 throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
00315 }
00316 } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) {
00317 Value v;
00318 v.init(dataType);
00319
00320 if (!g_value_transform(d->value(), v.d->value())) {
00321 throw Private::TransformationFailedException(toStdStringHelper(type().name()),
00322 toStdStringHelper(dataType.name()));
00323 }
00324
00325 v.getData(dataType, data);
00326 } else {
00327 throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
00328 toStdStringHelper(type().name()));
00329 }
00330 }
00331
00332 void Value::setData(Type dataType, const void *data)
00333 {
00334 if (!isValid()) {
00335 throw Private::InvalidValueException();
00336 } else if (g_value_type_compatible(dataType, type())) {
00337 ValueVTable vtable = s_dispatcher()->getVTable(dataType);
00338 if (vtable.set != NULL) {
00339 vtable.set(*this, data);
00340 } else {
00341 throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
00342 }
00343 } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) {
00344 Value v;
00345 v.init(dataType);
00346 v.setData(dataType, data);
00347
00348 if (!g_value_transform(v.d->value(), d->value())) {
00349 throw Private::TransformationFailedException(toStdStringHelper(dataType.name()),
00350 toStdStringHelper(type().name()));
00351 }
00352 } else {
00353 throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
00354 toStdStringHelper(type().name()));
00355 }
00356 }
00357
00358
00359 QDebug operator<<(QDebug debug, const Value & value)
00360 {
00361 debug.nospace() << "QGlib::Value";
00362 if(!value.isValid()) {
00363 debug << "(<invalid>)";
00364 return debug.space();
00365 } else {
00366 QString str = value.toString();
00367 if (str.isEmpty()) {
00368 if (g_value_fits_pointer(value)) {
00369 quintptr ptr = reinterpret_cast<quintptr>(g_value_peek_pointer(value));
00370 str = QString(QLatin1String("0x%1")).arg(ptr, sizeof(quintptr)*2,
00371 16, QLatin1Char('0'));
00372 } else {
00373 str = QLatin1String("<unknown value>");
00374 }
00375 }
00376
00377 debug << "(" << value.type().name() << ", " << str << ")";
00378 return debug.space();
00379 }
00380 }
00381
00382 }