Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4estable.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 Crimson AS <info@crimson.no>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#include "qv4estable_p.h"
6#include "qv4object_p.h"
7
8using namespace QV4;
9
10// The ES spec requires that Map/Set be implemented using a data structure that
11// is a little different from most; it requires nonlinear access, and must also
12// preserve the order of insertion of items in a deterministic way.
13//
14// This class implements those requirements, except for fast access: that
15// will be addressed in a followup patch.
16
17ESTable::ESTable()
18 : m_capacity(8)
19{
20 m_keys = (Value*)malloc(m_capacity * sizeof(Value));
21 m_values = (Value*)malloc(m_capacity * sizeof(Value));
22 memset(m_keys, 0, m_capacity);
23 memset(m_values, 0, m_capacity);
24}
25
26ESTable::~ESTable()
27{
28 free(m_keys);
29 free(m_values);
30 m_size = 0;
31 m_capacity = 0;
32 m_keys = nullptr;
33 m_values = nullptr;
34}
35
36void ESTable::markObjects(MarkStack *s, bool isWeakMap)
37{
38 for (uint i = 0; i < m_size; ++i) {
39 if (!isWeakMap)
40 m_keys[i].mark(s);
41 m_values[i].mark(s);
42 }
43}
44
45// Pretends that there's nothing in the table. Doesn't actually free memory, as
46// it will almost certainly be reused again anyway.
47void ESTable::clear()
48{
49 m_size = 0;
50
51 std::for_each(m_observers.begin(), m_observers.end(), [](ShiftObserver* ob){
52 Q_ASSERT(ob);
53 ob->pivot = ShiftObserver::OUT_OF_TABLE;
54 });
55}
56
57// Update the table to contain \a value for a given \a key. The key is
58// normalized, as required by the ES spec.
59void ESTable::set(const Value &key, const Value &value)
60{
61 for (uint i = 0; i < m_size; ++i) {
62 if (m_keys[i].sameValueZero(key)) {
63 m_values[i] = value;
64 return;
65 }
66 }
67
68 if (m_capacity == m_size) {
69 uint oldCap = m_capacity;
70 m_capacity *= 2;
71 m_keys = (Value*)realloc(m_keys, m_capacity * sizeof(Value));
72 m_values = (Value*)realloc(m_values, m_capacity * sizeof(Value));
73 memset(m_keys + oldCap, 0, m_capacity - oldCap);
74 memset(m_values + oldCap, 0, m_capacity - oldCap);
75 }
76
77 Value nk = key;
78 if (nk.isDouble()) {
79 if (nk.doubleValue() == 0 && std::signbit(nk.doubleValue()))
80 nk = Value::fromDouble(+0);
81 }
82
83 m_keys[m_size] = nk;
84 m_values[m_size] = value;
85
86 m_size++;
87}
88
89// Returns true if the table contains \a key, false otherwise.
90bool ESTable::has(const Value &key) const
91{
92 for (uint i = 0; i < m_size; ++i) {
93 if (m_keys[i].sameValueZero(key))
94 return true;
95 }
96
97 return false;
98}
99
100// Fetches the value for the given \a key, and if \a hasValue is passed in,
101// it is set depending on whether or not the given key was found.
102ReturnedValue ESTable::get(const Value &key, bool *hasValue) const
103{
104 for (uint i = 0; i < m_size; ++i) {
105 if (m_keys[i].sameValueZero(key)) {
106 if (hasValue)
107 *hasValue = true;
108 return m_values[i].asReturnedValue();
109 }
110 }
111
112 if (hasValue)
113 *hasValue = false;
114 return Encode::undefined();
115}
116
117// Removes the given \a key from the table
118bool ESTable::remove(const Value &key)
119{
120 for (uint index = 0; index < m_size; ++index) {
121 if (m_keys[index].sameValueZero(key)) {
122 // Remove the element at |index| by moving all elements to the right
123 // of |index| one place to the left.
124 size_t count = (m_size - (index + 1)) * sizeof(Value);
125 memmove(m_keys + index, m_keys + index + 1, count);
126 memmove(m_values + index, m_values + index + 1, count);
127 m_size--;
128
129 std::for_each(m_observers.begin(), m_observers.end(), [index](ShiftObserver* ob) {
130 Q_ASSERT(ob);
131 if (index <= ob->pivot && ob->pivot != ShiftObserver::OUT_OF_TABLE)
132 ob->pivot = ob->pivot == 0 ? ShiftObserver::OUT_OF_TABLE : ob->pivot - 1;
133 });
134
135 return true;
136 }
137 }
138 return false;
139}
140
141// Returns the size of the table. Note that the size may not match the underlying allocation.
142uint ESTable::size() const
143{
144 return m_size;
145}
146
147// Retrieves a key and value for a given \a idx, and places them in \a key and
148// \a value. They must be valid pointers.
149void ESTable::iterate(uint idx, Value *key, Value *value)
150{
151 Q_ASSERT(idx < m_size);
152 Q_ASSERT(key);
153 Q_ASSERT(value);
154 *key = m_keys[idx];
155 *value = m_values[idx];
156}
157
158void ESTable::removeUnmarkedKeys()
159{
160 uint idx = 0;
161 uint toIdx = 0;
162 for (; idx < m_size; ++idx) {
163 Q_ASSERT(m_keys[idx].isObject());
164 Object &o = static_cast<Object &>(m_keys[idx]);
165 if (o.d()->isMarked()) {
166 m_keys[toIdx] = m_keys[idx];
167 m_values[toIdx] = m_values[idx];
168 ++toIdx;
169 }
170 }
171 m_size = toIdx;
172}