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#include "qqmlprofilerevent_p.h"
41#include <QtCore/qdatastream.h>
42
43QT_BEGIN_NAMESPACE
44
45bool operator==(const QQmlProfilerEvent &event1, const QQmlProfilerEvent &event2)
46{
47 if (event1.timestamp() != event2.timestamp() || event1.typeIndex() != event2.typeIndex())
48 return false;
49
50 // This is not particularly efficient, but we also don't need to do this very often.
51 return event1.numbers<QVarLengthArray<qint64>>() == event2.numbers<QVarLengthArray<qint64>>();
52}
53
54bool operator!=(const QQmlProfilerEvent &event1, const QQmlProfilerEvent &event2)
55{
56 return !(event1 == event2);
57}
58
59enum SerializationType {
60 OneByte = 0,
61 TwoByte = 1,
62 FourByte = 2,
63 EightByte = 3,
64 TypeMask = 0x3
65};
66
67enum SerializationTypeOffset {
68 TimestampOffset = 0,
69 TypeIndexOffset = 2,
70 DataLengthOffset = 4,
71 DataOffset = 6
72};
73
74template<typename Number>
75static inline void readNumbers(QDataStream &stream, Number *data, quint16 length)
76{
77 for (quint16 i = 0; i != length; ++i)
78 stream >> data[i];
79}
80
81template<typename Number>
82static inline Number readNumber(QDataStream &stream, qint8 type)
83{
84 switch (type) {
85 case OneByte: {
86 qint8 value;
87 stream >> value;
88 return static_cast<Number>(value);
89 }
90 case TwoByte: {
91 qint16 value;
92 stream >> value;
93 return static_cast<Number>(value);
94 }
95 case FourByte: {
96 qint32 value;
97 stream >> value;
98 return static_cast<Number>(value);
99 }
100 case EightByte: {
101 qint64 value;
102 stream >> value;
103 return static_cast<Number>(value);
104 }
105 default:
106 Q_UNREACHABLE();
107 return 0;
108 }
109}
110
111QDataStream &operator>>(QDataStream &stream, QQmlProfilerEvent &event)
112{
113 qint8 type;
114 stream >> type;
115
116 event.m_timestamp = readNumber<qint64>(stream, type: (type >> TimestampOffset) & TypeMask);
117 event.m_typeIndex = readNumber<qint32>(stream, type: (type >> TypeIndexOffset) & TypeMask);
118 event.m_dataLength = readNumber<quint16>(stream, type: (type >> DataLengthOffset) & TypeMask);
119
120 uint bytesPerNumber = 1 << ((type >> DataOffset) & TypeMask);
121
122 if (event.m_dataLength * bytesPerNumber > sizeof(event.m_data)) {
123 event.m_dataType = static_cast<QQmlProfilerEvent::Type>((bytesPerNumber * 8)
124 | QQmlProfilerEvent::External);
125 event.m_data.external = malloc(size: event.m_dataLength * bytesPerNumber);
126 } else {
127 event.m_dataType = static_cast<QQmlProfilerEvent::Type>(bytesPerNumber * 8);
128 }
129
130 switch (event.m_dataType) {
131 case QQmlProfilerEvent::Inline8Bit:
132 readNumbers<qint8>(stream, data: event.m_data.internal8bit, length: event.m_dataLength);
133 break;
134 case QQmlProfilerEvent::External8Bit:
135 readNumbers<qint8>(stream, data: static_cast<qint8 *>(event.m_data.external),
136 length: event.m_dataLength);
137 break;
138 case QQmlProfilerEvent::Inline16Bit:
139 readNumbers<qint16>(stream, data: event.m_data.internal16bit, length: event.m_dataLength);
140 break;
141 case QQmlProfilerEvent::External16Bit:
142 readNumbers<qint16>(stream, data: static_cast<qint16 *>(event.m_data.external),
143 length: event.m_dataLength);
144 break;
145 case QQmlProfilerEvent::Inline32Bit:
146 readNumbers<qint32>(stream, data: event.m_data.internal32bit, length: event.m_dataLength);
147 break;
148 case QQmlProfilerEvent::External32Bit:
149 readNumbers<qint32>(stream, data: static_cast<qint32 *>(event.m_data.external),
150 length: event.m_dataLength);
151 break;
152 case QQmlProfilerEvent::Inline64Bit:
153 readNumbers<qint64>(stream, data: event.m_data.internal64bit, length: event.m_dataLength);
154 break;
155 case QQmlProfilerEvent::External64Bit:
156 readNumbers<qint64>(stream, data: static_cast<qint64 *>(event.m_data.external),
157 length: event.m_dataLength);
158 break;
159 default:
160 Q_UNREACHABLE();
161 break;
162 }
163
164 return stream;
165}
166
167static inline qint8 minimumType(const QQmlProfilerEvent &event, quint16 length,
168 quint16 origBitsPerNumber)
169{
170 qint8 type = OneByte;
171 bool ok = true;
172 for (quint16 i = 0; i < length;) {
173 if ((1 << type) == origBitsPerNumber / 8)
174 return type;
175 switch (type) {
176 case OneByte:
177 ok = (event.number<qint8>(i) == event.number<qint64>(i));
178 break;
179 case TwoByte:
180 ok = (event.number<qint16>(i) == event.number<qint64>(i));
181 break;
182 case FourByte:
183 ok = (event.number<qint32>(i) == event.number<qint64>(i));
184 break;
185 default:
186 // EightByte isn't possible, as (1 << type) == origBitsPerNumber / 8 then.
187 Q_UNREACHABLE();
188 break;
189 }
190
191 if (ok)
192 ++i;
193 else
194 ++type;
195 }
196 return type;
197}
198
199template<typename Number>
200static inline qint8 minimumType(Number number)
201{
202 if (static_cast<qint8>(number) == number)
203 return OneByte;
204 if (static_cast<qint16>(number) == number)
205 return TwoByte;
206 if (static_cast<qint32>(number) == number)
207 return FourByte;
208 return EightByte;
209}
210
211template<typename Number>
212static inline void writeNumbers(QDataStream &stream, const QQmlProfilerEvent &event, quint16 length)
213{
214 for (quint16 i = 0; i != length; ++i)
215 stream << event.number<Number>(i);
216}
217
218template<typename Number>
219static inline void writeNumber(QDataStream &stream, Number number, qint8 type)
220{
221 switch (type) {
222 case OneByte:
223 stream << static_cast<qint8>(number);
224 break;
225 case TwoByte:
226 stream << static_cast<qint16>(number);
227 break;
228 case FourByte:
229 stream << static_cast<qint32>(number);
230 break;
231 case EightByte:
232 stream << static_cast<qint64>(number);
233 break;
234 default:
235 Q_UNREACHABLE();
236 break;
237 }
238}
239
240QDataStream &operator<<(QDataStream &stream, const QQmlProfilerEvent &event)
241{
242 qint8 type = minimumType(number: event.m_timestamp); // << TimestampOffset;
243 type |= minimumType(number: event.m_typeIndex) << TypeIndexOffset;
244 type |= minimumType(number: event.m_dataLength) << DataLengthOffset;
245 type |= minimumType(event, length: event.m_dataLength, origBitsPerNumber: event.m_dataType) << DataOffset;
246 stream << type;
247
248 writeNumber(stream, number: event.m_timestamp, type: (type >> TimestampOffset) & TypeMask);
249 writeNumber(stream, number: event.m_typeIndex, type: (type >> TypeIndexOffset) & TypeMask);
250 writeNumber(stream, number: event.m_dataLength, type: (type >> DataLengthOffset) & TypeMask);
251
252 switch ((type >> DataOffset) & TypeMask) {
253 case OneByte:
254 writeNumbers<qint8>(stream, event, length: event.m_dataLength);
255 break;
256 case TwoByte:
257 writeNumbers<qint16>(stream, event, length: event.m_dataLength);
258 break;
259 case FourByte:
260 writeNumbers<qint32>(stream, event, length: event.m_dataLength);
261 break;
262 case EightByte:
263 writeNumbers<qint64>(stream, event, length: event.m_dataLength);
264 break;
265 default:
266 Q_UNREACHABLE();
267 break;
268 }
269
270 return stream;
271}
272
273QT_END_NAMESPACE
274

source code of qtdeclarative/src/qmldebug/qqmlprofilerevent.cpp