Path: blob/main/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts
5221 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' };2425// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any26export const lengthZero = 0 as any as Length;2728export function lengthIsZero(length: Length): boolean {29// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any30return length as any as number === 0;31}3233/*34* We have 52 bits available in a JS number.35* We use the upper 26 bits to store the line and the lower 26 bits to store the column.36*/37///*38const factor = 2 ** 26;39/*/40const factor = 1000000;41// */4243export function toLength(lineCount: number, columnCount: number): Length {44// llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)45// line count (26 bits) column count (26 bits)4647// If there is no overflow (all values/sums below 2^26 = 67108864),48// we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.4950// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any51return (lineCount * factor + columnCount) as any as Length;52}5354export function lengthToObj(length: Length): TextLength {55// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any56const l = length as any as number;57const lineCount = Math.floor(l / factor);58const columnCount = l - lineCount * factor;59return new TextLength(lineCount, columnCount);60}6162export function lengthGetLineCount(length: Length): number {63// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any64return Math.floor(length as any as number / factor);65}6667/**68* Returns the amount of columns of the given length, assuming that it does not span any line.69*/70export function lengthGetColumnCountIfZeroLineCount(length: Length): number {71// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any72return length as any as number;73}747576// [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]77// [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]78export function lengthAdd(length1: Length, length2: Length): Length;79// eslint-disable-next-line @typescript-eslint/no-explicit-any80export function lengthAdd(l1: any, l2: any): Length {81let r = l1 + l2;82if (l2 >= factor) { r = r - (l1 % factor); }83return r;84}8586export function sumLengths<T>(items: readonly T[], lengthFn: (item: T) => Length): Length {87return items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);88}8990export function lengthEquals(length1: Length, length2: Length): boolean {91return length1 === length2;92}9394/**95* Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.96*/97export function lengthDiffNonNegative(length1: Length, length2: Length): Length {98// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any99const l1 = length1 as any as number;100// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any101const l2 = length2 as any as number;102103const diff = l2 - l1;104if (diff <= 0) {105// line-count of length1 is higher than line-count of length2106// or they are equal and column-count of length1 is higher than column-count of length2107return lengthZero;108}109110const lineCount1 = Math.floor(l1 / factor);111const lineCount2 = Math.floor(l2 / factor);112113const colCount2 = l2 - lineCount2 * factor;114115if (lineCount1 === lineCount2) {116const colCount1 = l1 - lineCount1 * factor;117return toLength(0, colCount2 - colCount1);118} else {119return toLength(lineCount2 - lineCount1, colCount2);120}121}122123export function lengthLessThan(length1: Length, length2: Length): boolean {124// First, compare line counts, then column counts.125// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any126return (length1 as any as number) < (length2 as any as number);127}128129export function lengthLessThanEqual(length1: Length, length2: Length): boolean {130// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any131return (length1 as any as number) <= (length2 as any as number);132}133134export function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {135// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any136return (length1 as any as number) >= (length2 as any as number);137}138139export function lengthToPosition(length: Length): Position {140// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any141const l = length as any as number;142const lineCount = Math.floor(l / factor);143const colCount = l - lineCount * factor;144return new Position(lineCount + 1, colCount + 1);145}146147export function positionToLength(position: Position): Length {148return toLength(position.lineNumber - 1, position.column - 1);149}150151export function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {152// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any153const l = lengthStart as any as number;154const lineCount = Math.floor(l / factor);155const colCount = l - lineCount * factor;156157// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any158const l2 = lengthEnd as any as number;159const lineCount2 = Math.floor(l2 / factor);160const colCount2 = l2 - lineCount2 * factor;161162return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);163}164165export function lengthOfRange(range: Range): TextLength {166if (range.startLineNumber === range.endLineNumber) {167return new TextLength(0, range.endColumn - range.startColumn);168} else {169return new TextLength(range.endLineNumber - range.startLineNumber, range.endColumn - 1);170}171}172173export function lengthCompare(length1: Length, length2: Length): number {174// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any175const l1 = length1 as any as number;176// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any177const l2 = length2 as any as number;178return l1 - l2;179}180181export function lengthOfString(str: string): Length {182const lines = splitLines(str);183return toLength(lines.length - 1, lines[lines.length - 1].length);184}185186export function lengthOfStringObj(str: string): TextLength {187const lines = splitLines(str);188return new TextLength(lines.length - 1, lines[lines.length - 1].length);189}190191/**192* Computes a numeric hash of the given length.193*/194export function lengthHash(length: Length): number {195// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any196return length as any;197}198199export function lengthMax(length1: Length, length2: Length): Length {200return length1 > length2 ? length1 : length2;201}202203204