perf(ngcc): use line start positions for computing offsets in source-map flattening (#36027)

By computing and caching the start of each line, rather than the length
of each line, we can save a lot of duplicated computation in the `segmentDiff()`
and `offsetSegment()` functions.

PR Close #36027
This commit is contained in:
Pete Bacon Darwin
2020-03-11 12:17:36 +00:00
committed by Andrew Kushnir
parent a40be00e17
commit e8900824dd
4 changed files with 112 additions and 92 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {compareSegments, offsetSegment, segmentDiff} from '../../src/sourcemaps/segment_marker';
import {computeLineLengths} from '../../src/sourcemaps/source_file';
import {computeStartOfLinePositions} from '../../src/sourcemaps/source_file';
describe('SegmentMarker utils', () => {
describe('compareSegments()', () => {
@ -34,77 +34,99 @@ describe('SegmentMarker utils', () => {
describe('segmentDiff()', () => {
it('should return 0 if the segments are the same', () => {
const lineLengths = computeLineLengths('abcdef\nabcdefghj\nabcdefghijklm\nabcdef');
expect(segmentDiff(lineLengths, {line: 0, column: 0}, {line: 0, column: 0})).toEqual(0);
expect(segmentDiff(lineLengths, {line: 3, column: 0}, {line: 3, column: 0})).toEqual(0);
expect(segmentDiff(lineLengths, {line: 0, column: 5}, {line: 0, column: 5})).toEqual(0);
expect(segmentDiff(lineLengths, {line: 3, column: 5}, {line: 3, column: 5})).toEqual(0);
const startOfLinePositions =
computeStartOfLinePositions('abcdef\nabcdefghj\nabcdefghijklm\nabcdef');
expect(segmentDiff(startOfLinePositions, {line: 0, column: 0}, {line: 0, column: 0}))
.toEqual(0);
expect(segmentDiff(startOfLinePositions, {line: 3, column: 0}, {line: 3, column: 0}))
.toEqual(0);
expect(segmentDiff(startOfLinePositions, {line: 0, column: 5}, {line: 0, column: 5}))
.toEqual(0);
expect(segmentDiff(startOfLinePositions, {line: 3, column: 5}, {line: 3, column: 5}))
.toEqual(0);
});
it('should return the column difference if the markers are on the same line', () => {
const lineLengths = computeLineLengths('abcdef\nabcdefghj\nabcdefghijklm\nabcdef');
expect(segmentDiff(lineLengths, {line: 0, column: 0}, {line: 0, column: 3})).toEqual(3);
expect(segmentDiff(lineLengths, {line: 1, column: 1}, {line: 1, column: 5})).toEqual(4);
expect(segmentDiff(lineLengths, {line: 2, column: 5}, {line: 2, column: 1})).toEqual(-4);
expect(segmentDiff(lineLengths, {line: 3, column: 3}, {line: 3, column: 0})).toEqual(-3);
const startOfLinePositions =
computeStartOfLinePositions('abcdef\nabcdefghj\nabcdefghijklm\nabcdef');
expect(segmentDiff(startOfLinePositions, {line: 0, column: 0}, {line: 0, column: 3}))
.toEqual(3);
expect(segmentDiff(startOfLinePositions, {line: 1, column: 1}, {line: 1, column: 5}))
.toEqual(4);
expect(segmentDiff(startOfLinePositions, {line: 2, column: 5}, {line: 2, column: 1}))
.toEqual(-4);
expect(segmentDiff(startOfLinePositions, {line: 3, column: 3}, {line: 3, column: 0}))
.toEqual(-3);
});
it('should return the number of actual characters difference (including newlineLengths) if not on the same line',
it('should return the number of actual characters difference (including newline markers) if not on the same line',
() => {
let lineLengths: number[];
let startOfLinePositions: number[];
lineLengths = computeLineLengths('A12345\nB123456789');
expect(segmentDiff(lineLengths, {line: 0, column: 0}, {line: 1, column: 0}))
startOfLinePositions = computeStartOfLinePositions('A12345\nB123456789');
expect(segmentDiff(startOfLinePositions, {line: 0, column: 0}, {line: 1, column: 0}))
.toEqual(6 + 1);
lineLengths = computeLineLengths('012A45\n01234B6789');
expect(segmentDiff(lineLengths, {line: 0, column: 3}, {line: 1, column: 5}))
startOfLinePositions = computeStartOfLinePositions('012A45\n01234B6789');
expect(segmentDiff(startOfLinePositions, {line: 0, column: 3}, {line: 1, column: 5}))
.toEqual(3 + 1 + 5);
lineLengths = computeLineLengths('012345\n012345A789\n01234567\nB123456');
expect(segmentDiff(lineLengths, {line: 1, column: 6}, {line: 3, column: 0}))
startOfLinePositions =
computeStartOfLinePositions('012345\n012345A789\n01234567\nB123456');
expect(segmentDiff(startOfLinePositions, {line: 1, column: 6}, {line: 3, column: 0}))
.toEqual(4 + 1 + 8 + 1 + 0);
lineLengths = computeLineLengths('012345\nA123456789\n01234567\n012B456');
expect(segmentDiff(lineLengths, {line: 1, column: 0}, {line: 3, column: 3}))
startOfLinePositions =
computeStartOfLinePositions('012345\nA123456789\n01234567\n012B456');
expect(segmentDiff(startOfLinePositions, {line: 1, column: 0}, {line: 3, column: 3}))
.toEqual(10 + 1 + 8 + 1 + 3);
lineLengths = computeLineLengths('012345\nB123456789\nA1234567\n0123456');
expect(segmentDiff(lineLengths, {line: 2, column: 0}, {line: 1, column: 0}))
startOfLinePositions =
computeStartOfLinePositions('012345\nB123456789\nA1234567\n0123456');
expect(segmentDiff(startOfLinePositions, {line: 2, column: 0}, {line: 1, column: 0}))
.toEqual(0 - 1 - 10 + 0);
lineLengths = computeLineLengths('012345\n0123B56789\n01234567\n012A456');
expect(segmentDiff(lineLengths, {line: 3, column: 3}, {line: 1, column: 4}))
startOfLinePositions =
computeStartOfLinePositions('012345\n0123B56789\n01234567\n012A456');
expect(segmentDiff(startOfLinePositions, {line: 3, column: 3}, {line: 1, column: 4}))
.toEqual(-3 - 1 - 8 - 1 - 10 + 4);
lineLengths = computeLineLengths('B12345\n0123456789\n0123A567\n0123456');
expect(segmentDiff(lineLengths, {line: 2, column: 4}, {line: 0, column: 0}))
startOfLinePositions =
computeStartOfLinePositions('B12345\n0123456789\n0123A567\n0123456');
expect(segmentDiff(startOfLinePositions, {line: 2, column: 4}, {line: 0, column: 0}))
.toEqual(-4 - 1 - 10 - 1 - 6 + 0);
lineLengths = computeLineLengths('0123B5\n0123456789\nA1234567\n0123456');
expect(segmentDiff(lineLengths, {line: 2, column: 0}, {line: 0, column: 4}))
startOfLinePositions =
computeStartOfLinePositions('0123B5\n0123456789\nA1234567\n0123456');
expect(segmentDiff(startOfLinePositions, {line: 2, column: 0}, {line: 0, column: 4}))
.toEqual(0 - 1 - 10 - 1 - 6 + 4);
});
});
describe('offsetSegment()', () => {
it('should return an identical marker if offset is 0', () => {
const lineLengths = computeLineLengths('012345\n0123456789\n01234567\n0123456');
const startOfLinePositions =
computeStartOfLinePositions('012345\n0123456789\r\n01234567\n0123456');
const marker = {line: 2, column: 3};
expect(offsetSegment(lineLengths, marker, 0)).toBe(marker);
expect(offsetSegment(startOfLinePositions, marker, 0)).toBe(marker);
});
it('should return a new marker offset by the given chars', () => {
const lineLengths = computeLineLengths('012345\n0123456789\n012*4567\n0123456');
const startOfLinePositions =
computeStartOfLinePositions('012345\n0123456789\r\n012*4567\n0123456');
const marker = {line: 2, column: 3};
expect(offsetSegment(lineLengths, marker, 1)).toEqual({line: 2, column: 4});
expect(offsetSegment(lineLengths, marker, 2)).toEqual({line: 2, column: 5});
expect(offsetSegment(lineLengths, marker, 4)).toEqual({line: 2, column: 7});
expect(offsetSegment(lineLengths, marker, 8)).toEqual({line: 3, column: 2});
expect(offsetSegment(lineLengths, marker, -1)).toEqual({line: 2, column: 2});
expect(offsetSegment(lineLengths, marker, -2)).toEqual({line: 2, column: 1});
expect(offsetSegment(lineLengths, marker, -4)).toEqual({line: 1, column: 10});
expect(offsetSegment(lineLengths, marker, -6)).toEqual({line: 1, column: 8});
expect(offsetSegment(startOfLinePositions, marker, 1)).toEqual({line: 2, column: 4});
expect(offsetSegment(startOfLinePositions, marker, 2)).toEqual({line: 2, column: 5});
expect(offsetSegment(startOfLinePositions, marker, 4)).toEqual({line: 2, column: 7});
expect(offsetSegment(startOfLinePositions, marker, 6)).toEqual({line: 3, column: 0});
expect(offsetSegment(startOfLinePositions, marker, 8)).toEqual({line: 3, column: 2});
expect(offsetSegment(startOfLinePositions, marker, 20)).toEqual({line: 3, column: 14});
expect(offsetSegment(startOfLinePositions, marker, -1)).toEqual({line: 2, column: 2});
expect(offsetSegment(startOfLinePositions, marker, -2)).toEqual({line: 2, column: 1});
expect(offsetSegment(startOfLinePositions, marker, -3)).toEqual({line: 2, column: 0});
expect(offsetSegment(startOfLinePositions, marker, -4)).toEqual({line: 1, column: 10});
expect(offsetSegment(startOfLinePositions, marker, -6)).toEqual({line: 1, column: 8});
expect(offsetSegment(startOfLinePositions, marker, -16)).toEqual({line: 0, column: 5});
});
});
});

View File

@ -11,7 +11,7 @@ import {absoluteFrom} from '../../../src/ngtsc/file_system';
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
import {RawSourceMap} from '../../src/sourcemaps/raw_source_map';
import {SegmentMarker} from '../../src/sourcemaps/segment_marker';
import {Mapping, SourceFile, computeLineLengths, extractOriginalSegments, findLastMappingIndexBefore, parseMappings} from '../../src/sourcemaps/source_file';
import {Mapping, SourceFile, computeStartOfLinePositions, extractOriginalSegments, findLastMappingIndexBefore, parseMappings} from '../../src/sourcemaps/source_file';
runInEachFileSystem(() => {
describe('SourceFile and utilities', () => {
@ -482,17 +482,17 @@ runInEachFileSystem(() => {
});
});
describe('computeLineLengths()', () => {
it('should compute the length of each line in the given string', () => {
expect(computeLineLengths('')).toEqual([0]);
expect(computeLineLengths('abc')).toEqual([3]);
expect(computeLineLengths('\n')).toEqual([0, 0]);
expect(computeLineLengths('\n\n')).toEqual([0, 0, 0]);
expect(computeLineLengths('abc\n')).toEqual([3, 0]);
expect(computeLineLengths('\nabc')).toEqual([0, 3]);
expect(computeLineLengths('abc\ndefg')).toEqual([3, 4]);
expect(computeLineLengths('abc\r\n')).toEqual([3, 0]);
expect(computeLineLengths('abc\r\ndefg')).toEqual([3, 4]);
describe('computeStartOfLinePositions()', () => {
it('should compute the cumulative length of each line in the given string', () => {
expect(computeStartOfLinePositions('')).toEqual([0]);
expect(computeStartOfLinePositions('abc')).toEqual([0]);
expect(computeStartOfLinePositions('\n')).toEqual([0, 1]);
expect(computeStartOfLinePositions('\n\n')).toEqual([0, 1, 2]);
expect(computeStartOfLinePositions('abc\n')).toEqual([0, 4]);
expect(computeStartOfLinePositions('\nabc')).toEqual([0, 1]);
expect(computeStartOfLinePositions('abc\ndefg')).toEqual([0, 4]);
expect(computeStartOfLinePositions('abc\r\n')).toEqual([0, 4]);
expect(computeStartOfLinePositions('abc\r\ndefg')).toEqual([0, 4]);
});
});
});