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
qv4sparsearray.cpp
Go to the documentation of this file.
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// Qt-Security score:significant
4
6#include <stdlib.h>
7
8#ifdef QT_QMAP_DEBUG
9# include <qstring.h>
10# include <qvector.h>
11#endif
12
13using namespace QV4;
14
16{
17 const SparseArrayNode *n = this;
18 if (n->right) {
19 n = n->right;
20 while (n->left)
21 n = n->left;
22 } else {
23 const SparseArrayNode *y = n->parent();
24 while (y && n == y->right) {
25 n = y;
26 y = n->parent();
27 }
28 n = y;
29 }
30 return n;
31}
32
34{
35 const SparseArrayNode *n = this;
36 if (n->left) {
37 n = n->left;
38 while (n->right)
39 n = n->right;
40 } else {
41 const SparseArrayNode *y = n->parent();
42 while (y && n == y->left) {
43 n = y;
44 y = n->parent();
45 }
46 n = y;
47 }
48 return n;
49}
50
51SparseArrayNode *SparseArrayNode::copy(SparseArray *d) const
52{
53 SparseArrayNode *n = d->createNode(size_left, nullptr, false);
54 n->value = value;
56 if (left) {
59 } else {
60 n->left = nullptr;
61 }
62 if (right) {
65 } else {
66 n->right = nullptr;
67 }
68 return n;
69}
70
71/*
72 x y
73 \ / \
74 y --> x b
75 / \ \
76 a b a
77*/
78void SparseArray::rotateLeft(SparseArrayNode *x)
79{
80 SparseArrayNode *&root = header.left;
81 SparseArrayNode *y = x->right;
82 x->right = y->left;
83 if (y->left != nullptr)
84 y->left->setParent(x);
85 y->setParent(x->parent());
86 if (x == root)
87 root = y;
88 else if (x == x->parent()->left)
89 x->parent()->left = y;
90 else
91 x->parent()->right = y;
92 y->left = x;
93 x->setParent(y);
94 y->size_left += x->size_left;
95}
96
97
98/*
99 x y
100 / / \
101 y --> a x
102 / \ /
103 a b b
104*/
105void SparseArray::rotateRight(SparseArrayNode *x)
106{
107 SparseArrayNode *&root = header.left;
108 SparseArrayNode *y = x->left;
109 x->left = y->right;
110 if (y->right != nullptr)
111 y->right->setParent(x);
112 y->setParent(x->parent());
113 if (x == root)
114 root = y;
115 else if (x == x->parent()->right)
116 x->parent()->right = y;
117 else
118 x->parent()->left = y;
119 y->right = x;
120 x->setParent(y);
121 x->size_left -= y->size_left;
122}
123
124
125void SparseArray::rebalance(SparseArrayNode *x)
126{
127 SparseArrayNode *&root = header.left;
128 x->setColor(SparseArrayNode::Red);
129 while (x != root && x->parent()->color() == SparseArrayNode::Red) {
130 if (x->parent() == x->parent()->parent()->left) {
131 SparseArrayNode *y = x->parent()->parent()->right;
132 if (y && y->color() == SparseArrayNode::Red) {
133 x->parent()->setColor(SparseArrayNode::Black);
134 y->setColor(SparseArrayNode::Black);
135 x->parent()->parent()->setColor(SparseArrayNode::Red);
136 x = x->parent()->parent();
137 } else {
138 if (x == x->parent()->right) {
139 x = x->parent();
140 rotateLeft(x);
141 }
142 x->parent()->setColor(SparseArrayNode::Black);
143 x->parent()->parent()->setColor(SparseArrayNode::Red);
144 rotateRight (x->parent()->parent());
145 }
146 } else {
147 SparseArrayNode *y = x->parent()->parent()->left;
148 if (y && y->color() == SparseArrayNode::Red) {
149 x->parent()->setColor(SparseArrayNode::Black);
150 y->setColor(SparseArrayNode::Black);
151 x->parent()->parent()->setColor(SparseArrayNode::Red);
152 x = x->parent()->parent();
153 } else {
154 if (x == x->parent()->left) {
155 x = x->parent();
156 rotateRight(x);
157 }
158 x->parent()->setColor(SparseArrayNode::Black);
159 x->parent()->parent()->setColor(SparseArrayNode::Red);
160 rotateLeft(x->parent()->parent());
161 }
162 }
163 }
164 root->setColor(SparseArrayNode::Black);
165}
166
167void SparseArray::deleteNode(SparseArrayNode *z)
168{
169 SparseArrayNode *&root = header.left;
170 SparseArrayNode *y = z;
171 SparseArrayNode *x;
172 SparseArrayNode *x_parent;
173 if (y->left == nullptr) {
174 x = y->right;
175 if (y == mostLeftNode) {
176 if (x)
177 mostLeftNode = x; // It cannot have (left) children due the red black invariant.
178 else
179 mostLeftNode = y->parent();
180 }
181 } else if (y->right == nullptr) {
182 x = y->left;
183 } else {
184 y = y->right;
185 while (y->left != nullptr)
186 y = y->left;
187 x = y->right;
188 }
189 if (y != z) {
190 // move y into the position of z
191 // adjust size_left so the keys are ok.
192 z->size_left += y->size_left;
193 SparseArrayNode *n = y->parent();
194 while (n != z) {
195 n->size_left -= y->size_left;
196 n = n->parent();
197 }
198 y->size_left = 0;
199 z->value = y->value;
200
201 if (y != z->right) {
202 x_parent = y->parent();
203 y->parent()->left = x;
204 } else {
205 x_parent = z;
206 z->right = x;
207 }
208 if (x)
209 x->setParent(x_parent);
210 } else {
211 x_parent = y->parent();
212 if (x)
213 x->setParent(y->parent());
214 if (root == y)
215 root = x;
216 else if (y->parent()->left == y)
217 y->parent()->left = x;
218 else
219 y->parent()->right = x;
220 if (x && x == y->right)
221 x->size_left += y->size_left;
222 y->size_left = 0;
223 }
224 if (y->color() != SparseArrayNode::Red) {
225 while (x != root && (x == nullptr || x->color() == SparseArrayNode::Black)) {
226 if (x == x_parent->left) {
227 SparseArrayNode *w = x_parent->right;
228 if (w->color() == SparseArrayNode::Red) {
229 w->setColor(SparseArrayNode::Black);
230 x_parent->setColor(SparseArrayNode::Red);
231 rotateLeft(x_parent);
232 w = x_parent->right;
233 }
234 if ((w->left == nullptr || w->left->color() == SparseArrayNode::Black) &&
235 (w->right == nullptr || w->right->color() == SparseArrayNode::Black)) {
236 w->setColor(SparseArrayNode::Red);
237 x = x_parent;
238 x_parent = x_parent->parent();
239 } else {
240 if (w->right == nullptr || w->right->color() == SparseArrayNode::Black) {
241 if (w->left)
242 w->left->setColor(SparseArrayNode::Black);
243 w->setColor(SparseArrayNode::Red);
244 rotateRight(w);
245 w = x_parent->right;
246 }
247 w->setColor(x_parent->color());
248 x_parent->setColor(SparseArrayNode::Black);
249 if (w->right)
250 w->right->setColor(SparseArrayNode::Black);
251 rotateLeft(x_parent);
252 break;
253 }
254 } else {
255 SparseArrayNode *w = x_parent->left;
256 if (w->color() == SparseArrayNode::Red) {
257 w->setColor(SparseArrayNode::Black);
258 x_parent->setColor(SparseArrayNode::Red);
259 rotateRight(x_parent);
260 w = x_parent->left;
261 }
262 if ((w->right == nullptr || w->right->color() == SparseArrayNode::Black) &&
263 (w->left == nullptr || w->left->color() == SparseArrayNode::Black)) {
264 w->setColor(SparseArrayNode::Red);
265 x = x_parent;
266 x_parent = x_parent->parent();
267 } else {
268 if (w->left == nullptr || w->left->color() == SparseArrayNode::Black) {
269 if (w->right)
270 w->right->setColor(SparseArrayNode::Black);
271 w->setColor(SparseArrayNode::Red);
272 rotateLeft(w);
273 w = x_parent->left;
274 }
275 w->setColor(x_parent->color());
276 x_parent->setColor(SparseArrayNode::Black);
277 if (w->left)
278 w->left->setColor(SparseArrayNode::Black);
279 rotateRight(x_parent);
280 break;
281 }
282 }
283 }
284 if (x)
285 x->setColor(SparseArrayNode::Black);
286 }
287 free(y);
288 --numEntries;
289}
290
291void SparseArray::recalcMostLeftNode()
292{
293 mostLeftNode = &header;
294 while (mostLeftNode->left)
295 mostLeftNode = mostLeftNode->left;
296}
297
298static inline int qMapAlignmentThreshold()
299{
300 // malloc on 32-bit platforms should return pointers that are 8-byte
301 // aligned or more while on 64-bit platforms they should be 16-byte aligned
302 // or more
303 return 2 * sizeof(void*);
304}
305
306static inline void *qMapAllocate(int alloc, int alignment)
307{
308 return alignment > qMapAlignmentThreshold()
309 ? qMallocAligned(alloc, alignment)
310 : ::malloc(alloc);
311}
312
313static inline void qMapDeallocate(SparseArrayNode *node, int alignment)
314{
315 if (alignment > qMapAlignmentThreshold())
316 qFreeAligned(node);
317 else
318 ::free(node);
319}
320
321SparseArrayNode *SparseArray::createNode(uint sl, SparseArrayNode *parent, bool left)
322{
323 SparseArrayNode *node = static_cast<SparseArrayNode *>(qMapAllocate(sizeof(SparseArrayNode), alignof(SparseArrayNode)));
324 Q_CHECK_PTR(node);
325
326 node->p = (quintptr)parent;
327 node->left = nullptr;
328 node->right = nullptr;
329 node->size_left = sl;
330 node->value = UINT_MAX;
331 ++numEntries;
332
333 if (parent) {
334 if (left) {
335 parent->left = node;
336 if (parent == mostLeftNode)
337 mostLeftNode = node;
338 } else {
339 parent->right = node;
340 }
341 node->setParent(parent);
342 rebalance(node);
343 }
344 return node;
345}
346
347void SparseArray::freeTree(SparseArrayNode *root, int alignment)
348{
349 if (root->left)
350 freeTree(root->left, alignment);
351 if (root->right)
352 freeTree(root->right, alignment);
353 qMapDeallocate(root, alignment);
354}
355
356SparseArray::SparseArray()
357 : numEntries(0)
358{
359 freeList = Encode(-1);
360 header.p = 0;
361 header.left = nullptr;
362 header.right = nullptr;
363 mostLeftNode = &header;
364}
365
366SparseArray::SparseArray(const SparseArray &other)
367{
368 header.p = 0;
369 header.right = nullptr;
370 if (other.header.left) {
371 header.left = other.header.left->copy(this);
372 header.left->setParent(&header);
373 recalcMostLeftNode();
374 }
375 freeList = other.freeList;
376}
377
378SparseArrayNode *SparseArray::insert(uint akey)
379{
380 SparseArrayNode *n = root();
381 SparseArrayNode *y = end();
382 bool left = true;
383 uint s = akey;
384 while (n) {
385 y = n;
386 if (s == n->size_left) {
387 return n;
388 } else if (s < n->size_left) {
389 left = true;
390 n = n->left;
391 } else {
392 left = false;
393 s -= n->size_left;
394 n = n->right;
395 }
396 }
397
398 return createNode(s, y, left);
399}
Definition qjsvalue.h:23
static void qMapDeallocate(SparseArrayNode *node, int alignment)
static int qMapAlignmentThreshold()
static void * qMapAllocate(int alloc, int alignment)
SparseArrayNode * right
SparseArrayNode * left
SparseArrayNode * copy(SparseArray *d) const
const SparseArrayNode * previousNode() const
SparseArrayNode * parent() const
const SparseArrayNode * nextNode() const
void setParent(SparseArrayNode *pp)