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
40#include "qv4string_p.h"
41#include "qv4value_p.h"
42#include "qv4identifiertable_p.h"
43#include "qv4runtime_p.h"
44#include "qv4objectproto_p.h"
45#include "qv4stringobject_p.h"
46#include <QtCore/QHash>
47#include <QtCore/private/qnumeric_p.h>
48
49using namespace QV4;
50
51void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
52{
53 StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
54 Heap::StringOrSymbol *id = s->identifier.asStringOrSymbol();
55 if (id)
56 id->mark(markStack);
57}
58
59void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
60{
61 StringOrSymbol::markObjects(that, markStack);
62 String *s = static_cast<String *>(that);
63 if (s->subtype < StringType_Complex)
64 return;
65
66 ComplexString *cs = static_cast<ComplexString *>(s);
67 if (cs->subtype == StringType_AddedString) {
68 cs->left->mark(markStack);
69 cs->right->mark(markStack);
70 } else {
71 Q_ASSERT(cs->subtype == StringType_SubString);
72 cs->left->mark(markStack);
73 }
74}
75
76DEFINE_MANAGED_VTABLE(StringOrSymbol);
77DEFINE_MANAGED_VTABLE(String);
78
79
80bool String::virtualIsEqualTo(Managed *t, Managed *o)
81{
82 if (t == o)
83 return true;
84
85 if (!o->vtable()->isString)
86 return false;
87
88 return static_cast<String *>(t)->isEqualTo(other: static_cast<String *>(o));
89}
90
91
92void Heap::String::init(const QString &t)
93{
94 Base::init();
95
96 subtype = String::StringType_Unknown;
97
98 text = const_cast<QString &>(t).data_ptr();
99 text->ref.ref();
100}
101
102void Heap::ComplexString::init(String *l, String *r)
103{
104 Base::init();
105
106 subtype = String::StringType_AddedString;
107
108 left = l;
109 right = r;
110 len = left->length() + right->length();
111 if (left->subtype >= StringType_Complex)
112 largestSubLength = static_cast<ComplexString *>(left)->largestSubLength;
113 else
114 largestSubLength = left->length();
115 if (right->subtype >= StringType_Complex)
116 largestSubLength = qMax(a: largestSubLength, b: static_cast<ComplexString *>(right)->largestSubLength);
117 else
118 largestSubLength = qMax(a: largestSubLength, b: right->length());
119
120 // make sure we don't get excessive depth in our strings
121 if (len > 256 && len >= 2*largestSubLength)
122 simplifyString();
123}
124
125void Heap::ComplexString::init(Heap::String *ref, int from, int len)
126{
127 Q_ASSERT(ref->length() >= from + len);
128 Base::init();
129
130 subtype = String::StringType_SubString;
131
132 left = ref;
133 this->from = from;
134 this->len = len;
135}
136
137void Heap::StringOrSymbol::destroy()
138{
139 if (text) {
140 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(delta: qptrdiff(-text->size) * (int)sizeof(QChar));
141 if (!text->ref.deref())
142 QStringData::deallocate(data: text);
143 }
144 Base::destroy();
145}
146
147uint String::toUInt(bool *ok) const
148{
149 *ok = true;
150
151 if (subtype() >= Heap::String::StringType_Unknown)
152 d()->createHashValue();
153 if (subtype() == Heap::String::StringType_ArrayIndex)
154 return d()->stringHash;
155
156 // required for UINT_MAX or numbers starting with a leading 0
157 double d = RuntimeHelpers::stringToNumber(s: toQString());
158 uint l = (uint)d;
159 if (d == l)
160 return l;
161 *ok = false;
162 return UINT_MAX;
163}
164
165void String::createPropertyKeyImpl() const
166{
167 if (!d()->text)
168 d()->simplifyString();
169 Q_ASSERT(d()->text);
170 engine()->identifierTable->asPropertyKey(str: this);
171}
172
173void Heap::String::simplifyString() const
174{
175 Q_ASSERT(!text);
176
177 int l = length();
178 QString result(l, Qt::Uninitialized);
179 QChar *ch = const_cast<QChar *>(result.constData());
180 append(data: this, ch);
181 text = result.data_ptr();
182 text->ref.ref();
183 const ComplexString *cs = static_cast<const ComplexString *>(this);
184 identifier = PropertyKey::invalid();
185 cs->left = cs->right = nullptr;
186
187 internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(delta: qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
188 subtype = StringType_Unknown;
189}
190
191bool Heap::String::startsWithUpper() const
192{
193 if (subtype == StringType_AddedString)
194 return static_cast<const Heap::ComplexString *>(this)->left->startsWithUpper();
195
196 const Heap::String *str = this;
197 int offset = 0;
198 if (subtype == StringType_SubString) {
199 const ComplexString *cs = static_cast<const Heap::ComplexString *>(this);
200 if (!cs->len)
201 return false;
202 // simplification here is not ideal, but hopefully not a common case.
203 if (cs->left->subtype >= Heap::String::StringType_Complex)
204 cs->left->simplifyString();
205 str = cs->left;
206 offset = cs->from;
207 }
208 Q_ASSERT(str->subtype < Heap::String::StringType_Complex);
209 return str->text->size > offset && QChar::isUpper(ucs4: str->text->data()[offset]);
210}
211
212void Heap::String::append(const String *data, QChar *ch)
213{
214 std::vector<const String *> worklist;
215 worklist.reserve(n: 32);
216 worklist.push_back(x: data);
217
218 while (!worklist.empty()) {
219 const String *item = worklist.back();
220 worklist.pop_back();
221
222 if (item->subtype == StringType_AddedString) {
223 const ComplexString *cs = static_cast<const ComplexString *>(item);
224 worklist.push_back(x: cs->right);
225 worklist.push_back(x: cs->left);
226 } else if (item->subtype == StringType_SubString) {
227 const ComplexString *cs = static_cast<const ComplexString *>(item);
228 memcpy(dest: ch, src: cs->left->toQString().constData() + cs->from, n: cs->len*sizeof(QChar));
229 ch += cs->len;
230 } else {
231 memcpy(dest: static_cast<void *>(ch), src: static_cast<const void *>(item->text->data()), n: item->text->size * sizeof(QChar));
232 ch += item->text->size;
233 }
234 }
235}
236
237void Heap::StringOrSymbol::createHashValue() const
238{
239 if (!text) {
240 Q_ASSERT(internalClass->vtable->isString);
241 static_cast<const Heap::String *>(this)->simplifyString();
242 }
243 Q_ASSERT(text);
244 const QChar *ch = reinterpret_cast<const QChar *>(text->data());
245 const QChar *end = ch + text->size;
246 stringHash = QV4::String::calculateHashValue(ch, end, subtype: &subtype);
247}
248
249qint64 String::virtualGetLength(const Managed *m)
250{
251 return static_cast<const String *>(m)->d()->length();
252}
253

source code of qtdeclarative/src/qml/jsruntime/qv4string.cpp