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

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