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 <private/qv4identifierhash_p.h>
5#include <private/qv4identifiertable_p.h>
6#include <private/qv4string_p.h>
7#include <private/qv4identifierhashdata_p.h>
8#include <private/qprimefornumbits_p.h>
9
10QT_BEGIN_NAMESPACE
11
12namespace QV4 {
13
14IdentifierHash::IdentifierHash(ExecutionEngine *engine)
15{
16 d = new IdentifierHashData(engine->identifierTable, 3);
17 Q_ASSERT(!isEmpty());
18}
19
20void IdentifierHash::detach()
21{
22 if (!d || d->refCount.loadAcquire() == 1)
23 return;
24 IdentifierHashData *newData = new IdentifierHashData(d);
25 if (d && !d->refCount.deref())
26 delete d;
27 d = newData;
28}
29
30inline
31IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
32{
33 Q_ASSERT(identifier.isStringOrSymbol());
34
35 // fill up to max 50%
36 bool grow = (d->alloc <= d->size*2);
37
38 if (grow) {
39 ++d->numBits;
40 int newAlloc = qPrimeForNumBits(numBits: d->numBits);
41 IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(size: newAlloc * sizeof(IdentifierHashEntry));
42 memset(s: newEntries, c: 0, n: newAlloc*sizeof(IdentifierHashEntry));
43 for (int i = 0; i < d->alloc; ++i) {
44 const IdentifierHashEntry &e = d->entries[i];
45 if (!e.identifier.isValid())
46 continue;
47 uint idx = e.identifier.id() % newAlloc;
48 while (newEntries[idx].identifier.isValid()) {
49 ++idx;
50 idx %= newAlloc;
51 }
52 newEntries[idx] = e;
53 }
54 free(ptr: d->entries);
55 d->entries = newEntries;
56 d->alloc = newAlloc;
57 }
58
59 uint idx = identifier.id() % d->alloc;
60 while (d->entries[idx].identifier.isValid()) {
61 Q_ASSERT(d->entries[idx].identifier != identifier);
62 ++idx;
63 idx %= d->alloc;
64 }
65 d->entries[idx].identifier = identifier;
66 ++d->size;
67 return d->entries + idx;
68}
69
70inline
71const IdentifierHashEntry *IdentifierHash::lookup(PropertyKey identifier) const
72{
73 if (!d || !identifier.isStringOrSymbol())
74 return nullptr;
75 Q_ASSERT(d->entries);
76
77 uint idx = identifier.id() % d->alloc;
78 while (1) {
79 if (!d->entries[idx].identifier.isValid())
80 return nullptr;
81 if (d->entries[idx].identifier == identifier)
82 return d->entries + idx;
83 ++idx;
84 idx %= d->alloc;
85 }
86}
87
88inline
89const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const
90{
91 if (!d)
92 return nullptr;
93
94 PropertyKey id = d->identifierTable->asPropertyKey(s: str, conversionBehavior: IdentifierTable::ForceConversionToId);
95 return lookup(identifier: id);
96}
97
98inline
99const IdentifierHashEntry *IdentifierHash::lookup(String *str) const
100{
101 if (!d)
102 return nullptr;
103 PropertyKey id = d->identifierTable->asPropertyKey(str);
104 if (id.isValid())
105 return lookup(identifier: id);
106 return lookup(str: str->toQString());
107}
108
109inline
110const PropertyKey IdentifierHash::toIdentifier(const QString &str) const
111{
112 Q_ASSERT(d);
113 return d->identifierTable->asPropertyKey(s: str, conversionBehavior: IdentifierTable::ForceConversionToId);
114}
115
116inline
117const PropertyKey IdentifierHash::toIdentifier(Heap::String *str) const
118{
119 Q_ASSERT(d);
120 return d->identifierTable->asPropertyKey(str);
121}
122
123QString QV4::IdentifierHash::findId(int value) const
124{
125 IdentifierHashEntry *e = d->entries;
126 IdentifierHashEntry *end = e + d->alloc;
127 while (e < end) {
128 if (e->identifier.isValid() && e->value == value)
129 return e->identifier.toQString();
130 ++e;
131 }
132 return QString();
133}
134
135QV4::IdentifierHash::IdentifierHash(const IdentifierHash &other)
136{
137 d = other.d;
138 if (d)
139 d->refCount.ref();
140}
141
142QV4::IdentifierHash::~IdentifierHash()
143{
144 if (d && !d->refCount.deref())
145 delete d;
146}
147
148IdentifierHash &QV4::IdentifierHash::operator=(const IdentifierHash &other)
149{
150 if (other.d)
151 other.d->refCount.ref();
152 if (d && !d->refCount.deref())
153 delete d;
154 d = other.d;
155 return *this;
156}
157
158int QV4::IdentifierHash::count() const
159{
160 return d ? d->size : 0;
161}
162
163void QV4::IdentifierHash::add(const QString &str, int value)
164{
165 IdentifierHashEntry *e = addEntry(identifier: toIdentifier(str));
166 e->value = value;
167}
168
169void QV4::IdentifierHash::add(Heap::String *str, int value)
170{
171 IdentifierHashEntry *e = addEntry(identifier: toIdentifier(str));
172 e->value = value;
173}
174
175int QV4::IdentifierHash::value(const QString &str) const
176{
177 const IdentifierHashEntry *e = lookup(str);
178 return e ? e->value : -1;
179}
180
181int QV4::IdentifierHash::value(String *str) const
182{
183 const IdentifierHashEntry *e = lookup(str);
184 return e ? e->value : -1;
185}
186
187
188}
189
190QT_END_NAMESPACE
191

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