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