1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QQMLPROFILEREVENT_P_H
41#define QQMLPROFILEREVENT_P_H
42
43#include "qqmlprofilerclientdefinitions_p.h"
44
45#include <QtCore/qstring.h>
46#include <QtCore/qbytearray.h>
47#include <QtCore/qvarlengtharray.h>
48#include <QtCore/qmetatype.h>
49
50#include <initializer_list>
51#include <limits>
52#include <type_traits>
53
54//
55// W A R N I N G
56// -------------
57//
58// This file is not part of the Qt API. It exists purely as an
59// implementation detail. This header file may change from version to
60// version without notice, or even be removed.
61//
62// We mean it.
63//
64
65QT_BEGIN_NAMESPACE
66
67struct QQmlProfilerEvent {
68 QQmlProfilerEvent() :
69 m_timestamp(-1), m_typeIndex(-1), m_dataType(Inline8Bit), m_dataLength(0)
70 {}
71
72 template<typename Number>
73 QQmlProfilerEvent(qint64 timestamp, int typeIndex, std::initializer_list<Number> list)
74 : m_timestamp(timestamp), m_typeIndex(typeIndex)
75 {
76 assignNumbers<std::initializer_list<Number>, Number>(list);
77 }
78
79 QQmlProfilerEvent(qint64 timestamp, int typeIndex, const QString &data)
80 : m_timestamp(timestamp), m_typeIndex(typeIndex)
81 {
82 assignNumbers<QByteArray, qint8>(numbers: data.toUtf8());
83 }
84
85 template<typename Number>
86 QQmlProfilerEvent(qint64 timestamp, int typeIndex, const QVector<Number> &data)
87 : m_timestamp(timestamp), m_typeIndex(typeIndex)
88 {
89 assignNumbers<QVector<Number>, Number>(data);
90 }
91
92 QQmlProfilerEvent(const QQmlProfilerEvent &other)
93 : m_timestamp(other.m_timestamp), m_typeIndex(other.m_typeIndex),
94 m_dataType(other.m_dataType), m_dataLength(other.m_dataLength)
95 {
96 assignData(other);
97 }
98
99 QQmlProfilerEvent(QQmlProfilerEvent &&other)
100 {
101 memcpy(dest: static_cast<void *>(this), src: static_cast<const void *>(&other), n: sizeof(QQmlProfilerEvent));
102 other.m_dataType = Inline8Bit; // prevent dtor from deleting the pointer
103 }
104
105 QQmlProfilerEvent &operator=(const QQmlProfilerEvent &other)
106 {
107 if (this != &other) {
108 clearPointer();
109 m_timestamp = other.m_timestamp;
110 m_typeIndex = other.m_typeIndex;
111 m_dataType = other.m_dataType;
112 m_dataLength = other.m_dataLength;
113 assignData(other);
114 }
115 return *this;
116 }
117
118 QQmlProfilerEvent &operator=(QQmlProfilerEvent &&other)
119 {
120 if (this != &other) {
121 memcpy(dest: static_cast<void *>(this), src: static_cast<const void *>(&other), n: sizeof(QQmlProfilerEvent));
122 other.m_dataType = Inline8Bit;
123 }
124 return *this;
125 }
126
127 ~QQmlProfilerEvent()
128 {
129 clearPointer();
130 }
131
132 qint64 timestamp() const { return m_timestamp; }
133 void setTimestamp(qint64 timestamp) { m_timestamp = timestamp; }
134
135 int typeIndex() const { return m_typeIndex; }
136 void setTypeIndex(int typeIndex) { m_typeIndex = typeIndex; }
137
138 template<typename Number>
139 Number number(int i) const
140 {
141 // Trailing zeroes can be omitted, for example for SceneGraph events
142 if (i >= m_dataLength)
143 return 0;
144 switch (m_dataType) {
145 case Inline8Bit:
146 return m_data.internal8bit[i];
147QT_WARNING_PUSH
148QT_WARNING_DISABLE_GCC("-Warray-bounds") // Mingw 5.3 gcc doesn't get the type/length logic.
149 case Inline16Bit:
150 return m_data.internal16bit[i];
151 case Inline32Bit:
152 return m_data.internal32bit[i];
153 case Inline64Bit:
154 return m_data.internal64bit[i];
155QT_WARNING_POP
156 case External8Bit:
157 return static_cast<const qint8 *>(m_data.external)[i];
158 case External16Bit:
159 return static_cast<const qint16 *>(m_data.external)[i];
160 case External32Bit:
161 return static_cast<const qint32 *>(m_data.external)[i];
162 case External64Bit:
163 return static_cast<const qint64 *>(m_data.external)[i];
164 default:
165 return 0;
166 }
167 }
168
169 template<typename Number>
170 void setNumber(int i, Number number)
171 {
172 QVarLengthArray<Number> nums = numbers<QVarLengthArray<Number>, Number>();
173 int prevSize = nums.size();
174 if (i >= prevSize) {
175 nums.resize(i + 1);
176 // Fill with zeroes. We don't want to accidentally prevent squeezing.
177 while (prevSize < i)
178 nums[prevSize++] = 0;
179 }
180 nums[i] = number;
181 setNumbers<QVarLengthArray<Number>, Number>(nums);
182 }
183
184 template<typename Container, typename Number>
185 void setNumbers(const Container &numbers)
186 {
187 clearPointer();
188 assignNumbers<Container, Number>(numbers);
189 }
190
191 template<typename Number>
192 void setNumbers(std::initializer_list<Number> numbers)
193 {
194 setNumbers<std::initializer_list<Number>, Number>(numbers);
195 }
196
197 template<typename Container, typename Number = qint64>
198 Container numbers() const
199 {
200 Container container;
201 for (int i = 0; i < m_dataLength; ++i)
202 container.append(number<Number>(i));
203 return container;
204 }
205
206 QString string() const
207 {
208 switch (m_dataType) {
209 case External8Bit:
210 return QString::fromUtf8(str: static_cast<const char *>(m_data.external), size: m_dataLength);
211 case Inline8Bit:
212 return QString::fromUtf8(str: m_data.internalChar, size: m_dataLength);
213 default:
214 Q_UNREACHABLE();
215 return QString();
216 }
217 }
218
219 void setString(const QString &data)
220 {
221 clearPointer();
222 assignNumbers<QByteArray, char>(numbers: data.toUtf8());
223 }
224
225 Message rangeStage() const
226 {
227 Q_ASSERT(m_dataType == Inline8Bit);
228 return static_cast<Message>(m_data.internal8bit[0]);
229 }
230
231 void setRangeStage(Message stage)
232 {
233 clearPointer();
234 m_dataType = Inline8Bit;
235 m_dataLength = 1;
236 m_data.internal8bit[0] = stage;
237 }
238
239 bool isValid() const
240 {
241 return m_timestamp != -1;
242 }
243
244private:
245 enum Type: quint16 {
246 External = 1,
247 Inline8Bit = 8,
248 External8Bit = Inline8Bit | External,
249 Inline16Bit = 16,
250 External16Bit = Inline16Bit | External,
251 Inline32Bit = 32,
252 External32Bit = Inline32Bit | External,
253 Inline64Bit = 64,
254 External64Bit = Inline64Bit | External
255 };
256
257 qint64 m_timestamp;
258
259 static const int s_internalDataLength = 8;
260 union {
261 void *external;
262 char internalChar [s_internalDataLength];
263 qint8 internal8bit [s_internalDataLength];
264 qint16 internal16bit[s_internalDataLength / 2];
265 qint32 internal32bit[s_internalDataLength / 4];
266 qint64 internal64bit[s_internalDataLength / 8];
267 } m_data;
268
269 qint32 m_typeIndex;
270 Type m_dataType;
271 quint16 m_dataLength;
272
273 void assignData(const QQmlProfilerEvent &other)
274 {
275 if (m_dataType & External) {
276 uint length = m_dataLength * (other.m_dataType / 8);
277 m_data.external = malloc(size: length);
278 memcpy(dest: m_data.external, src: other.m_data.external, n: length);
279 } else {
280 memcpy(dest: &m_data, src: &other.m_data, n: sizeof(m_data));
281 }
282 }
283
284 template<typename Big, typename Small>
285 bool squeezable(Big source)
286 {
287 return static_cast<Small>(source) == source;
288 }
289
290 template<typename Container, typename Number>
291 typename std::enable_if<(sizeof(Number) > 1), bool>::type
292 squeeze(const Container &numbers)
293 {
294 typedef typename QIntegerForSize<sizeof(Number) / 2>::Signed Small;
295 for (Number item : numbers) {
296 if (!squeezable<Number, Small>(item))
297 return false;
298 }
299 assignNumbers<Container, Small>(numbers);
300 return true;
301 }
302
303 template<typename Container, typename Number>
304 typename std::enable_if<(sizeof(Number) <= 1), bool>::type
305 squeeze(const Container &)
306 {
307 return false;
308 }
309
310 template<typename Container, typename Number>
311 void assignNumbers(const Container &numbers)
312 {
313 Number *data;
314 m_dataLength = squeezable<size_t, quint16>(source: static_cast<size_t>(numbers.size())) ?
315 static_cast<quint16>(numbers.size()) : std::numeric_limits<quint16>::max();
316 if (m_dataLength > sizeof(m_data) / sizeof(Number)) {
317 if (squeeze<Container, Number>(numbers))
318 return;
319 m_dataType = static_cast<Type>((sizeof(Number) * 8) | External);
320 m_data.external = malloc(size: m_dataLength * sizeof(Number));
321 data = static_cast<Number *>(m_data.external);
322 } else {
323 m_dataType = static_cast<Type>(sizeof(Number) * 8);
324 data = static_cast<Number *>(m_dataType & External ? m_data.external : &m_data);
325 }
326 quint16 i = 0;
327 for (Number item : numbers) {
328 if (i >= m_dataLength)
329 break;
330 data[i++] = item;
331 }
332 }
333
334 void clearPointer()
335 {
336 if (m_dataType & External)
337 free(ptr: m_data.external);
338 }
339
340 friend QDataStream &operator>>(QDataStream &stream, QQmlProfilerEvent &event);
341 friend QDataStream &operator<<(QDataStream &stream, const QQmlProfilerEvent &event);
342};
343
344bool operator==(const QQmlProfilerEvent &event1, const QQmlProfilerEvent &event2);
345bool operator!=(const QQmlProfilerEvent &event1, const QQmlProfilerEvent &event2);
346
347QDataStream &operator>>(QDataStream &stream, QQmlProfilerEvent &event);
348QDataStream &operator<<(QDataStream &stream, const QQmlProfilerEvent &event);
349
350Q_DECLARE_TYPEINFO(QQmlProfilerEvent, Q_MOVABLE_TYPE);
351
352QT_END_NAMESPACE
353
354Q_DECLARE_METATYPE(QQmlProfilerEvent)
355
356#endif // QQMLPROFILEREVENT_P_H
357

source code of qtdeclarative/src/qmldebug/qqmlprofilerevent_p.h