1/****************************************************************************
2**
3** Copyright (C) 2016 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#ifndef QV4STRING_H
40#define QV4STRING_H
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include <QtCore/qstring.h>
54#include "qv4managed_p.h"
55#include <QtCore/private/qnumeric_p.h>
56#include "qv4enginebase_p.h"
57#include <private/qv4stringtoarrayindex_p.h>
58
59QT_BEGIN_NAMESPACE
60
61namespace QV4 {
62
63struct ExecutionEngine;
64struct PropertyKey;
65
66namespace Heap {
67
68struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
69{
70 enum StringType {
71 StringType_Symbol,
72 StringType_Regular,
73 StringType_ArrayIndex,
74 StringType_Unknown,
75 StringType_AddedString,
76 StringType_SubString,
77 StringType_Complex = StringType_AddedString
78 };
79
80 mutable QStringData *text;
81 mutable PropertyKey identifier;
82 mutable uint subtype;
83 mutable uint stringHash;
84
85 static void markObjects(Heap::Base *that, MarkStack *markStack);
86 void destroy();
87
88 inline QString toQString() const {
89 if (!text)
90 return QString();
91 QStringDataPtr ptr = { text };
92 text->ref.ref();
93 return QString(ptr);
94 }
95 void createHashValue() const;
96 inline unsigned hashValue() const {
97 if (subtype >= StringType_Unknown)
98 createHashValue();
99 Q_ASSERT(subtype < StringType_Complex);
100
101 return stringHash;
102 }
103};
104
105struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
106 static void markObjects(Heap::Base *that, MarkStack *markStack);
107
108 const VTable *vtable() const {
109 return internalClass->vtable;
110 }
111
112 void init(const QString &text);
113 void simplifyString() const;
114 int length() const;
115 std::size_t retainedTextSize() const {
116 return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar));
117 }
118 inline QString toQString() const {
119 if (subtype >= StringType_Complex)
120 simplifyString();
121 QStringDataPtr ptr = { text };
122 text->ref.ref();
123 return QString(ptr);
124 }
125 inline bool isEqualTo(const String *other) const {
126 if (this == other)
127 return true;
128 if (hashValue() != other->hashValue())
129 return false;
130 Q_ASSERT(subtype < StringType_Complex);
131 if (identifier.isValid() && identifier == other->identifier)
132 return true;
133 if (subtype == Heap::String::StringType_ArrayIndex && other->subtype == Heap::String::StringType_ArrayIndex)
134 return true;
135
136 return toQString() == other->toQString();
137 }
138
139 bool startsWithUpper() const;
140
141private:
142 static void append(const String *data, QChar *ch);
143};
144Q_STATIC_ASSERT(std::is_trivial< String >::value);
145
146struct ComplexString : String {
147 void init(String *l, String *n);
148 void init(String *ref, int from, int len);
149 mutable String *left;
150 mutable String *right;
151 union {
152 mutable int largestSubLength;
153 int from;
154 };
155 int len;
156};
157Q_STATIC_ASSERT(std::is_trivial< ComplexString >::value);
158
159inline
160int String::length() const {
161 return text ? text->size : static_cast<const ComplexString *>(this)->len;
162}
163
164}
165
166struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
167 V4_MANAGED(StringOrSymbol, Managed)
168 V4_NEEDS_DESTROY
169 enum {
170 IsStringOrSymbol = true
171 };
172
173private:
174 inline void createPropertyKey() const;
175public:
176 PropertyKey propertyKey() const { Q_ASSERT(d()->identifier.isValid()); return d()->identifier; }
177 PropertyKey toPropertyKey() const;
178
179
180 inline QString toQString() const {
181 return d()->toQString();
182 }
183};
184
185struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
186 V4_MANAGED(String, StringOrSymbol)
187 Q_MANAGED_TYPE(String)
188 V4_INTERNALCLASS(String)
189 enum {
190 IsString = true
191 };
192
193 uchar subtype() const { return d()->subtype; }
194 void setSubtype(uchar subtype) const { d()->subtype = subtype; }
195
196 bool equals(String *other) const {
197 return d()->isEqualTo(other->d());
198 }
199 inline bool isEqualTo(const String *other) const {
200 return d()->isEqualTo(other->d());
201 }
202
203 inline bool lessThan(const String *other) {
204 return toQString() < other->toQString();
205 }
206
207 inline QString toQString() const {
208 return d()->toQString();
209 }
210
211 inline unsigned hashValue() const {
212 return d()->hashValue();
213 }
214 uint toUInt(bool *ok) const;
215
216 // slow path
217 Q_NEVER_INLINE void createPropertyKeyImpl() const;
218
219 static uint createHashValue(const QChar *ch, int length, uint *subtype)
220 {
221 const QChar *end = ch + length;
222 return calculateHashValue(ch, end, subtype);
223 }
224
225 static uint createHashValue(const char *ch, int length, uint *subtype)
226 {
227 const char *end = ch + length;
228 return calculateHashValue(ch, end, subtype);
229 }
230
231 bool startsWithUpper() const { return d()->startsWithUpper(); }
232
233protected:
234 static bool virtualIsEqualTo(Managed *that, Managed *o);
235 static qint64 virtualGetLength(const Managed *m);
236
237public:
238 template <typename T>
239 static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
240 {
241 // array indices get their number as hash value
242 uint h = stringToArrayIndex(ch, end);
243 if (h != UINT_MAX) {
244 if (subtype)
245 *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
246 return h;
247 }
248
249 while (ch < end) {
250 h = 31 * h + charToUInt(ch);
251 ++ch;
252 }
253
254 if (subtype)
255 *subtype = (charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
256 return h;
257 }
258};
259
260struct ComplexString : String {
261 typedef QV4::Heap::ComplexString Data;
262 QV4::Heap::ComplexString *d_unchecked() const { return static_cast<QV4::Heap::ComplexString *>(m()); }
263 QV4::Heap::ComplexString *d() const {
264 QV4::Heap::ComplexString *dptr = d_unchecked();
265 dptr->_checkIsInitialized();
266 return dptr;
267 }
268};
269
270inline
271void StringOrSymbol::createPropertyKey() const {
272 Q_ASSERT(!d()->identifier.isValid());
273 Q_ASSERT(isString());
274 static_cast<const String *>(this)->createPropertyKeyImpl();
275}
276
277inline PropertyKey StringOrSymbol::toPropertyKey() const {
278 if (!d()->identifier.isValid())
279 createPropertyKey();
280 return d()->identifier;
281}
282
283template<>
284inline const StringOrSymbol *Value::as() const {
285 return isManaged() && m()->internalClass->vtable->isStringOrSymbol ? static_cast<const String *>(this) : nullptr;
286}
287
288template<>
289inline const String *Value::as() const {
290 return isManaged() && m()->internalClass->vtable->isString ? static_cast<const String *>(this) : nullptr;
291}
292
293template<>
294inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
295{
296 return v.toString(e)->asReturnedValue();
297}
298
299}
300
301QT_END_NAMESPACE
302
303#endif
304