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

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