1 /************************************************************************
2  *
3  * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com)
4  *
5  * This file is part of SuperCollider Qt GUI.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  ************************************************************************/
21 
22 #pragma once
23 
24 #include "type_codec.hpp"
25 
26 #include <PyrSlot.h>
27 
28 #include <QMetaType>
29 #include <QVariant>
30 
31 namespace QtCollider {
32 
33 struct MetaType {
34 public:
35     static void initAll();
36 
37     static MetaType* find(PyrSlot*);
38     static MetaType* find(int id);
39 
40     // Generic algorithms
41 
readQtCollider::MetaType42     template <typename T> static void* read(PyrSlot* slot, void* ptr) {
43         if (slot)
44             return new (ptr) T(TypeCodec<T>::read(slot));
45         else
46             return new (ptr) T();
47     }
48 
readQtCollider::MetaType49     template <typename T> static QVariant read(PyrSlot* slot) {
50         return QVariant::fromValue<T>(TypeCodec<T>::read(slot));
51     }
52 
writeQtCollider::MetaType53     template <typename T> static void write(PyrSlot* slot, void* ptr) {
54         TypeCodec<T>::write(slot, *reinterpret_cast<T*>(ptr));
55     }
56 
writeQtCollider::MetaType57     template <typename T> static void write(PyrSlot* slot, const QVariant& var) {
58         TypeCodec<T>::write(slot, var.value<T>());
59     }
60 
destructQtCollider::MetaType61     template <typename T> static void destruct(void* ptr) {
62         T* typed_ptr = reinterpret_cast<T*>(ptr);
63         typed_ptr->~T();
64     }
65 
66     // Abstract access to generic algorithms
67 
68     virtual size_t size() = 0;
69     virtual void* read(PyrSlot*, void* ptr) = 0;
70     virtual QVariant read(PyrSlot*) = 0;
71     virtual void write(PyrSlot*, void* ptr) = 0;
72     virtual void write(PyrSlot*, const QVariant&) = 0;
73     virtual void destruct(void* ptr) = 0;
74 
idQtCollider::MetaType75     const int& id() const { return mId; }
76 
77 protected:
MetaTypeQtCollider::MetaType78     MetaType(int a_id): mId(a_id) {}
79     int mId;
80 };
81 
82 template <typename T> struct MetaTypeImpl : MetaType {
MetaTypeImplQtCollider::MetaTypeImpl83     MetaTypeImpl(): MetaType(qMetaTypeId<T>()) {}
84 
sizeQtCollider::MetaTypeImpl85     size_t size() { return sizeof(T); }
86 
readQtCollider::MetaTypeImpl87     void* read(PyrSlot* slot, void* ptr) { return MetaType::read<T>(slot, ptr); }
88 
readQtCollider::MetaTypeImpl89     QVariant read(PyrSlot* slot) { return MetaType::read<T>(slot); }
90 
writeQtCollider::MetaTypeImpl91     void write(PyrSlot* slot, void* ptr) { MetaType::write<T>(slot, ptr); }
92 
writeQtCollider::MetaTypeImpl93     void write(PyrSlot* slot, const QVariant& var) { MetaType::write<T>(slot, var); }
94 
destructQtCollider::MetaTypeImpl95     void destruct(void* ptr) { MetaType::destruct<T>(ptr); }
96 
97     /////////////
98 
99     static MetaTypeImpl<T>* instance;
100 };
101 
102 class MetaValue {
103 public:
MetaValue()104     MetaValue(): mType(0), mData(0) {}
105 
~MetaValue()106     ~MetaValue() {
107         if (mType)
108             mType->destruct(mData);
109     }
110 
type() const111     MetaType* type() const { return mType; }
112 
read(void * mem,MetaType * type,PyrSlot * slot)113     void read(void* mem, MetaType* type, PyrSlot* slot) {
114         mData = mem;
115         mType = type;
116         mType->read(slot, mData);
117     }
118 
write(PyrSlot * slot)119     void write(PyrSlot* slot) {
120         if (mType)
121             mType->write(slot, mData);
122     }
123 
value()124     template <typename T> T value() {
125         if (mType && qMetaTypeId<T>() == mType->id())
126             return *reinterpret_cast<T*>(mData);
127         else
128             return T();
129     }
130 
toGenericArgument()131     QGenericArgument toGenericArgument() {
132         if (mType)
133             return QGenericArgument(QMetaType::typeName(mType->id()), mData);
134         else
135             return QGenericArgument();
136     }
137 
toGenericReturnArgument()138     QGenericReturnArgument toGenericReturnArgument() {
139         if (mType)
140             return QGenericReturnArgument(QMetaType::typeName(mType->id()), mData);
141         else
142             return QGenericReturnArgument();
143     }
144 
145 private:
146     MetaType* mType;
147     void* mData;
148 };
149 
150 
metaType()151 template <typename T> inline MetaType* metaType() { return MetaTypeImpl<T>::instance; }
152 
153 template <> struct TypeCodec<QVariant> {
safeReadQtCollider::TypeCodec154     static QVariant safeRead(PyrSlot* slot) {
155         MetaType* mt = MetaType::find(slot);
156         return mt ? mt->read(slot) : QVariant();
157     }
158 };
159 
set(PyrSlot * s,const QVariant & var)160 inline bool set(PyrSlot* s, const QVariant& var) {
161     MetaType* mt = MetaType::find(var.userType());
162     if (!mt)
163         return false;
164     mt->write(s, var);
165     return true;
166 }
167 
168 } // namespace QtCollider
169