Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
95dfbe44
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
95dfbe44
编写于
1月 22, 2018
作者:
P
Peng Lyu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Move rbtree logic out of piecetreebase.
上级
d34a8edc
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
445 addition
and
441 deletion
+445
-441
src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts
.../editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts
+16
-440
src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts
src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts
+427
-0
src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts
...mon/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts
+2
-1
未找到文件。
src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts
浏览文件 @
95dfbe44
...
...
@@ -8,49 +8,7 @@ import { Position } from 'vs/editor/common/core/position';
import
{
CharCode
}
from
'
vs/base/common/charCode
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
ITextSnapshot
}
from
'
vs/platform/files/common/files
'
;
export
const
enum
NodeColor
{
Black
=
0
,
Red
=
1
,
}
export
function
getNodeColor
(
node
:
TreeNode
)
{
return
node
.
color
;
}
function
leftest
(
node
:
TreeNode
):
TreeNode
{
while
(
node
.
left
!==
SENTINEL
)
{
node
=
node
.
left
;
}
return
node
;
}
function
righttest
(
node
:
TreeNode
):
TreeNode
{
while
(
node
.
right
!==
SENTINEL
)
{
node
=
node
.
right
;
}
return
node
;
}
function
calculateSize
(
node
:
TreeNode
):
number
{
if
(
node
===
SENTINEL
)
{
return
0
;
}
return
node
.
size_left
+
node
.
piece
.
length
+
calculateSize
(
node
.
right
);
}
function
calculateLF
(
node
:
TreeNode
):
number
{
if
(
node
===
SENTINEL
)
{
return
0
;
}
return
node
.
lf_left
+
node
.
piece
.
lineFeedCnt
+
calculateLF
(
node
.
right
);
}
function
resetSentinel
():
void
{
SENTINEL
.
parent
=
SENTINEL
;
}
import
{
leftest
,
righttest
,
updateTreeMetadata
,
rbDelete
,
fixInsert
,
NodeColor
,
SENTINEL
,
TreeNode
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase
'
;
// const lfRegex = new RegExp(/\r\n|\r|\n/g);
...
...
@@ -138,84 +96,6 @@ export function createLineStarts(r: number[], str: string): LineStarts {
return
result
;
}
export
class
TreeNode
{
parent
:
TreeNode
;
left
:
TreeNode
;
right
:
TreeNode
;
color
:
NodeColor
;
// Piece
piece
:
Piece
;
size_left
:
number
;
// size of the left subtree (not inorder)
lf_left
:
number
;
// line feeds cnt in the left subtree (not in order)
constructor
(
piece
:
Piece
,
color
:
NodeColor
)
{
this
.
piece
=
piece
;
this
.
color
=
color
;
this
.
size_left
=
0
;
this
.
lf_left
=
0
;
this
.
parent
=
null
;
this
.
left
=
null
;
this
.
right
=
null
;
}
public
next
():
TreeNode
{
if
(
this
.
right
!==
SENTINEL
)
{
return
leftest
(
this
.
right
);
}
let
node
:
TreeNode
=
this
;
while
(
node
.
parent
!==
SENTINEL
)
{
if
(
node
.
parent
.
left
===
node
)
{
break
;
}
node
=
node
.
parent
;
}
if
(
node
.
parent
===
SENTINEL
)
{
return
SENTINEL
;
}
else
{
return
node
.
parent
;
}
}
public
prev
():
TreeNode
{
if
(
this
.
left
!==
SENTINEL
)
{
return
righttest
(
this
.
left
);
}
let
node
:
TreeNode
=
this
;
while
(
node
.
parent
!==
SENTINEL
)
{
if
(
node
.
parent
.
right
===
node
)
{
break
;
}
node
=
node
.
parent
;
}
if
(
node
.
parent
===
SENTINEL
)
{
return
SENTINEL
;
}
else
{
return
node
.
parent
;
}
}
public
detach
():
void
{
this
.
parent
=
null
;
this
.
left
=
null
;
this
.
right
=
null
;
}
}
export
const
SENTINEL
:
TreeNode
=
new
TreeNode
(
null
,
NodeColor
.
Black
);
SENTINEL
.
parent
=
SENTINEL
;
SENTINEL
.
left
=
SENTINEL
;
SENTINEL
.
right
=
SENTINEL
;
SENTINEL
.
color
=
NodeColor
.
Black
;
export
interface
NodePosition
{
/**
* Piece Index
...
...
@@ -393,7 +273,6 @@ export class PieceTreeBase {
this
.
create
(
chunks
);
}
// #region Buffer API
public
createSnapshot
(
BOM
:
string
):
ITextSnapshot
{
return
new
PieceTreeSnapshot
(
this
,
BOM
);
...
...
@@ -654,7 +533,7 @@ export class PieceTreeBase {
if
(
startPosition
.
nodeStartOffset
===
offset
)
{
if
(
cnt
===
startNode
.
piece
.
length
)
{
// delete node
let
next
=
startNode
.
next
();
this
.
rbDelete
(
startNode
);
rbDelete
(
this
,
startNode
);
this
.
validateCRLFWithPrevNode
(
next
);
this
.
computeBufferMetadata
();
return
;
...
...
@@ -718,7 +597,7 @@ export class PieceTreeBase {
piece
.
length
-=
1
;
value
+=
'
\n
'
;
this
.
updateTreeMetadata
(
node
,
-
1
,
-
1
);
updateTreeMetadata
(
this
,
node
,
-
1
,
-
1
);
if
(
node
.
piece
.
length
===
0
)
{
nodesToDel
.
push
(
node
);
...
...
@@ -822,7 +701,7 @@ export class PieceTreeBase {
deleteNodes
(
nodes
:
TreeNode
[]):
void
{
for
(
let
i
=
0
;
i
<
nodes
.
length
;
i
++
)
{
this
.
rbDelete
(
nodes
[
i
]);
rbDelete
(
this
,
nodes
[
i
]);
}
}
...
...
@@ -978,7 +857,7 @@ export class PieceTreeBase {
let
lf_delta
=
piece
.
lineFeedCnt
-
originalLFCnt
;
let
size_delta
=
newEndOffset
-
originalEndOffset
;
piece
.
length
+=
size_delta
;
this
.
updateTreeMetadata
(
node
,
size_delta
,
lf_delta
);
updateTreeMetadata
(
this
,
node
,
size_delta
,
lf_delta
);
}
deleteNodeHead
(
node
:
TreeNode
,
pos
:
BufferCursor
)
{
...
...
@@ -992,7 +871,7 @@ export class PieceTreeBase {
let
lf_delta
=
piece
.
lineFeedCnt
-
originalLFCnt
;
let
size_delta
=
originalStartOffset
-
newStartOffset
;
piece
.
length
+=
size_delta
;
this
.
updateTreeMetadata
(
node
,
size_delta
,
lf_delta
);
updateTreeMetadata
(
this
,
node
,
size_delta
,
lf_delta
);
}
shrinkNode
(
node
:
TreeNode
,
start
:
BufferCursor
,
end
:
BufferCursor
)
{
...
...
@@ -1008,7 +887,7 @@ export class PieceTreeBase {
let
newLength
=
this
.
offsetInBuffer
(
piece
.
bufferIndex
,
start
)
-
this
.
offsetInBuffer
(
piece
.
bufferIndex
,
originalStartPos
);
let
newLFCnt
=
piece
.
lineFeedCnt
;
piece
.
length
=
newLength
;
this
.
updateTreeMetadata
(
node
,
newLength
-
oldLength
,
newLFCnt
-
oldLFCnt
);
updateTreeMetadata
(
this
,
node
,
newLength
-
oldLength
,
newLFCnt
-
oldLFCnt
);
// new right piece, end, originalEndPos
let
newPiece
=
new
Piece
(
...
...
@@ -1052,7 +931,7 @@ export class PieceTreeBase {
node
.
piece
.
lineFeedCnt
=
newLineFeedCnt
;
let
lf_delta
=
newLineFeedCnt
-
oldLineFeedCnt
;
this
.
_lastChangeBufferPos
=
endPos
;
this
.
updateTreeMetadata
(
node
,
value
.
length
,
lf_delta
);
updateTreeMetadata
(
this
,
node
,
value
.
length
,
lf_delta
);
}
nodeAt
(
offset
:
number
):
NodePosition
{
...
...
@@ -1247,7 +1126,7 @@ export class PieceTreeBase {
prev
.
piece
.
length
-=
1
;
prev
.
piece
.
lineFeedCnt
-=
1
;
this
.
updateTreeMetadata
(
prev
,
-
1
,
-
1
);
updateTreeMetadata
(
this
,
prev
,
-
1
,
-
1
);
if
(
prev
.
piece
.
length
===
0
)
{
nodesToDel
.
push
(
prev
);
}
...
...
@@ -1259,7 +1138,7 @@ export class PieceTreeBase {
next
.
piece
.
lineFeedCnt
=
this
.
getLineFeedCnt
(
next
.
piece
.
bufferIndex
,
next
.
piece
.
start
,
next
.
piece
.
end
);
// @todo, we can optimize
// }
this
.
updateTreeMetadata
(
next
,
-
1
,
-
1
);
updateTreeMetadata
(
this
,
next
,
-
1
,
-
1
);
if
(
next
.
piece
.
length
===
0
)
{
nodesToDel
.
push
(
next
);
}
...
...
@@ -1270,7 +1149,7 @@ export class PieceTreeBase {
// delete empty nodes
for
(
let
i
=
0
;
i
<
nodesToDel
.
length
;
i
++
)
{
this
.
rbDelete
(
nodesToDel
[
i
]);
rbDelete
(
this
,
nodesToDel
[
i
]);
}
}
...
...
@@ -1282,7 +1161,7 @@ export class PieceTreeBase {
value
+=
'
\n
'
;
if
(
nextNode
.
piece
.
length
===
1
)
{
this
.
rbDelete
(
nextNode
);
rbDelete
(
this
,
nextNode
);
}
else
{
let
piece
=
nextNode
.
piece
;
...
...
@@ -1290,7 +1169,7 @@ export class PieceTreeBase {
piece
.
start
=
newStart
;
piece
.
length
-=
1
;
piece
.
lineFeedCnt
=
this
.
getLineFeedCnt
(
piece
.
bufferIndex
,
piece
.
start
,
piece
.
end
);
// @todo, we can optimize
this
.
updateTreeMetadata
(
nextNode
,
-
1
,
-
1
);
updateTreeMetadata
(
this
,
nextNode
,
-
1
,
-
1
);
}
return
true
;
}
...
...
@@ -1303,7 +1182,7 @@ export class PieceTreeBase {
// #endregion
// #region
Red Black Tree
// #region
Tree operations
iterate
(
node
:
TreeNode
,
callback
:
(
node
:
TreeNode
)
=>
boolean
):
boolean
{
if
(
node
===
SENTINEL
)
{
return
callback
(
SENTINEL
);
...
...
@@ -1330,53 +1209,6 @@ export class PieceTreeBase {
return
currentContent
;
}
leftRotate
(
x
:
TreeNode
)
{
let
y
=
x
.
right
;
// fix size_left
y
.
size_left
+=
x
.
size_left
+
(
x
.
piece
?
x
.
piece
.
length
:
0
);
y
.
lf_left
+=
x
.
lf_left
+
(
x
.
piece
?
x
.
piece
.
lineFeedCnt
:
0
);
x
.
right
=
y
.
left
;
if
(
y
.
left
!==
SENTINEL
)
{
y
.
left
.
parent
=
x
;
}
y
.
parent
=
x
.
parent
;
if
(
x
.
parent
===
SENTINEL
)
{
this
.
root
=
y
;
}
else
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
left
=
y
;
}
else
{
x
.
parent
.
right
=
y
;
}
y
.
left
=
x
;
x
.
parent
=
y
;
}
rightRotate
(
y
:
TreeNode
)
{
let
x
=
y
.
left
;
y
.
left
=
x
.
right
;
if
(
x
.
right
!==
SENTINEL
)
{
x
.
right
.
parent
=
y
;
}
x
.
parent
=
y
.
parent
;
// fix size_left
y
.
size_left
-=
x
.
size_left
+
(
x
.
piece
?
x
.
piece
.
length
:
0
);
y
.
lf_left
-=
x
.
lf_left
+
(
x
.
piece
?
x
.
piece
.
lineFeedCnt
:
0
);
if
(
y
.
parent
===
SENTINEL
)
{
this
.
root
=
x
;
}
else
if
(
y
===
y
.
parent
.
right
)
{
y
.
parent
.
right
=
x
;
}
else
{
y
.
parent
.
left
=
x
;
}
x
.
right
=
y
;
y
.
parent
=
x
;
}
/**
* node node
* / \ / \
...
...
@@ -1405,7 +1237,7 @@ export class PieceTreeBase {
z
.
parent
=
nextNode
;
}
this
.
fixInsert
(
z
);
fixInsert
(
this
,
z
);
return
z
;
}
...
...
@@ -1437,266 +1269,10 @@ export class PieceTreeBase {
z
.
parent
=
prevNode
;
}
this
.
fixInsert
(
z
);
fixInsert
(
this
,
z
);
return
z
;
}
rbDelete
(
z
:
TreeNode
)
{
let
x
:
TreeNode
;
let
y
:
TreeNode
;
if
(
z
.
left
===
SENTINEL
)
{
y
=
z
;
x
=
y
.
right
;
}
else
if
(
z
.
right
===
SENTINEL
)
{
y
=
z
;
x
=
y
.
left
;
}
else
{
y
=
leftest
(
z
.
right
);
x
=
y
.
right
;
}
if
(
y
===
this
.
root
)
{
this
.
root
=
x
;
// if x is null, we are removing the only node
x
.
color
=
NodeColor
.
Black
;
z
.
detach
();
resetSentinel
();
this
.
root
.
parent
=
SENTINEL
;
return
;
}
let
yWasRed
=
(
y
.
color
===
NodeColor
.
Red
);
if
(
y
===
y
.
parent
.
left
)
{
y
.
parent
.
left
=
x
;
}
else
{
y
.
parent
.
right
=
x
;
}
if
(
y
===
z
)
{
x
.
parent
=
y
.
parent
;
this
.
recomputeTreeMetadata
(
x
);
}
else
{
if
(
y
.
parent
===
z
)
{
x
.
parent
=
y
;
}
else
{
x
.
parent
=
y
.
parent
;
}
// as we make changes to x's hierarchy, update size_left of subtree first
this
.
recomputeTreeMetadata
(
x
);
y
.
left
=
z
.
left
;
y
.
right
=
z
.
right
;
y
.
parent
=
z
.
parent
;
y
.
color
=
z
.
color
;
if
(
z
===
this
.
root
)
{
this
.
root
=
y
;
}
else
{
if
(
z
===
z
.
parent
.
left
)
{
z
.
parent
.
left
=
y
;
}
else
{
z
.
parent
.
right
=
y
;
}
}
if
(
y
.
left
!==
SENTINEL
)
{
y
.
left
.
parent
=
y
;
}
if
(
y
.
right
!==
SENTINEL
)
{
y
.
right
.
parent
=
y
;
}
// update metadata
// we replace z with y, so in this sub tree, the length change is z.item.length
y
.
size_left
=
z
.
size_left
;
y
.
lf_left
=
z
.
lf_left
;
this
.
recomputeTreeMetadata
(
y
);
}
z
.
detach
();
if
(
x
.
parent
.
left
===
x
)
{
let
newSizeLeft
=
calculateSize
(
x
);
let
newLFLeft
=
calculateLF
(
x
);
if
(
newSizeLeft
!==
x
.
parent
.
size_left
||
newLFLeft
!==
x
.
parent
.
lf_left
)
{
let
delta
=
newSizeLeft
-
x
.
parent
.
size_left
;
let
lf_delta
=
newLFLeft
-
x
.
parent
.
lf_left
;
x
.
parent
.
size_left
=
newSizeLeft
;
x
.
parent
.
lf_left
=
newLFLeft
;
this
.
updateTreeMetadata
(
x
.
parent
,
delta
,
lf_delta
);
}
}
this
.
recomputeTreeMetadata
(
x
.
parent
);
if
(
yWasRed
)
{
resetSentinel
();
return
;
}
// RB-DELETE-FIXUP
let
w
:
TreeNode
;
while
(
x
!==
this
.
root
&&
x
.
color
===
NodeColor
.
Black
)
{
if
(
x
===
x
.
parent
.
left
)
{
w
=
x
.
parent
.
right
;
if
(
w
.
color
===
NodeColor
.
Red
)
{
w
.
color
=
NodeColor
.
Black
;
x
.
parent
.
color
=
NodeColor
.
Red
;
this
.
leftRotate
(
x
.
parent
);
w
=
x
.
parent
.
right
;
}
if
(
w
.
left
.
color
===
NodeColor
.
Black
&&
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
;
}
else
{
if
(
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
left
.
color
=
NodeColor
.
Black
;
w
.
color
=
NodeColor
.
Red
;
this
.
rightRotate
(
w
);
w
=
x
.
parent
.
right
;
}
w
.
color
=
x
.
parent
.
color
;
x
.
parent
.
color
=
NodeColor
.
Black
;
w
.
right
.
color
=
NodeColor
.
Black
;
this
.
leftRotate
(
x
.
parent
);
x
=
this
.
root
;
}
}
else
{
w
=
x
.
parent
.
left
;
if
(
w
.
color
===
NodeColor
.
Red
)
{
w
.
color
=
NodeColor
.
Black
;
x
.
parent
.
color
=
NodeColor
.
Red
;
this
.
rightRotate
(
x
.
parent
);
w
=
x
.
parent
.
left
;
}
if
(
w
.
left
.
color
===
NodeColor
.
Black
&&
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
;
}
else
{
if
(
w
.
left
.
color
===
NodeColor
.
Black
)
{
w
.
right
.
color
=
NodeColor
.
Black
;
w
.
color
=
NodeColor
.
Red
;
this
.
leftRotate
(
w
);
w
=
x
.
parent
.
left
;
}
w
.
color
=
x
.
parent
.
color
;
x
.
parent
.
color
=
NodeColor
.
Black
;
w
.
left
.
color
=
NodeColor
.
Black
;
this
.
rightRotate
(
x
.
parent
);
x
=
this
.
root
;
}
}
}
x
.
color
=
NodeColor
.
Black
;
resetSentinel
();
}
fixInsert
(
x
:
TreeNode
)
{
this
.
recomputeTreeMetadata
(
x
);
while
(
x
!==
this
.
root
&&
x
.
parent
.
color
===
NodeColor
.
Red
)
{
if
(
x
.
parent
===
x
.
parent
.
parent
.
left
)
{
const
y
=
x
.
parent
.
parent
.
right
;
if
(
y
.
color
===
NodeColor
.
Red
)
{
x
.
parent
.
color
=
NodeColor
.
Black
;
y
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
.
parent
;
}
else
{
if
(
x
===
x
.
parent
.
right
)
{
x
=
x
.
parent
;
this
.
leftRotate
(
x
);
}
x
.
parent
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
this
.
rightRotate
(
x
.
parent
.
parent
);
}
}
else
{
const
y
=
x
.
parent
.
parent
.
left
;
if
(
y
.
color
===
NodeColor
.
Red
)
{
x
.
parent
.
color
=
NodeColor
.
Black
;
y
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
.
parent
;
}
else
{
if
(
x
===
x
.
parent
.
left
)
{
x
=
x
.
parent
;
this
.
rightRotate
(
x
);
}
x
.
parent
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
this
.
leftRotate
(
x
.
parent
.
parent
);
}
}
}
this
.
root
.
color
=
NodeColor
.
Black
;
}
updateTreeMetadata
(
x
:
TreeNode
,
delta
:
number
,
lineFeedCntDelta
:
number
):
void
{
// node length change or line feed count change
while
(
x
!==
this
.
root
&&
x
!==
SENTINEL
)
{
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
size_left
+=
delta
;
x
.
parent
.
lf_left
+=
lineFeedCntDelta
;
}
x
=
x
.
parent
;
}
}
recomputeTreeMetadata
(
x
:
TreeNode
)
{
let
delta
=
0
;
let
lf_delta
=
0
;
if
(
x
===
this
.
root
)
{
return
;
}
if
(
delta
===
0
)
{
// go upwards till the node whose left subtree is changed.
while
(
x
!==
this
.
root
&&
x
===
x
.
parent
.
right
)
{
x
=
x
.
parent
;
}
if
(
x
===
this
.
root
)
{
// well, it means we add a node to the end (inorder)
return
;
}
// x is the node whose right subtree is changed.
x
=
x
.
parent
;
delta
=
calculateSize
(
x
.
left
)
-
x
.
size_left
;
lf_delta
=
calculateLF
(
x
.
left
)
-
x
.
lf_left
;
x
.
size_left
+=
delta
;
x
.
lf_left
+=
lf_delta
;
}
// go upwards till root. O(logN)
while
(
x
!==
this
.
root
&&
(
delta
!==
0
||
lf_delta
!==
0
))
{
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
size_left
+=
delta
;
x
.
parent
.
lf_left
+=
lf_delta
;
}
x
=
x
.
parent
;
}
}
getContentOfSubTree
(
node
:
TreeNode
):
string
{
let
str
=
''
;
...
...
src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts
0 → 100644
浏览文件 @
95dfbe44
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
Piece
,
PieceTreeBase
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase
'
;
export
class
TreeNode
{
parent
:
TreeNode
;
left
:
TreeNode
;
right
:
TreeNode
;
color
:
NodeColor
;
// Piece
piece
:
Piece
;
size_left
:
number
;
// size of the left subtree (not inorder)
lf_left
:
number
;
// line feeds cnt in the left subtree (not in order)
constructor
(
piece
:
Piece
,
color
:
NodeColor
)
{
this
.
piece
=
piece
;
this
.
color
=
color
;
this
.
size_left
=
0
;
this
.
lf_left
=
0
;
this
.
parent
=
null
;
this
.
left
=
null
;
this
.
right
=
null
;
}
public
next
():
TreeNode
{
if
(
this
.
right
!==
SENTINEL
)
{
return
leftest
(
this
.
right
);
}
let
node
:
TreeNode
=
this
;
while
(
node
.
parent
!==
SENTINEL
)
{
if
(
node
.
parent
.
left
===
node
)
{
break
;
}
node
=
node
.
parent
;
}
if
(
node
.
parent
===
SENTINEL
)
{
return
SENTINEL
;
}
else
{
return
node
.
parent
;
}
}
public
prev
():
TreeNode
{
if
(
this
.
left
!==
SENTINEL
)
{
return
righttest
(
this
.
left
);
}
let
node
:
TreeNode
=
this
;
while
(
node
.
parent
!==
SENTINEL
)
{
if
(
node
.
parent
.
right
===
node
)
{
break
;
}
node
=
node
.
parent
;
}
if
(
node
.
parent
===
SENTINEL
)
{
return
SENTINEL
;
}
else
{
return
node
.
parent
;
}
}
public
detach
():
void
{
this
.
parent
=
null
;
this
.
left
=
null
;
this
.
right
=
null
;
}
}
export
const
SENTINEL
:
TreeNode
=
new
TreeNode
(
null
,
NodeColor
.
Black
);
SENTINEL
.
parent
=
SENTINEL
;
SENTINEL
.
left
=
SENTINEL
;
SENTINEL
.
right
=
SENTINEL
;
SENTINEL
.
color
=
NodeColor
.
Black
;
export
const
enum
NodeColor
{
Black
=
0
,
Red
=
1
,
}
export
function
leftest
(
node
:
TreeNode
):
TreeNode
{
while
(
node
.
left
!==
SENTINEL
)
{
node
=
node
.
left
;
}
return
node
;
}
export
function
righttest
(
node
:
TreeNode
):
TreeNode
{
while
(
node
.
right
!==
SENTINEL
)
{
node
=
node
.
right
;
}
return
node
;
}
export
function
calculateSize
(
node
:
TreeNode
):
number
{
if
(
node
===
SENTINEL
)
{
return
0
;
}
return
node
.
size_left
+
node
.
piece
.
length
+
calculateSize
(
node
.
right
);
}
export
function
calculateLF
(
node
:
TreeNode
):
number
{
if
(
node
===
SENTINEL
)
{
return
0
;
}
return
node
.
lf_left
+
node
.
piece
.
lineFeedCnt
+
calculateLF
(
node
.
right
);
}
export
function
resetSentinel
():
void
{
SENTINEL
.
parent
=
SENTINEL
;
}
export
function
leftRotate
(
tree
:
PieceTreeBase
,
x
:
TreeNode
)
{
let
y
=
x
.
right
;
// fix size_left
y
.
size_left
+=
x
.
size_left
+
(
x
.
piece
?
x
.
piece
.
length
:
0
);
y
.
lf_left
+=
x
.
lf_left
+
(
x
.
piece
?
x
.
piece
.
lineFeedCnt
:
0
);
x
.
right
=
y
.
left
;
if
(
y
.
left
!==
SENTINEL
)
{
y
.
left
.
parent
=
x
;
}
y
.
parent
=
x
.
parent
;
if
(
x
.
parent
===
SENTINEL
)
{
tree
.
root
=
y
;
}
else
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
left
=
y
;
}
else
{
x
.
parent
.
right
=
y
;
}
y
.
left
=
x
;
x
.
parent
=
y
;
}
export
function
rightRotate
(
tree
:
PieceTreeBase
,
y
:
TreeNode
)
{
let
x
=
y
.
left
;
y
.
left
=
x
.
right
;
if
(
x
.
right
!==
SENTINEL
)
{
x
.
right
.
parent
=
y
;
}
x
.
parent
=
y
.
parent
;
// fix size_left
y
.
size_left
-=
x
.
size_left
+
(
x
.
piece
?
x
.
piece
.
length
:
0
);
y
.
lf_left
-=
x
.
lf_left
+
(
x
.
piece
?
x
.
piece
.
lineFeedCnt
:
0
);
if
(
y
.
parent
===
SENTINEL
)
{
tree
.
root
=
x
;
}
else
if
(
y
===
y
.
parent
.
right
)
{
y
.
parent
.
right
=
x
;
}
else
{
y
.
parent
.
left
=
x
;
}
x
.
right
=
y
;
y
.
parent
=
x
;
}
export
function
rbDelete
(
tree
:
PieceTreeBase
,
z
:
TreeNode
)
{
let
x
:
TreeNode
;
let
y
:
TreeNode
;
if
(
z
.
left
===
SENTINEL
)
{
y
=
z
;
x
=
y
.
right
;
}
else
if
(
z
.
right
===
SENTINEL
)
{
y
=
z
;
x
=
y
.
left
;
}
else
{
y
=
leftest
(
z
.
right
);
x
=
y
.
right
;
}
if
(
y
===
tree
.
root
)
{
tree
.
root
=
x
;
// if x is null, we are removing the only node
x
.
color
=
NodeColor
.
Black
;
z
.
detach
();
resetSentinel
();
tree
.
root
.
parent
=
SENTINEL
;
return
;
}
let
yWasRed
=
(
y
.
color
===
NodeColor
.
Red
);
if
(
y
===
y
.
parent
.
left
)
{
y
.
parent
.
left
=
x
;
}
else
{
y
.
parent
.
right
=
x
;
}
if
(
y
===
z
)
{
x
.
parent
=
y
.
parent
;
recomputeTreeMetadata
(
tree
,
x
);
}
else
{
if
(
y
.
parent
===
z
)
{
x
.
parent
=
y
;
}
else
{
x
.
parent
=
y
.
parent
;
}
// as we make changes to x's hierarchy, update size_left of subtree first
recomputeTreeMetadata
(
tree
,
x
);
y
.
left
=
z
.
left
;
y
.
right
=
z
.
right
;
y
.
parent
=
z
.
parent
;
y
.
color
=
z
.
color
;
if
(
z
===
tree
.
root
)
{
tree
.
root
=
y
;
}
else
{
if
(
z
===
z
.
parent
.
left
)
{
z
.
parent
.
left
=
y
;
}
else
{
z
.
parent
.
right
=
y
;
}
}
if
(
y
.
left
!==
SENTINEL
)
{
y
.
left
.
parent
=
y
;
}
if
(
y
.
right
!==
SENTINEL
)
{
y
.
right
.
parent
=
y
;
}
// update metadata
// we replace z with y, so in this sub tree, the length change is z.item.length
y
.
size_left
=
z
.
size_left
;
y
.
lf_left
=
z
.
lf_left
;
recomputeTreeMetadata
(
tree
,
y
);
}
z
.
detach
();
if
(
x
.
parent
.
left
===
x
)
{
let
newSizeLeft
=
calculateSize
(
x
);
let
newLFLeft
=
calculateLF
(
x
);
if
(
newSizeLeft
!==
x
.
parent
.
size_left
||
newLFLeft
!==
x
.
parent
.
lf_left
)
{
let
delta
=
newSizeLeft
-
x
.
parent
.
size_left
;
let
lf_delta
=
newLFLeft
-
x
.
parent
.
lf_left
;
x
.
parent
.
size_left
=
newSizeLeft
;
x
.
parent
.
lf_left
=
newLFLeft
;
updateTreeMetadata
(
tree
,
x
.
parent
,
delta
,
lf_delta
);
}
}
recomputeTreeMetadata
(
tree
,
x
.
parent
);
if
(
yWasRed
)
{
resetSentinel
();
return
;
}
// RB-DELETE-FIXUP
let
w
:
TreeNode
;
while
(
x
!==
tree
.
root
&&
x
.
color
===
NodeColor
.
Black
)
{
if
(
x
===
x
.
parent
.
left
)
{
w
=
x
.
parent
.
right
;
if
(
w
.
color
===
NodeColor
.
Red
)
{
w
.
color
=
NodeColor
.
Black
;
x
.
parent
.
color
=
NodeColor
.
Red
;
leftRotate
(
tree
,
x
.
parent
);
w
=
x
.
parent
.
right
;
}
if
(
w
.
left
.
color
===
NodeColor
.
Black
&&
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
;
}
else
{
if
(
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
left
.
color
=
NodeColor
.
Black
;
w
.
color
=
NodeColor
.
Red
;
rightRotate
(
tree
,
w
);
w
=
x
.
parent
.
right
;
}
w
.
color
=
x
.
parent
.
color
;
x
.
parent
.
color
=
NodeColor
.
Black
;
w
.
right
.
color
=
NodeColor
.
Black
;
leftRotate
(
tree
,
x
.
parent
);
x
=
tree
.
root
;
}
}
else
{
w
=
x
.
parent
.
left
;
if
(
w
.
color
===
NodeColor
.
Red
)
{
w
.
color
=
NodeColor
.
Black
;
x
.
parent
.
color
=
NodeColor
.
Red
;
rightRotate
(
tree
,
x
.
parent
);
w
=
x
.
parent
.
left
;
}
if
(
w
.
left
.
color
===
NodeColor
.
Black
&&
w
.
right
.
color
===
NodeColor
.
Black
)
{
w
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
;
}
else
{
if
(
w
.
left
.
color
===
NodeColor
.
Black
)
{
w
.
right
.
color
=
NodeColor
.
Black
;
w
.
color
=
NodeColor
.
Red
;
leftRotate
(
tree
,
w
);
w
=
x
.
parent
.
left
;
}
w
.
color
=
x
.
parent
.
color
;
x
.
parent
.
color
=
NodeColor
.
Black
;
w
.
left
.
color
=
NodeColor
.
Black
;
rightRotate
(
tree
,
x
.
parent
);
x
=
tree
.
root
;
}
}
}
x
.
color
=
NodeColor
.
Black
;
resetSentinel
();
}
export
function
fixInsert
(
tree
:
PieceTreeBase
,
x
:
TreeNode
)
{
recomputeTreeMetadata
(
tree
,
x
);
while
(
x
!==
tree
.
root
&&
x
.
parent
.
color
===
NodeColor
.
Red
)
{
if
(
x
.
parent
===
x
.
parent
.
parent
.
left
)
{
const
y
=
x
.
parent
.
parent
.
right
;
if
(
y
.
color
===
NodeColor
.
Red
)
{
x
.
parent
.
color
=
NodeColor
.
Black
;
y
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
.
parent
;
}
else
{
if
(
x
===
x
.
parent
.
right
)
{
x
=
x
.
parent
;
leftRotate
(
tree
,
x
);
}
x
.
parent
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
rightRotate
(
tree
,
x
.
parent
.
parent
);
}
}
else
{
const
y
=
x
.
parent
.
parent
.
left
;
if
(
y
.
color
===
NodeColor
.
Red
)
{
x
.
parent
.
color
=
NodeColor
.
Black
;
y
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
x
=
x
.
parent
.
parent
;
}
else
{
if
(
x
===
x
.
parent
.
left
)
{
x
=
x
.
parent
;
rightRotate
(
tree
,
x
);
}
x
.
parent
.
color
=
NodeColor
.
Black
;
x
.
parent
.
parent
.
color
=
NodeColor
.
Red
;
leftRotate
(
tree
,
x
.
parent
.
parent
);
}
}
}
tree
.
root
.
color
=
NodeColor
.
Black
;
}
export
function
updateTreeMetadata
(
tree
:
PieceTreeBase
,
x
:
TreeNode
,
delta
:
number
,
lineFeedCntDelta
:
number
):
void
{
// node length change or line feed count change
while
(
x
!==
tree
.
root
&&
x
!==
SENTINEL
)
{
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
size_left
+=
delta
;
x
.
parent
.
lf_left
+=
lineFeedCntDelta
;
}
x
=
x
.
parent
;
}
}
export
function
recomputeTreeMetadata
(
tree
:
PieceTreeBase
,
x
:
TreeNode
)
{
let
delta
=
0
;
let
lf_delta
=
0
;
if
(
x
===
tree
.
root
)
{
return
;
}
if
(
delta
===
0
)
{
// go upwards till the node whose left subtree is changed.
while
(
x
!==
tree
.
root
&&
x
===
x
.
parent
.
right
)
{
x
=
x
.
parent
;
}
if
(
x
===
tree
.
root
)
{
// well, it means we add a node to the end (inorder)
return
;
}
// x is the node whose right subtree is changed.
x
=
x
.
parent
;
delta
=
calculateSize
(
x
.
left
)
-
x
.
size_left
;
lf_delta
=
calculateLF
(
x
.
left
)
-
x
.
lf_left
;
x
.
size_left
+=
delta
;
x
.
lf_left
+=
lf_delta
;
}
// go upwards till root. O(logN)
while
(
x
!==
tree
.
root
&&
(
delta
!==
0
||
lf_delta
!==
0
))
{
if
(
x
.
parent
.
left
===
x
)
{
x
.
parent
.
size_left
+=
delta
;
x
.
parent
.
lf_left
+=
lf_delta
;
}
x
=
x
.
parent
;
}
}
src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts
浏览文件 @
95dfbe44
...
...
@@ -9,7 +9,8 @@ import { Position } from 'vs/editor/common/core/position';
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
PieceTreeTextBufferBuilder
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder
'
;
import
{
DefaultEndOfLine
}
from
'
vs/editor/common/model
'
;
import
{
PieceTreeBase
,
SENTINEL
,
NodeColor
,
TreeNode
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase
'
;
import
{
PieceTreeBase
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase
'
;
import
{
SENTINEL
,
NodeColor
,
TreeNode
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase
'
;
import
{
PieceTreeTextBuffer
}
from
'
vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer
'
;
const
alphabet
=
'
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
\r\n
'
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录