Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Piece, PieceTreeBase } from './pieceTreeBase.js';
7
8
export class TreeNode {
9
parent: TreeNode;
10
left: TreeNode;
11
right: TreeNode;
12
color: NodeColor;
13
14
// Piece
15
piece: Piece;
16
size_left: number; // size of the left subtree (not inorder)
17
lf_left: number; // line feeds cnt in the left subtree (not in order)
18
19
constructor(piece: Piece, color: NodeColor) {
20
this.piece = piece;
21
this.color = color;
22
this.size_left = 0;
23
this.lf_left = 0;
24
this.parent = this;
25
this.left = this;
26
this.right = this;
27
}
28
29
public next(): TreeNode {
30
if (this.right !== SENTINEL) {
31
return leftest(this.right);
32
}
33
34
let node: TreeNode = this;
35
36
while (node.parent !== SENTINEL) {
37
if (node.parent.left === node) {
38
break;
39
}
40
41
node = node.parent;
42
}
43
44
if (node.parent === SENTINEL) {
45
return SENTINEL;
46
} else {
47
return node.parent;
48
}
49
}
50
51
public prev(): TreeNode {
52
if (this.left !== SENTINEL) {
53
return righttest(this.left);
54
}
55
56
let node: TreeNode = this;
57
58
while (node.parent !== SENTINEL) {
59
if (node.parent.right === node) {
60
break;
61
}
62
63
node = node.parent;
64
}
65
66
if (node.parent === SENTINEL) {
67
return SENTINEL;
68
} else {
69
return node.parent;
70
}
71
}
72
73
public detach(): void {
74
this.parent = null!;
75
this.left = null!;
76
this.right = null!;
77
}
78
}
79
80
export const enum NodeColor {
81
Black = 0,
82
Red = 1,
83
}
84
85
export const SENTINEL: TreeNode = new TreeNode(null!, NodeColor.Black);
86
SENTINEL.parent = SENTINEL;
87
SENTINEL.left = SENTINEL;
88
SENTINEL.right = SENTINEL;
89
SENTINEL.color = NodeColor.Black;
90
91
export function leftest(node: TreeNode): TreeNode {
92
while (node.left !== SENTINEL) {
93
node = node.left;
94
}
95
return node;
96
}
97
98
export function righttest(node: TreeNode): TreeNode {
99
while (node.right !== SENTINEL) {
100
node = node.right;
101
}
102
return node;
103
}
104
105
function calculateSize(node: TreeNode): number {
106
if (node === SENTINEL) {
107
return 0;
108
}
109
110
return node.size_left + node.piece.length + calculateSize(node.right);
111
}
112
113
function calculateLF(node: TreeNode): number {
114
if (node === SENTINEL) {
115
return 0;
116
}
117
118
return node.lf_left + node.piece.lineFeedCnt + calculateLF(node.right);
119
}
120
121
function resetSentinel(): void {
122
SENTINEL.parent = SENTINEL;
123
}
124
125
export function leftRotate(tree: PieceTreeBase, x: TreeNode) {
126
const y = x.right;
127
128
// fix size_left
129
y.size_left += x.size_left + (x.piece ? x.piece.length : 0);
130
y.lf_left += x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);
131
x.right = y.left;
132
133
if (y.left !== SENTINEL) {
134
y.left.parent = x;
135
}
136
y.parent = x.parent;
137
if (x.parent === SENTINEL) {
138
tree.root = y;
139
} else if (x.parent.left === x) {
140
x.parent.left = y;
141
} else {
142
x.parent.right = y;
143
}
144
y.left = x;
145
x.parent = y;
146
}
147
148
export function rightRotate(tree: PieceTreeBase, y: TreeNode) {
149
const x = y.left;
150
y.left = x.right;
151
if (x.right !== SENTINEL) {
152
x.right.parent = y;
153
}
154
x.parent = y.parent;
155
156
// fix size_left
157
y.size_left -= x.size_left + (x.piece ? x.piece.length : 0);
158
y.lf_left -= x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);
159
160
if (y.parent === SENTINEL) {
161
tree.root = x;
162
} else if (y === y.parent.right) {
163
y.parent.right = x;
164
} else {
165
y.parent.left = x;
166
}
167
168
x.right = y;
169
y.parent = x;
170
}
171
172
export function rbDelete(tree: PieceTreeBase, z: TreeNode) {
173
let x: TreeNode;
174
let y: TreeNode;
175
176
if (z.left === SENTINEL) {
177
y = z;
178
x = y.right;
179
} else if (z.right === SENTINEL) {
180
y = z;
181
x = y.left;
182
} else {
183
y = leftest(z.right);
184
x = y.right;
185
}
186
187
if (y === tree.root) {
188
tree.root = x;
189
190
// if x is null, we are removing the only node
191
x.color = NodeColor.Black;
192
z.detach();
193
resetSentinel();
194
tree.root.parent = SENTINEL;
195
196
return;
197
}
198
199
const yWasRed = (y.color === NodeColor.Red);
200
201
if (y === y.parent.left) {
202
y.parent.left = x;
203
} else {
204
y.parent.right = x;
205
}
206
207
if (y === z) {
208
x.parent = y.parent;
209
recomputeTreeMetadata(tree, x);
210
} else {
211
if (y.parent === z) {
212
x.parent = y;
213
} else {
214
x.parent = y.parent;
215
}
216
217
// as we make changes to x's hierarchy, update size_left of subtree first
218
recomputeTreeMetadata(tree, x);
219
220
y.left = z.left;
221
y.right = z.right;
222
y.parent = z.parent;
223
y.color = z.color;
224
225
if (z === tree.root) {
226
tree.root = y;
227
} else {
228
if (z === z.parent.left) {
229
z.parent.left = y;
230
} else {
231
z.parent.right = y;
232
}
233
}
234
235
if (y.left !== SENTINEL) {
236
y.left.parent = y;
237
}
238
if (y.right !== SENTINEL) {
239
y.right.parent = y;
240
}
241
// update metadata
242
// we replace z with y, so in this sub tree, the length change is z.item.length
243
y.size_left = z.size_left;
244
y.lf_left = z.lf_left;
245
recomputeTreeMetadata(tree, y);
246
}
247
248
z.detach();
249
250
if (x.parent.left === x) {
251
const newSizeLeft = calculateSize(x);
252
const newLFLeft = calculateLF(x);
253
if (newSizeLeft !== x.parent.size_left || newLFLeft !== x.parent.lf_left) {
254
const delta = newSizeLeft - x.parent.size_left;
255
const lf_delta = newLFLeft - x.parent.lf_left;
256
x.parent.size_left = newSizeLeft;
257
x.parent.lf_left = newLFLeft;
258
updateTreeMetadata(tree, x.parent, delta, lf_delta);
259
}
260
}
261
262
recomputeTreeMetadata(tree, x.parent);
263
264
if (yWasRed) {
265
resetSentinel();
266
return;
267
}
268
269
// RB-DELETE-FIXUP
270
let w: TreeNode;
271
while (x !== tree.root && x.color === NodeColor.Black) {
272
if (x === x.parent.left) {
273
w = x.parent.right;
274
275
if (w.color === NodeColor.Red) {
276
w.color = NodeColor.Black;
277
x.parent.color = NodeColor.Red;
278
leftRotate(tree, x.parent);
279
w = x.parent.right;
280
}
281
282
if (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {
283
w.color = NodeColor.Red;
284
x = x.parent;
285
} else {
286
if (w.right.color === NodeColor.Black) {
287
w.left.color = NodeColor.Black;
288
w.color = NodeColor.Red;
289
rightRotate(tree, w);
290
w = x.parent.right;
291
}
292
293
w.color = x.parent.color;
294
x.parent.color = NodeColor.Black;
295
w.right.color = NodeColor.Black;
296
leftRotate(tree, x.parent);
297
x = tree.root;
298
}
299
} else {
300
w = x.parent.left;
301
302
if (w.color === NodeColor.Red) {
303
w.color = NodeColor.Black;
304
x.parent.color = NodeColor.Red;
305
rightRotate(tree, x.parent);
306
w = x.parent.left;
307
}
308
309
if (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {
310
w.color = NodeColor.Red;
311
x = x.parent;
312
313
} else {
314
if (w.left.color === NodeColor.Black) {
315
w.right.color = NodeColor.Black;
316
w.color = NodeColor.Red;
317
leftRotate(tree, w);
318
w = x.parent.left;
319
}
320
321
w.color = x.parent.color;
322
x.parent.color = NodeColor.Black;
323
w.left.color = NodeColor.Black;
324
rightRotate(tree, x.parent);
325
x = tree.root;
326
}
327
}
328
}
329
x.color = NodeColor.Black;
330
resetSentinel();
331
}
332
333
export function fixInsert(tree: PieceTreeBase, x: TreeNode) {
334
recomputeTreeMetadata(tree, x);
335
336
while (x !== tree.root && x.parent.color === NodeColor.Red) {
337
if (x.parent === x.parent.parent.left) {
338
const y = x.parent.parent.right;
339
340
if (y.color === NodeColor.Red) {
341
x.parent.color = NodeColor.Black;
342
y.color = NodeColor.Black;
343
x.parent.parent.color = NodeColor.Red;
344
x = x.parent.parent;
345
} else {
346
if (x === x.parent.right) {
347
x = x.parent;
348
leftRotate(tree, x);
349
}
350
351
x.parent.color = NodeColor.Black;
352
x.parent.parent.color = NodeColor.Red;
353
rightRotate(tree, x.parent.parent);
354
}
355
} else {
356
const y = x.parent.parent.left;
357
358
if (y.color === NodeColor.Red) {
359
x.parent.color = NodeColor.Black;
360
y.color = NodeColor.Black;
361
x.parent.parent.color = NodeColor.Red;
362
x = x.parent.parent;
363
} else {
364
if (x === x.parent.left) {
365
x = x.parent;
366
rightRotate(tree, x);
367
}
368
x.parent.color = NodeColor.Black;
369
x.parent.parent.color = NodeColor.Red;
370
leftRotate(tree, x.parent.parent);
371
}
372
}
373
}
374
375
tree.root.color = NodeColor.Black;
376
}
377
378
export function updateTreeMetadata(tree: PieceTreeBase, x: TreeNode, delta: number, lineFeedCntDelta: number): void {
379
// node length change or line feed count change
380
while (x !== tree.root && x !== SENTINEL) {
381
if (x.parent.left === x) {
382
x.parent.size_left += delta;
383
x.parent.lf_left += lineFeedCntDelta;
384
}
385
386
x = x.parent;
387
}
388
}
389
390
export function recomputeTreeMetadata(tree: PieceTreeBase, x: TreeNode) {
391
let delta = 0;
392
let lf_delta = 0;
393
if (x === tree.root) {
394
return;
395
}
396
397
// go upwards till the node whose left subtree is changed.
398
while (x !== tree.root && x === x.parent.right) {
399
x = x.parent;
400
}
401
402
if (x === tree.root) {
403
// well, it means we add a node to the end (inorder)
404
return;
405
}
406
407
// x is the node whose right subtree is changed.
408
x = x.parent;
409
410
delta = calculateSize(x.left) - x.size_left;
411
lf_delta = calculateLF(x.left) - x.lf_left;
412
x.size_left += delta;
413
x.lf_left += lf_delta;
414
415
416
// go upwards till root. O(logN)
417
while (x !== tree.root && (delta !== 0 || lf_delta !== 0)) {
418
if (x.parent.left === x) {
419
x.parent.size_left += delta;
420
x.parent.lf_left += lf_delta;
421
}
422
423
x = x.parent;
424
}
425
}
426
427