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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | namespace QV4 { |
13 | |
14 | IdentifierHash::IdentifierHash(ExecutionEngine *engine) |
15 | { |
16 | d = new IdentifierHashData(engine->identifierTable, 3); |
17 | Q_ASSERT(!isEmpty()); |
18 | } |
19 | |
20 | void 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 | |
30 | inline |
31 | IdentifierHashEntry *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 | |
70 | inline |
71 | const 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 | |
88 | inline |
89 | const 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 | |
98 | inline |
99 | const 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 | |
109 | inline |
110 | const PropertyKey IdentifierHash::toIdentifier(const QString &str) const |
111 | { |
112 | Q_ASSERT(d); |
113 | return d->identifierTable->asPropertyKey(s: str, conversionBehavior: IdentifierTable::ForceConversionToId); |
114 | } |
115 | |
116 | inline |
117 | const PropertyKey IdentifierHash::toIdentifier(Heap::String *str) const |
118 | { |
119 | Q_ASSERT(d); |
120 | return d->identifierTable->asPropertyKey(str); |
121 | } |
122 | |
123 | QString 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 | |
135 | QV4::IdentifierHash::IdentifierHash(const IdentifierHash &other) |
136 | { |
137 | d = other.d; |
138 | if (d) |
139 | d->refCount.ref(); |
140 | } |
141 | |
142 | QV4::IdentifierHash::~IdentifierHash() |
143 | { |
144 | if (d && !d->refCount.deref()) |
145 | delete d; |
146 | } |
147 | |
148 | IdentifierHash &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 | |
158 | int QV4::IdentifierHash::count() const |
159 | { |
160 | return d ? d->size : 0; |
161 | } |
162 | |
163 | void QV4::IdentifierHash::add(const QString &str, int value) |
164 | { |
165 | IdentifierHashEntry *e = addEntry(identifier: toIdentifier(str)); |
166 | e->value = value; |
167 | } |
168 | |
169 | void QV4::IdentifierHash::add(Heap::String *str, int value) |
170 | { |
171 | IdentifierHashEntry *e = addEntry(identifier: toIdentifier(str)); |
172 | e->value = value; |
173 | } |
174 | |
175 | int QV4::IdentifierHash::value(const QString &str) const |
176 | { |
177 | const IdentifierHashEntry *e = lookup(str); |
178 | return e ? e->value : -1; |
179 | } |
180 | |
181 | int QV4::IdentifierHash::value(String *str) const |
182 | { |
183 | const IdentifierHashEntry *e = lookup(str); |
184 | return e ? e->value : -1; |
185 | } |
186 | |
187 | |
188 | } |
189 | |
190 | QT_END_NAMESPACE |
191 |