summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/QGlib/value.cpp208
-rw-r--r--src/QGlib/value.h248
2 files changed, 273 insertions, 183 deletions
diff --git a/src/QGlib/value.cpp b/src/QGlib/value.cpp
index 2b9616e..e353ca0 100644
--- a/src/QGlib/value.cpp
+++ b/src/QGlib/value.cpp
@@ -1,5 +1,7 @@
/*
Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
+ Copyright (C) 2010 Collabora Ltd.
+ @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
@@ -18,8 +20,91 @@
#include "string.h"
#include <glib-object.h>
#include <QtCore/QDebug>
+#include <QtCore/QReadWriteLock>
namespace QGlib {
+namespace Private {
+
+class Dispatcher
+{
+public:
+ Dispatcher();
+
+ ValueVTable getVTable(Type t) const;
+ void setVTable(Type t, const ValueVTable & vtable);
+
+private:
+ mutable QReadWriteLock lock;
+ QHash<Type, ValueVTable> dispatchTable;
+};
+
+Dispatcher::Dispatcher()
+{
+#define DECLARE_VTABLE(T, NICK, GTYPE) \
+ struct ValueVTable_##NICK \
+ { \
+ static void get(const ValueBase & value, void *data) \
+ { \
+ *reinterpret_cast<T*>(data) = g_value_get_##NICK(value); \
+ }; \
+ \
+ static void set(ValueBase & value, const void *data) \
+ { \
+ g_value_set_##NICK(value, *reinterpret_cast<T const *>(data)); \
+ }; \
+ }; \
+ setVTable(GTYPE, ValueVTable(ValueVTable_##NICK::set, ValueVTable_##NICK::get));
+
+ DECLARE_VTABLE(char, char, Type::Char)
+ DECLARE_VTABLE(unsigned char, uchar, Type::Uchar)
+ DECLARE_VTABLE(bool, boolean, Type::Boolean)
+ DECLARE_VTABLE(int, int, Type::Int)
+ DECLARE_VTABLE(unsigned int, uint, Type::Uint)
+ DECLARE_VTABLE(long, long, Type::Long)
+ DECLARE_VTABLE(unsigned long, ulong, Type::Ulong)
+ DECLARE_VTABLE(qint64, int64, Type::Int64)
+ DECLARE_VTABLE(quint64, uint64, Type::Uint64)
+ DECLARE_VTABLE(int, enum, Type::Enum);
+ DECLARE_VTABLE(uint, flags, Type::Flags)
+ DECLARE_VTABLE(float, float, Type::Float)
+ DECLARE_VTABLE(double, double, Type::Double)
+ DECLARE_VTABLE(QByteArray, string, Type::String)
+ DECLARE_VTABLE(void*, pointer, Type::Pointer)
+ DECLARE_VTABLE(void*, boxed, Type::Boxed)
+ DECLARE_VTABLE(GParamSpec*, param, Type::Param)
+ DECLARE_VTABLE(void*, object, Type::Object)
+ DECLARE_VTABLE(QGlib::Type, gtype, GetType<QGlib::Type>())
+
+#undef DECLARE_VTABLE
+}
+
+ValueVTable Dispatcher::getVTable(Type t) const
+{
+ QReadLocker l(&lock);
+
+ if (dispatchTable.contains(t)) {
+ return dispatchTable[t];
+ }
+
+ while (t.isDerived()) {
+ t = t.parent();
+ if (dispatchTable.contains(t)) {
+ return dispatchTable[t];
+ }
+ }
+
+ return ValueVTable();
+}
+
+void Dispatcher::setVTable(Type t, const ValueVTable & vtable)
+{
+ QWriteLocker l(&lock);
+ dispatchTable[t] = vtable;
+}
+
+} //namespace Private
+
+Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);
//BEGIN ValueBase
@@ -64,6 +149,70 @@ Value ValueBase::transformTo(Type t) const
return dest;
}
+//static
+void ValueBase::registerValueVTable(Type type, const ValueVTable & vtable)
+{
+ s_dispatcher()->setVTable(type, vtable);
+}
+
+void ValueBase::getData(Type dataType, void *data) const
+{
+ if (!isValid()) {
+ throw InvalidValueException();
+ } else if (g_value_type_compatible(type(), dataType)) {
+ ValueVTable vtable = s_dispatcher()->getVTable(dataType);
+ if (vtable.get != NULL) {
+ vtable.get(*this, data);
+ } else {
+ throw std::logic_error("Unable to handle the given type. Type is not registered");
+ }
+ } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) {
+ Value v;
+ v.init(dataType);
+
+ if (!g_value_transform(m_value, v.m_value)) {
+ throw InvalidTypeException();
+ }
+
+ try {
+ v.getData(dataType, data);
+ } catch (const InvalidTypeException &) {
+ Q_ASSERT(false); //This must never happen
+ }
+ } else {
+ throw InvalidTypeException();
+ }
+}
+
+void ValueBase::setData(Type dataType, const void *data)
+{
+ if (!isValid()) {
+ throw InvalidValueException();
+ } else if (g_value_type_compatible(dataType, type())) {
+ ValueVTable vtable = s_dispatcher()->getVTable(dataType);
+ if (vtable.set != NULL) {
+ vtable.set(*this, data);
+ } else {
+ throw std::logic_error("Unable to handle the given type. Type is not registered");
+ }
+ } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) {
+ Value v;
+ v.init(dataType);
+
+ try {
+ v.setData(dataType, data);
+ } catch (const InvalidTypeException &) {
+ Q_ASSERT(false); //This must never happen
+ }
+
+ if (!g_value_transform(v.m_value, m_value)) {
+ throw InvalidTypeException();
+ }
+ } else {
+ throw InvalidTypeException();
+ }
+}
+
//END ValueBase
//BEGIN Value
@@ -164,42 +313,7 @@ SharedValue & SharedValue::operator=(const SharedValue & other)
//END SharedValue
-
-//BEGIN ValueImpl internal helpers
-
-uint ValueImpl_Flags::get(const ValueBase & value)
-{
- return g_value_get_flags(value);
-}
-
-void ValueImpl_Flags::set(ValueBase & value, uint data)
-{
- g_value_set_flags(value, data);
-}
-
-int ValueImpl_Enum::get(const ValueBase & value)
-{
- return g_value_get_enum(value);
-}
-
-void ValueImpl_Enum::set(ValueBase & value, int data)
-{
- g_value_set_enum(value, data);
-}
-
-void *ValueImpl_Boxed::get(const ValueBase & value)
-{
- return g_value_get_boxed(value);
-}
-
-void ValueImpl_Boxed::set(ValueBase & value, void *data)
-{
- g_value_set_boxed(value, data);
-}
-
-//END ValueImpl internal helpers
-
-}
+} //namespace QGlib
QDebug & operator<<(QDebug debug, const QGlib::ValueBase & value)
@@ -225,25 +339,3 @@ QDebug & operator<<(QDebug debug, const QGlib::ValueBase & value)
return debug.space();
}
}
-
-#define SHORT_VALUEIMPL_IMPLEMENTATION(T, NICK) \
- QGLIB_REGISTER_VALUEIMPL_IMPLEMENTATION(T, g_value_get_##NICK(value), g_value_set_##NICK(value, data))
-
-SHORT_VALUEIMPL_IMPLEMENTATION(bool, boolean)
-SHORT_VALUEIMPL_IMPLEMENTATION(char, char)
-SHORT_VALUEIMPL_IMPLEMENTATION(unsigned char, uchar)
-SHORT_VALUEIMPL_IMPLEMENTATION(int, int)
-SHORT_VALUEIMPL_IMPLEMENTATION(unsigned int, uint)
-SHORT_VALUEIMPL_IMPLEMENTATION(long, long)
-SHORT_VALUEIMPL_IMPLEMENTATION(unsigned long, ulong)
-SHORT_VALUEIMPL_IMPLEMENTATION(qint64, int64)
-SHORT_VALUEIMPL_IMPLEMENTATION(quint64, uint64)
-SHORT_VALUEIMPL_IMPLEMENTATION(float, float)
-SHORT_VALUEIMPL_IMPLEMENTATION(double, double)
-SHORT_VALUEIMPL_IMPLEMENTATION(void*, pointer)
-SHORT_VALUEIMPL_IMPLEMENTATION(QGlib::Type, gtype)
-SHORT_VALUEIMPL_IMPLEMENTATION(const char*, string)
-SHORT_VALUEIMPL_IMPLEMENTATION(QByteArray, string)
-
-QGLIB_REGISTER_VALUEIMPL_IMPLEMENTATION(QString, QString::fromUtf8(g_value_get_string(value)),
- g_value_set_string(value, data.toUtf8().constData()))
diff --git a/src/QGlib/value.h b/src/QGlib/value.h
index 66f0f04..061dbc4 100644
--- a/src/QGlib/value.h
+++ b/src/QGlib/value.h
@@ -1,5 +1,7 @@
/*
Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
+ Copyright (C) 2010 Collabora Ltd.
+ @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
@@ -19,11 +21,28 @@
#include "global.h"
#include "type.h"
+#include "refpointer.h"
+#include <boost/mpl/if.hpp>
#include <boost/type_traits.hpp>
#include <stdexcept>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
namespace QGlib {
+struct ValueVTable
+{
+ typedef void (*SetFunction)(ValueBase & value, const void *data);
+ typedef void (*GetFunction)(const ValueBase & value, void *data);
+
+ inline ValueVTable() : set(NULL), get(NULL) {}
+ inline ValueVTable(SetFunction s, GetFunction g) : set(s), get(g) {}
+
+ SetFunction set;
+ GetFunction get;
+};
+
+
/*! \headerfile value.h <QGlib/Value>
* \brief Common base class for Value and SharedValue, wrappers for GValue
*/
@@ -105,7 +124,19 @@ public:
inline operator GValue*() { return m_value; }
inline operator const GValue*() const { return m_value; }
+ /*! \internal */
+ static void registerValueVTable(Type type, const ValueVTable & vtable);
+
protected:
+ template <typename T>
+ friend struct ValueImpl;
+
+ /*! \internal */
+ void getData(Type dataType, void *data) const;
+ /*! \internal */
+ void setData(Type dataType, const void *data);
+
+
ValueBase(GValue *val);
virtual ~ValueBase();
Q_DISABLE_COPY(ValueBase)
@@ -182,101 +213,27 @@ struct ValueImpl
static inline void set(ValueBase & value, const T & data);
};
-/*! \addtogroup macros Internal macros */
-//@{
-
-/*! This macro declares a specialization for ValueImpl for the type \a T.
- * It should be used in a header, in combination with QGLIB_REGISTER_VALUEIMPL_IMPLEMENTATION
- * in the respective source file, which will define the implementation of this specialization.
- * \sa QGlib::ValueImpl, QGLIB_REGISTER_VALUEIMPL_IMPLEMENTATION
- */
-#define QGLIB_REGISTER_VALUEIMPL(T) \
- namespace QGlib { \
- template <> \
- struct ValueImpl<T> \
- { \
- static T get(const ValueBase & value); \
- static void set(ValueBase & value, T const & data); \
- }; \
- }
-
-/*! This macro defines the implementation of a ValueImpl specialization for type \a T.
- * \param GET_IMPL should be an expression that evaluates to type T and extracts a value from
- * a const ValueBase refererence called 'value'
- * \param SET_IMPL should be an expression that evaluates to void and sets the data from a
- * const T reference called 'data' to a ValueBase reference called 'value'
- * \sa QGLIB_REGISTER_VALUEIMPL, QGlib::ValueImpl, QGlib::ValueBase
- */
-#define QGLIB_REGISTER_VALUEIMPL_IMPLEMENTATION(T, GET_IMPL, SET_IMPL) \
- namespace QGlib { \
- T ValueImpl<T>::get(const ValueBase & value) \
- { \
- return (GET_IMPL);\
- } \
- void ValueImpl<T>::set(ValueBase & value, T const & data) \
- { \
- (SET_IMPL);\
- } \
- }
-
-/*! This macro declares a specialization (with its inline implementation)
- * for ValueImpl for the type \a T, where \a T is a Boxed type.
- * You can use this macro to register any boxed type in your code, in case
- * you need to use it with an element property or with a signal.
- * You will also need to register type \a T with the type system first,
- * using the QGLIB_REGISTER_BOXED_TYPE macro.
- *
- * Example:
- * \code
- * QGLIB_REGISTER_BOXED_TYPE(GList*)
- * QGLIB_REGISTER_VALUEIMPL_FOR_BOXED_TYPE(GList*)
- * \endcode
- *
- * \note \a T must be a pointer
- * \sa QGLIB_REGISTER_BOXED_TYPE
- */
-#define QGLIB_REGISTER_VALUEIMPL_FOR_BOXED_TYPE(T) \
- namespace QGlib { \
- template <> \
- struct ValueImpl<T> \
- { \
- static T get(const ValueBase & value) { \
- return static_cast<T>(ValueImpl_Boxed::get(value)); \
- } \
- static void set(ValueBase & value, T const & data) { \
- ValueImpl_Boxed::set(value, static_cast<void*>(data)); \
- } \
- }; \
- }
-
-//@}
-
// -- template implementations --
template <typename T>
T ValueBase::get() const
{
- if (!isValid()) {
- throw InvalidValueException();
- }
- if (!QGlib::Private::CanConvertTo<T>::from(type())) {
- throw InvalidTypeException();
+ try {
+ return ValueImpl<T>::get(*this);
+ } catch (const std::exception & e) {
+ qWarning() << "QGlib::ValueBase::get:" << e.what();
+ return T();
}
-
- return ValueImpl<T>::get(*this);
}
template <typename T>
void ValueBase::set(const T & data)
{
- if (!isValid()) {
- throw InvalidValueException();
- }
- if (!QGlib::Private::CanConvertFrom<T>::to(type())) {
- throw InvalidTypeException();
+ try {
+ ValueImpl<T>::set(*this, data);
+ } catch (const std::exception & e) {
+ qWarning() << "QGlib::ValueBase::set:" << e.what();
}
-
- ValueImpl<T>::set(*this, data);
}
@@ -294,58 +251,116 @@ inline void Value::init()
init(GetType<T>());
}
-// -- default ValueImpl implementation (handles enums) --
-
-struct ValueImpl_Enum
-{
- static int get(const ValueBase & value);
- static void set(ValueBase & value, int data);
-};
+// -- default ValueImpl implementation --
template <typename T>
inline T ValueImpl<T>::get(const ValueBase & value)
{
- QGLIB_STATIC_ASSERT(boost::is_enum<T>::value,
- "No QGlib::ValueImpl<T> specialization has been registered for this type");
- return static_cast<T>(ValueImpl_Enum::get(value));
+ //Use int for enums, T for everything else
+ typename boost::mpl::if_<
+ boost::is_enum<T>,
+ int, T
+ >::type result;
+
+ value.getData(GetType<T>(), &result);
+ return static_cast<T>(result);
}
template <typename T>
inline void ValueImpl<T>::set(ValueBase & value, const T & data)
{
- QGLIB_STATIC_ASSERT(boost::is_enum<T>::value,
- "No QGlib::ValueImpl<T> specialization has been registered for this type");
- ValueImpl_Enum::set(value, static_cast<int>(data));
+ //Use const int for enums, const T for everything else
+ typename boost::mpl::if_<
+ boost::is_enum<T>,
+ const int, const T &
+ >::type dataRef = data;
+
+ value.setData(GetType<T>(), &dataRef);
}
// -- ValueImpl specialization for QFlags --
-struct ValueImpl_Flags
-{
- static uint get(const ValueBase & value);
- static void set(ValueBase & value, uint data);
-};
-
template <class T>
struct ValueImpl< QFlags<T> >
{
static inline QFlags<T> get(const ValueBase & value)
{
- return QFlags<T>(QFlag(ValueImpl_Flags::get(value)));
+ uint flags;
+ value.getData(GetType< QFlags<T> >(), &flags);
+ return QFlags<T>(QFlag(flags));
}
static inline void set(ValueBase & value, const QFlags<T> & data)
{
- ValueImpl_Flags::set(value, static_cast<uint>(data));
+ uint flags = data;
+ value.setData(GetType< QFlags<T> >(), &flags);
+ }
+};
+
+// -- ValueImpl specialization for RefPointer --
+
+template <class T>
+struct ValueImpl< RefPointer<T> >
+{
+ static inline RefPointer<T> get(const ValueBase & value)
+ {
+ typename T::CType *gobj;
+ value.getData(GetType<T>(), &gobj);
+ return RefPointer<T>::wrap(gobj);
+ }
+
+ static inline void set(ValueBase & value, const RefPointer<T> & data)
+ {
+ typename T::CType *gobj = static_cast<typename T::CType*>(data);
+ value.setData(GetType<T>(), &gobj);
+ }
+};
+
+// -- ValueImpl specialization for string literals --
+
+template <int N>
+struct ValueImpl<char[N]>
+{
+ //No get method, obviously.
+
+ static inline void set(ValueBase & value, const char (&data)[N])
+ {
+ QByteArray str = QByteArray::fromRawData(data, N);
+ value.setData(Type::String, &str);
+ }
+};
+
+// -- ValueImpl specialization for const char* --
+
+template <>
+struct ValueImpl<const char*>
+{
+ //No get method, obviously.
+
+ static inline void set(ValueBase & value, const char *data)
+ {
+ QByteArray str = QByteArray::fromRawData(data, qstrlen(data));
+ value.setData(Type::String, &str);
}
};
-// -- ValueImpl helper for using boxed types --
+// -- ValueImpl specialization for QString --
-struct ValueImpl_Boxed
+template <>
+struct ValueImpl<QString>
{
- static void *get(const ValueBase & value);
- static void set(ValueBase & value, void *data);
+ static inline QString get(const ValueBase & value)
+ {
+ QByteArray str;
+ value.getData(Type::String, &str);
+ return QString::fromUtf8(str);
+ }
+
+ static inline void set(ValueBase & value, const QString & data)
+ {
+ QByteArray str = data.toUtf8();
+ value.setData(Type::String, &str);
+ }
};
} //namespace QGlib
@@ -357,21 +372,4 @@ QGLIB_REGISTER_TYPE(QGlib::ValueBase) //codegen: GType=G_TYPE_VALUE
QGLIB_REGISTER_TYPE(QGlib::Value)
QGLIB_REGISTER_TYPE(QGlib::SharedValue) //codegen: GType=G_TYPE_VALUE
-QGLIB_REGISTER_VALUEIMPL(bool)
-QGLIB_REGISTER_VALUEIMPL(char)
-QGLIB_REGISTER_VALUEIMPL(unsigned char)
-QGLIB_REGISTER_VALUEIMPL(int)
-QGLIB_REGISTER_VALUEIMPL(unsigned int)
-QGLIB_REGISTER_VALUEIMPL(long)
-QGLIB_REGISTER_VALUEIMPL(unsigned long)
-QGLIB_REGISTER_VALUEIMPL(qint64)
-QGLIB_REGISTER_VALUEIMPL(quint64)
-QGLIB_REGISTER_VALUEIMPL(float)
-QGLIB_REGISTER_VALUEIMPL(double)
-QGLIB_REGISTER_VALUEIMPL(void*)
-QGLIB_REGISTER_VALUEIMPL(QGlib::Type)
-QGLIB_REGISTER_VALUEIMPL(const char*)
-QGLIB_REGISTER_VALUEIMPL(QByteArray)
-QGLIB_REGISTER_VALUEIMPL(QString)
-
#endif