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 
59 QT_BEGIN_NAMESPACE
60 
61 namespace QV4 {
62 
63 struct ExecutionEngine;
64 struct PropertyKey;
65 
66 namespace Heap {
67 
68 struct 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 
toQStringStringOrSymbol88     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;
hashValueStringOrSymbol96     inline unsigned hashValue() const {
97         if (subtype >= StringType_Unknown)
98             createHashValue();
99         Q_ASSERT(subtype < StringType_Complex);
100 
101         return stringHash;
102     }
103 };
104 
105 struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
106     static void markObjects(Heap::Base *that, MarkStack *markStack);
107 
vtableString108     const VTable *vtable() const {
109         return internalClass->vtable;
110     }
111 
112     void init(const QString &text);
113     void simplifyString() const;
114     int length() const;
retainedTextSizeString115     std::size_t retainedTextSize() const {
116         return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar));
117     }
toQStringString118     inline QString toQString() const {
119         if (subtype >= StringType_Complex)
120             simplifyString();
121         QStringDataPtr ptr = { text };
122         text->ref.ref();
123         return QString(ptr);
124     }
isEqualToString125     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 
141 private:
142     static void append(const String *data, QChar *ch);
143 };
144 Q_STATIC_ASSERT(std::is_trivial< String >::value);
145 
146 struct 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 };
157 Q_STATIC_ASSERT(std::is_trivial< ComplexString >::value);
158 
159 inline
length()160 int String::length() const {
161     return text ? text->size : static_cast<const ComplexString *>(this)->len;
162 }
163 
164 }
165 
166 struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
167     V4_MANAGED(StringOrSymbol, Managed)
168     V4_NEEDS_DESTROY
169     enum {
170         IsStringOrSymbol = true
171     };
172 
173 private:
174     inline void createPropertyKey() const;
175 public:
propertyKeyStringOrSymbol176     PropertyKey propertyKey() const { Q_ASSERT(d()->identifier.isValid()); return d()->identifier; }
177     PropertyKey toPropertyKey() const;
178 
179 
toQStringStringOrSymbol180     inline QString toQString() const {
181         return d()->toQString();
182     }
183 };
184 
185 struct 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 
subtypeString193     uchar subtype() const { return d()->subtype; }
setSubtypeString194     void setSubtype(uchar subtype) const { d()->subtype = subtype; }
195 
equalsString196     bool equals(String *other) const {
197         return d()->isEqualTo(other->d());
198     }
isEqualToString199     inline bool isEqualTo(const String *other) const {
200         return d()->isEqualTo(other->d());
201     }
202 
lessThanString203     inline bool lessThan(const String *other) {
204         return toQString() < other->toQString();
205     }
206 
toQStringString207     inline QString toQString() const {
208         return d()->toQString();
209     }
210 
hashValueString211     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 
createHashValueString219     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 
createHashValueString225     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 
startsWithUpperString231     bool startsWithUpper() const { return d()->startsWithUpper(); }
232 
233 protected:
234     static bool virtualIsEqualTo(Managed *that, Managed *o);
235     static qint64 virtualGetLength(const Managed *m);
236 
237 public:
238     template <typename T>
calculateHashValueString239     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 
260 struct ComplexString : String {
261     typedef QV4::Heap::ComplexString Data;
d_uncheckedComplexString262     QV4::Heap::ComplexString *d_unchecked() const { return static_cast<QV4::Heap::ComplexString *>(m()); }
dComplexString263     QV4::Heap::ComplexString *d() const {
264         QV4::Heap::ComplexString *dptr = d_unchecked();
265         dptr->_checkIsInitialized();
266         return dptr;
267     }
268 };
269 
270 inline
createPropertyKey()271 void StringOrSymbol::createPropertyKey() const {
272     Q_ASSERT(!d()->identifier.isValid());
273     Q_ASSERT(isString());
274     static_cast<const String *>(this)->createPropertyKeyImpl();
275 }
276 
toPropertyKey()277 inline PropertyKey StringOrSymbol::toPropertyKey() const {
278     if (!d()->identifier.isValid())
279         createPropertyKey();
280     return d()->identifier;
281 }
282 
283 template<>
as()284 inline const StringOrSymbol *Value::as() const {
285     return isManaged() && m()->internalClass->vtable->isStringOrSymbol ? static_cast<const String *>(this) : nullptr;
286 }
287 
288 template<>
as()289 inline const String *Value::as() const {
290     return isManaged() && m()->internalClass->vtable->isString ? static_cast<const String *>(this) : nullptr;
291 }
292 
293 template<>
294 inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
295 {
296     return v.toString(e)->asReturnedValue();
297 }
298 
299 }
300 
301 QT_END_NAMESPACE
302 
303 #endif
304