blob: 223f4a47691748c447fb5228c0795a6e79ab76ed [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qv4string_p.h"
#include "qv4value_p.h"
#include "qv4identifiertable_p.h"
#include "qv4runtime_p.h"
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
#include <QtCore/QHash>
#include <QtCore/private/qnumeric_p.h>
using namespace QV4;
void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
{
StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
Heap::StringOrSymbol *id = s->identifier.asStringOrSymbol();
if (id)
id->mark(markStack);
}
void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
{
StringOrSymbol::markObjects(that, markStack);
String *s = static_cast<String *>(that);
if (s->subtype < StringType_Complex)
return;
ComplexString *cs = static_cast<ComplexString *>(s);
if (cs->subtype == StringType_AddedString) {
cs->left->mark(markStack);
cs->right->mark(markStack);
} else {
Q_ASSERT(cs->subtype == StringType_SubString);
cs->left->mark(markStack);
}
}
DEFINE_MANAGED_VTABLE(StringOrSymbol);
DEFINE_MANAGED_VTABLE(String);
bool String::virtualIsEqualTo(Managed *t, Managed *o)
{
if (t == o)
return true;
if (!o->vtable()->isString)
return false;
return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o));
}
void Heap::String::init(const QString &t)
{
Base::init();
subtype = String::StringType_Unknown;
text = const_cast<QString &>(t).data_ptr();
text->ref.ref();
}
void Heap::ComplexString::init(String *l, String *r)
{
Base::init();
subtype = String::StringType_AddedString;
left = l;
right = r;
len = left->length() + right->length();
if (left->subtype >= StringType_Complex)
largestSubLength = static_cast<ComplexString *>(left)->largestSubLength;
else
largestSubLength = left->length();
if (right->subtype >= StringType_Complex)
largestSubLength = qMax(largestSubLength, static_cast<ComplexString *>(right)->largestSubLength);
else
largestSubLength = qMax(largestSubLength, right->length());
// make sure we don't get excessive depth in our strings
if (len > 256 && len >= 2*largestSubLength)
simplifyString();
}
void Heap::ComplexString::init(Heap::String *ref, int from, int len)
{
Q_ASSERT(ref->length() >= from + len);
Base::init();
subtype = String::StringType_SubString;
left = ref;
this->from = from;
this->len = len;
}
void Heap::StringOrSymbol::destroy()
{
if (text) {
internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
if (!text->ref.deref())
QStringData::deallocate(text);
}
Base::destroy();
}
uint String::toUInt(bool *ok) const
{
*ok = true;
if (subtype() >= Heap::String::StringType_Unknown)
d()->createHashValue();
if (subtype() == Heap::String::StringType_ArrayIndex)
return d()->stringHash;
// required for UINT_MAX or numbers starting with a leading 0
double d = RuntimeHelpers::stringToNumber(toQString());
uint l = (uint)d;
if (d == l)
return l;
*ok = false;
return UINT_MAX;
}
void String::createPropertyKeyImpl() const
{
if (!d()->text)
d()->simplifyString();
Q_ASSERT(d()->text);
engine()->identifierTable->asPropertyKey(this);
}
void Heap::String::simplifyString() const
{
Q_ASSERT(!text);
int l = length();
QString result(l, Qt::Uninitialized);
QChar *ch = const_cast<QChar *>(result.constData());
append(this, ch);
text = result.data_ptr();
text->ref.ref();
const ComplexString *cs = static_cast<const ComplexString *>(this);
identifier = PropertyKey::invalid();
cs->left = cs->right = nullptr;
internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
subtype = StringType_Unknown;
}
bool Heap::String::startsWithUpper() const
{
if (subtype == StringType_AddedString)
return static_cast<const Heap::ComplexString *>(this)->left->startsWithUpper();
const Heap::String *str = this;
int offset = 0;
if (subtype == StringType_SubString) {
const ComplexString *cs = static_cast<const Heap::ComplexString *>(this);
if (!cs->len)
return false;
// simplification here is not ideal, but hopefully not a common case.
if (cs->left->subtype >= Heap::String::StringType_Complex)
cs->left->simplifyString();
str = cs->left;
offset = cs->from;
}
Q_ASSERT(str->subtype < Heap::String::StringType_Complex);
return str->text->size > offset && QChar::isUpper(str->text->data()[offset]);
}
void Heap::String::append(const String *data, QChar *ch)
{
std::vector<const String *> worklist;
worklist.reserve(32);
worklist.push_back(data);
while (!worklist.empty()) {
const String *item = worklist.back();
worklist.pop_back();
if (item->subtype == StringType_AddedString) {
const ComplexString *cs = static_cast<const ComplexString *>(item);
worklist.push_back(cs->right);
worklist.push_back(cs->left);
} else if (item->subtype == StringType_SubString) {
const ComplexString *cs = static_cast<const ComplexString *>(item);
memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar));
ch += cs->len;
} else {
memcpy(static_cast<void *>(ch), static_cast<const void *>(item->text->data()), item->text->size * sizeof(QChar));
ch += item->text->size;
}
}
}
void Heap::StringOrSymbol::createHashValue() const
{
if (!text) {
Q_ASSERT(internalClass->vtable->isString);
static_cast<const Heap::String *>(this)->simplifyString();
}
Q_ASSERT(text);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
}
qint64 String::virtualGetLength(const Managed *m)
{
return static_cast<const String *>(m)->d()->length();
}