QtGStreamer  0.10.2
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
value.cpp
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 Lesser 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 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 } //namespace QGlib