Path: blob/main/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { splitLines } from '../../../../../base/common/strings.js';6import { Position } from '../../../core/position.js';7import { Range } from '../../../core/range.js';8import { TextLength } from '../../../core/text/textLength.js';910/**11* The end must be greater than or equal to the start.12*/13export function lengthDiff(startLineCount: number, startColumnCount: number, endLineCount: number, endColumnCount: number): Length {14return (startLineCount !== endLineCount)15? toLength(endLineCount - startLineCount, endColumnCount)16: toLength(0, endColumnCount - startColumnCount);17}1819/**20* Represents a non-negative length in terms of line and column count.21* Does not allocate.22*/23export type Length = { _brand: 'Length' };2425export const lengthZero = 0 as any as Length;2627export function lengthIsZero(length: Length): boolean {28return length as any as number === 0;29}3031/*32* We have 52 bits available in a JS number.33* We use the upper 26 bits to store the line and the lower 26 bits to store the column.34*/35///*36const factor = 2 ** 26;37/*/38const factor = 1000000;39// */4041export function toLength(lineCount: number, columnCount: number): Length {42// llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)43// line count (26 bits) column count (26 bits)4445// If there is no overflow (all values/sums below 2^26 = 67108864),46// we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.4748return (lineCount * factor + columnCount) as any as Length;49}5051export function lengthToObj(length: Length): TextLength {52const l = length as any as number;53const lineCount = Math.floor(l / factor);54const columnCount = l - lineCount * factor;55return new TextLength(lineCount, columnCount);56}5758export function lengthGetLineCount(length: Length): number {59return Math.floor(length as any as number / factor);60}6162/**63* Returns the amount of columns of the given length, assuming that it does not span any line.64*/65export function lengthGetColumnCountIfZeroLineCount(length: Length): number {66return length as any as number;67}686970// [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]71// [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]72export function lengthAdd(length1: Length, length2: Length): Length;73export function lengthAdd(l1: any, l2: any): Length {74let r = l1 + l2;75if (l2 >= factor) { r = r - (l1 % factor); }76return r;77}7879export function sumLengths<T>(items: readonly T[], lengthFn: (item: T) => Length): Length {80return items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);81}8283export function lengthEquals(length1: Length, length2: Length): boolean {84return length1 === length2;85}8687/**88* Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.89*/90export function lengthDiffNonNegative(length1: Length, length2: Length): Length {91const l1 = length1 as any as number;92const l2 = length2 as any as number;9394const diff = l2 - l1;95if (diff <= 0) {96// line-count of length1 is higher than line-count of length297// or they are equal and column-count of length1 is higher than column-count of length298return lengthZero;99}100101const lineCount1 = Math.floor(l1 / factor);102const lineCount2 = Math.floor(l2 / factor);103104const colCount2 = l2 - lineCount2 * factor;105106if (lineCount1 === lineCount2) {107const colCount1 = l1 - lineCount1 * factor;108return toLength(0, colCount2 - colCount1);109} else {110return toLength(lineCount2 - lineCount1, colCount2);111}112}113114export function lengthLessThan(length1: Length, length2: Length): boolean {115// First, compare line counts, then column counts.116return (length1 as any as number) < (length2 as any as number);117}118119export function lengthLessThanEqual(length1: Length, length2: Length): boolean {120return (length1 as any as number) <= (length2 as any as number);121}122123export function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {124return (length1 as any as number) >= (length2 as any as number);125}126127export function lengthToPosition(length: Length): Position {128const l = length as any as number;129const lineCount = Math.floor(l / factor);130const colCount = l - lineCount * factor;131return new Position(lineCount + 1, colCount + 1);132}133134export function positionToLength(position: Position): Length {135return toLength(position.lineNumber - 1, position.column - 1);136}137138export function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {139const l = lengthStart as any as number;140const lineCount = Math.floor(l / factor);141const colCount = l - lineCount * factor;142143const l2 = lengthEnd as any as number;144const lineCount2 = Math.floor(l2 / factor);145const colCount2 = l2 - lineCount2 * factor;146147return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);148}149150export function lengthOfRange(range: Range): TextLength {151if (range.startLineNumber === range.endLineNumber) {152return new TextLength(0, range.endColumn - range.startColumn);153} else {154return new TextLength(range.endLineNumber - range.startLineNumber, range.endColumn - 1);155}156}157158export function lengthCompare(length1: Length, length2: Length): number {159const l1 = length1 as any as number;160const l2 = length2 as any as number;161return l1 - l2;162}163164export function lengthOfString(str: string): Length {165const lines = splitLines(str);166return toLength(lines.length - 1, lines[lines.length - 1].length);167}168169export function lengthOfStringObj(str: string): TextLength {170const lines = splitLines(str);171return new TextLength(lines.length - 1, lines[lines.length - 1].length);172}173174/**175* Computes a numeric hash of the given length.176*/177export function lengthHash(length: Length): number {178return length as any;179}180181export function lengthMax(length1: Length, length2: Length): Length {182return length1 > length2 ? length1 : length2;183}184185186