Improves performance of concat23Trees

上级 02e94bc1
......@@ -163,7 +163,7 @@ function computeLength(openingBracket: BracketAstNode, child: AstNode | null, cl
}
export class ListAstNode extends BaseAstNode {
public static create(items: AstNode[]) {
public static create(items: AstNode[]): ListAstNode {
if (items.length === 0) {
return new ListAstNode(lengthZero, 0, items, SmallImmutableSet.getEmpty());
} else {
......
......@@ -19,30 +19,59 @@ export function concat23Trees(items: AstNode[]): AstNode | null {
return items[0];
}
if (allItemsHaveSameHeight(items)) {
return concatFast(items);
let i = 0;
function readNode(): AstNode | null {
if (i >= items.length) {
return null;
}
const start = i;
const height = items[start].listHeight;
i++;
while (i < items.length && items[i].listHeight === height) {
i++;
}
if (i - start >= 2) {
return concat23TreesOfSameHeight(start === 0 && i === items.length ? items : items.slice(start, i));
} else {
return items[start];
}
}
return concatSlow(items);
}
/**
* @param items must be non empty.
*/
function allItemsHaveSameHeight(items: AstNode[]): boolean {
const firstHeight = items[0].listHeight;
// The items might not have the same height.
// We merge all items by using a binary concat operator.
let first = readNode()!; // There must be a first item
let second = readNode();
if (!second) {
return first;
}
for (const item of items) {
if (item.listHeight !== firstHeight) {
return false;
for (let item = readNode(); item; item = readNode()) {
// Prefer concatenating smaller trees, as the runtime of concat depends on the tree height.
if (heightDiff(first, second) <= heightDiff(second, item)) {
first = concat(first, second);
second = item;
} else {
second = concat(second, item);
}
}
return true;
const result = concat(first, second);
return result;
}
function concatFast(items: AstNode[]): AstNode | null {
export function concat23TreesOfSameHeight(items: AstNode[]): AstNode | null {
if (items.length === 0) {
return null;
}
if (items.length === 1) {
return items[0];
}
let length = items.length;
// All trees have same height, just create parent nodes.
while (length > 1) {
while (length > 3) {
const newLength = length >> 1;
// Ideally, due to the slice, not a lot of memory is wasted.
const newItems = new Array<AstNode>(newLength);
......@@ -53,34 +82,13 @@ function concatFast(items: AstNode[]): AstNode | null {
length = newLength;
items = newItems;
}
return items[0];
return ListAstNode.create(items);
}
function heightDiff(node1: AstNode, node2: AstNode): number {
return Math.abs(node1.listHeight - node2.listHeight);
}
function concatSlow(items: AstNode[]): AstNode | null {
// The items might not have the same height.
// We merge all items by using a binary concat operator.
let first = items[0];
let second = items[1];
for (let i = 2; i < items.length; i++) {
const item = items[i];
// Prefer concatenating smaller trees, as the runtime of concat depends on the tree height.
if (heightDiff(first, second) <= heightDiff(second, item)) {
first = concat(first, second);
second = item;
} else {
second = concat(second, item);
}
}
const result = concat(first, second);
return result;
}
function concat(node1: AstNode, node2: AstNode): AstNode {
if (node1.listHeight === node2.listHeight) {
return ListAstNode.create([node1, node2]);
......
......@@ -7,7 +7,7 @@ import { AstNode, AstNodeKind, BracketAstNode, InvalidBracketAstNode, ListAstNod
import { BeforeEditPositionMapper, TextEditInfo } from './beforeEditPositionMapper';
import { SmallImmutableSet } from './smallImmutableSet';
import { lengthGetLineCount, lengthIsZero, lengthLessThanEqual } from './length';
import { concat23Trees } from './concat23Trees';
import { concat23Trees, concat23TreesOfSameHeight } from './concat23Trees';
import { NodeReader } from './nodeReader';
import { OpeningBracketId, Tokenizer, TokenKind } from './tokenizer';
......@@ -80,7 +80,8 @@ class Parser {
items.push(child);
}
const result = concat23Trees(items);
// When there is no oldNodeReader, all items are created from scratch and must have the same height.
const result = this.oldNodeReader ? concat23Trees(items) : concat23TreesOfSameHeight(items);
return result;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册