Add QFastMetaBuilder
[profile/ivi/qtdeclarative.git] / src / declarative / qml / ftw / qfastmetabuilder.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfastmetabuilder_p.h"
43
44 QT_BEGIN_NAMESPACE
45
46 struct QFastMetaBuilderHeader
47 {
48     int fieldCount;
49 };
50
51 struct QMetaObjectPrivate 
52 {
53     int revision;
54     int className;
55     int classInfoCount, classInfoData;
56     int methodCount, methodData;
57     int propertyCount, propertyData;
58     int enumeratorCount, enumeratorData;
59     int constructorCount, constructorData; //since revision 2
60     int flags; //since revision 3
61     int signalCount; //since revision 4
62 };
63
64 enum MetaObjectFlag {
65     DynamicMetaObject = 0x01
66 };
67
68 enum PropertyFlags  {
69     Invalid = 0x00000000,
70     Readable = 0x00000001,
71     Writable = 0x00000002,
72     Resettable = 0x00000004,
73     EnumOrFlag = 0x00000008,
74     StdCppSet = 0x00000100,
75 //     Override = 0x00000200,
76     Constant = 0x00000400,
77     Final = 0x00000800,
78     Designable = 0x00001000,
79     ResolveDesignable = 0x00002000,
80     Scriptable = 0x00004000,
81     ResolveScriptable = 0x00008000,
82     Stored = 0x00010000,
83     ResolveStored = 0x00020000,
84     Editable = 0x00040000,
85     ResolveEditable = 0x00080000,
86     User = 0x00100000,
87     ResolveUser = 0x00200000,
88     Notify = 0x00400000,
89     Revisioned = 0x00800000
90 };
91
92 enum MethodFlags  {
93     AccessPrivate = 0x00,
94     AccessProtected = 0x01,
95     AccessPublic = 0x02,
96     AccessMask = 0x03, //mask
97
98     MethodMethod = 0x00,
99     MethodSignal = 0x04,
100     MethodSlot = 0x08,
101     MethodConstructor = 0x0c,
102     MethodTypeMask = 0x0c,
103
104     MethodCompatibility = 0x10,
105     MethodCloned = 0x20,
106     MethodScriptable = 0x40,
107     MethodRevisioned = 0x80
108 };
109
110 #define FMBHEADER_FIELD_COUNT 1
111
112 #define HEADER_FIELD_COUNT 14
113 #define CLASSINFO_FIELD_COUNT 2
114 #define METHOD_FIELD_COUNT 5
115 #define PROPERTY_FIELD_COUNT 3
116 #define PROPERTY_NOTIFY_FIELD_COUNT 1
117
118 static inline uint *fieldPointer(QByteArray &data)
119 { return reinterpret_cast<uint *>(data.data()) + FMBHEADER_FIELD_COUNT; }
120
121 static inline const uint *fieldPointer(const QByteArray &data)
122 { return reinterpret_cast<const uint *>(data.constData()) + FMBHEADER_FIELD_COUNT; }
123
124 static inline QMetaObjectPrivate *priv(QByteArray &data)
125 { return reinterpret_cast<QMetaObjectPrivate*>(fieldPointer(data)); }
126
127 static inline const QMetaObjectPrivate *priv(const QByteArray &data)
128 { return reinterpret_cast<const QMetaObjectPrivate*>(fieldPointer(data)); }
129
130 static inline QFastMetaBuilderHeader *header(QByteArray &data)
131 { return reinterpret_cast<QFastMetaBuilderHeader*>(data.data()); }
132
133 static inline const QFastMetaBuilderHeader *header(const QByteArray &data)
134 { return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); }
135
136 QFastMetaBuilder::QFastMetaBuilder()
137 : m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0)
138 {
139 }
140
141 QFastMetaBuilder::~QFastMetaBuilder()
142 {
143 }
144
145 QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength,
146                                                    int propertyCount, int methodCount, 
147                                                    int signalCount, int classInfoCount)
148 {
149     Q_ASSERT(m_data.isEmpty());
150     Q_ASSERT(classNameLength > 0);
151     Q_ASSERT(propertyCount >= 0);
152     Q_ASSERT(methodCount >= 0);
153     Q_ASSERT(signalCount >= 0);
154     Q_ASSERT(classInfoCount >= 0);
155
156     int fieldCount = FMBHEADER_FIELD_COUNT +
157                      HEADER_FIELD_COUNT + 
158                      propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) +
159                      methodCount * (METHOD_FIELD_COUNT) +
160                      signalCount * (METHOD_FIELD_COUNT) +
161                      classInfoCount * CLASSINFO_FIELD_COUNT;
162
163     m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1);
164     m_stringData = m_data.data() + m_data.size() - classNameLength - 1;
165     m_stringDataLength = classNameLength + 1;
166     m_stringDataAllocated = classNameLength + 1;
167     m_stringData[classNameLength] = 0;
168     m_zeroPtr = classNameLength;
169
170     header(m_data)->fieldCount = fieldCount;
171
172     QMetaObjectPrivate *p = priv(m_data);
173
174     int dataIndex = HEADER_FIELD_COUNT;
175
176     p->revision = 4;
177     p->className = 0;
178
179     // Class infos
180     p->classInfoCount = classInfoCount;
181     if (p->classInfoCount) { 
182         p->classInfoData = dataIndex;
183         dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT;
184     } else {
185         p->classInfoData = 0;
186     }
187
188     // Methods
189     p->methodCount = methodCount + signalCount;
190     if (p->methodCount) {
191         p->methodData = dataIndex;
192         dataIndex += p->methodCount * METHOD_FIELD_COUNT;
193     } else {
194         p->methodData = 0;
195     }
196     p->signalCount = signalCount;
197
198     // Properties
199     p->propertyCount = propertyCount;
200     if (p->propertyCount) {
201         p->propertyData = dataIndex;
202         dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT);
203     } else {
204         p->propertyData = 0;
205     }
206
207     // Flags
208     p->flags = DynamicMetaObject; // Always dynamic
209
210     // Enums and constructors not supported
211     p->enumeratorCount = 0;
212     p->enumeratorData = 0;
213     p->constructorCount = 0;
214     p->constructorData = 0;
215
216     StringRef className;
217     className._b = this;
218     className._o = 0;
219     className._l = classNameLength;
220     return className;
221 }
222
223 // Allocate a string of \a length.  \a length should *not* include the null terminator.
224 QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length)
225 {
226     Q_ASSERT(length > 0);
227
228     StringRef sr;
229     sr._b = this;
230     sr._o = m_stringDataLength;
231     sr._l = length;
232
233     m_stringDataLength += length + 1 /* for null terminator */;
234
235     return sr;
236 }
237
238 void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value)
239 {
240     Q_ASSERT(!m_data.isEmpty());
241     Q_ASSERT(!key.isEmpty() && !value.isEmpty());
242
243     QMetaObjectPrivate *p = priv(m_data);
244     Q_ASSERT(index < p->classInfoCount);
245
246     uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT;
247     // classinfo: key, value
248     ptr[0] = key.offset(); ptr[1] = value.offset();
249 }
250
251 void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, 
252                                    QMetaType::Type mtype, PropertyFlag flags, int notifySignal)
253 {
254     Q_ASSERT(!m_data.isEmpty());
255     Q_ASSERT(!name.isEmpty() && !type.isEmpty());
256
257     QMetaObjectPrivate *p = priv(m_data);
258     Q_ASSERT(index < p->propertyCount);
259
260     uint qtType = mtype;
261     if ((int)qtType == qMetaTypeId<QVariant>())
262         qtType = 0xFF; // Special handling for QVariant
263
264     uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
265     // properties: name, type, flags
266     ptr[0] = name.offset();
267     ptr[1] = type.offset();
268     if (notifySignal == -1) {
269         ptr[2] = qtType << 24;
270         ptr[2] |= flags | Scriptable | Readable;
271         *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
272     } else {
273         ptr[2] = qtType << 24;
274         ptr[2] |= flags | Scriptable | Readable | Notify;
275         *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
276     }
277 }
278
279 void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, 
280                                    QFastMetaBuilder::PropertyFlag flags, int notifySignal)
281 {
282     Q_ASSERT(!m_data.isEmpty());
283     Q_ASSERT(!name.isEmpty() && !type.isEmpty());
284
285     QMetaObjectPrivate *p = priv(m_data);
286     Q_ASSERT(index < p->propertyCount);
287
288     uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
289     // properties: name, type, flags
290     ptr[0] = name.offset();
291     ptr[1] = type.offset();
292     if (notifySignal == -1) {
293         ptr[2] = flags | Scriptable | Readable;
294         *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
295     } else {
296         ptr[2] = flags | Scriptable | Readable | Notify;
297         *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
298     }
299 }
300
301 void QFastMetaBuilder::setSignal(int index, const StringRef &signature,
302                                  const StringRef &parameterNames,
303                                  const StringRef &type)
304 {
305     Q_ASSERT(!m_data.isEmpty());
306     Q_ASSERT(!signature.isEmpty());
307
308     QMetaObjectPrivate *p = priv(m_data);
309     int mindex = metaObjectIndexForSignal(index);
310
311     uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
312     // methods: signature, parameters, type, tag, flags
313     ptr[0] = signature.offset();
314     ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
315     ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
316     ptr[3] = m_zeroPtr;
317     ptr[4] = AccessProtected | MethodSignal;
318 }
319
320 void QFastMetaBuilder::setMethod(int index, const StringRef &signature,
321                                  const StringRef &parameterNames,
322                                  const StringRef &type)
323 {
324     Q_ASSERT(!m_data.isEmpty());
325     Q_ASSERT(!signature.isEmpty());
326
327     QMetaObjectPrivate *p = priv(m_data);
328     int mindex = metaObjectIndexForMethod(index);
329
330     uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
331     // methods: signature, parameters, type, tag, flags
332     ptr[0] = signature.offset();
333     ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
334     ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
335     ptr[3] = m_zeroPtr;
336     ptr[4] = AccessProtected | MethodSlot;
337 }
338
339 int QFastMetaBuilder::metaObjectIndexForSignal(int index) const
340 {
341     Q_ASSERT(!m_data.isEmpty());
342     Q_ASSERT(index < priv(m_data)->signalCount);
343     return index;
344 }
345
346 int QFastMetaBuilder::metaObjectIndexForMethod(int index) const
347 {
348     Q_ASSERT(!m_data.isEmpty());
349
350     const QMetaObjectPrivate *p = priv(m_data);
351     Q_ASSERT(index < (p->methodCount - p->signalCount));
352     return index + p->signalCount;
353 }
354
355 void QFastMetaBuilder::allocateStringData()
356 {
357     if (m_stringDataAllocated < m_stringDataLength) {
358         m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated);
359         m_stringDataAllocated = m_stringDataLength;
360         m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint);
361     }
362 }
363
364 void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data)
365 {
366     output->d.superdata = parent;
367     output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint);
368     output->d.data = fieldPointer(data);
369 }
370
371 QT_END_NAMESPACE