forked from M3-Academy/challenge-algorithms-v2.0
131 lines
16 KiB
JavaScript
131 lines
16 KiB
JavaScript
|
import { compareRangeCovs } from "./compare";
|
||
|
export function emitForest(trees) {
|
||
|
return emitForestLines(trees).join("\n");
|
||
|
}
|
||
|
export function emitForestLines(trees) {
|
||
|
const colMap = getColMap(trees);
|
||
|
const header = emitOffsets(colMap);
|
||
|
return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))];
|
||
|
}
|
||
|
function getColMap(trees) {
|
||
|
const eventSet = new Set();
|
||
|
for (const tree of trees) {
|
||
|
const stack = [tree];
|
||
|
while (stack.length > 0) {
|
||
|
const cur = stack.pop();
|
||
|
eventSet.add(cur.start);
|
||
|
eventSet.add(cur.end);
|
||
|
for (const child of cur.children) {
|
||
|
stack.push(child);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const events = [...eventSet];
|
||
|
events.sort((a, b) => a - b);
|
||
|
let maxDigits = 1;
|
||
|
for (const event of events) {
|
||
|
maxDigits = Math.max(maxDigits, event.toString(10).length);
|
||
|
}
|
||
|
const colWidth = maxDigits + 3;
|
||
|
const colMap = new Map();
|
||
|
for (const [i, event] of events.entries()) {
|
||
|
colMap.set(event, i * colWidth);
|
||
|
}
|
||
|
return colMap;
|
||
|
}
|
||
|
function emitTree(tree, colMap) {
|
||
|
const layers = [];
|
||
|
let nextLayer = [tree];
|
||
|
while (nextLayer.length > 0) {
|
||
|
const layer = nextLayer;
|
||
|
layers.push(layer);
|
||
|
nextLayer = [];
|
||
|
for (const node of layer) {
|
||
|
for (const child of node.children) {
|
||
|
nextLayer.push(child);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return layers.map(layer => emitTreeLayer(layer, colMap));
|
||
|
}
|
||
|
export function parseFunctionRanges(text, offsetMap) {
|
||
|
const result = [];
|
||
|
for (const line of text.split("\n")) {
|
||
|
for (const range of parseTreeLayer(line, offsetMap)) {
|
||
|
result.push(range);
|
||
|
}
|
||
|
}
|
||
|
result.sort(compareRangeCovs);
|
||
|
return result;
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param layer Sorted list of disjoint trees.
|
||
|
* @param colMap
|
||
|
*/
|
||
|
function emitTreeLayer(layer, colMap) {
|
||
|
const line = [];
|
||
|
let curIdx = 0;
|
||
|
for (const { start, end, count } of layer) {
|
||
|
const startIdx = colMap.get(start);
|
||
|
const endIdx = colMap.get(end);
|
||
|
if (startIdx > curIdx) {
|
||
|
line.push(" ".repeat(startIdx - curIdx));
|
||
|
}
|
||
|
line.push(emitRange(count, endIdx - startIdx));
|
||
|
curIdx = endIdx;
|
||
|
}
|
||
|
return line.join("");
|
||
|
}
|
||
|
function parseTreeLayer(text, offsetMap) {
|
||
|
const result = [];
|
||
|
const regex = /\[(\d+)-*\)/gs;
|
||
|
while (true) {
|
||
|
const match = regex.exec(text);
|
||
|
if (match === null) {
|
||
|
break;
|
||
|
}
|
||
|
const startIdx = match.index;
|
||
|
const endIdx = startIdx + match[0].length;
|
||
|
const count = parseInt(match[1], 10);
|
||
|
const startOffset = offsetMap.get(startIdx);
|
||
|
const endOffset = offsetMap.get(endIdx);
|
||
|
if (startOffset === undefined || endOffset === undefined) {
|
||
|
throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`);
|
||
|
}
|
||
|
result.push({ startOffset, endOffset, count });
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
function emitRange(count, len) {
|
||
|
const rangeStart = `[${count.toString(10)}`;
|
||
|
const rangeEnd = ")";
|
||
|
const hyphensLen = len - (rangeStart.length + rangeEnd.length);
|
||
|
const hyphens = "-".repeat(Math.max(0, hyphensLen));
|
||
|
return `${rangeStart}${hyphens}${rangeEnd}`;
|
||
|
}
|
||
|
function emitOffsets(colMap) {
|
||
|
let line = "";
|
||
|
for (const [event, col] of colMap) {
|
||
|
if (line.length < col) {
|
||
|
line += " ".repeat(col - line.length);
|
||
|
}
|
||
|
line += event.toString(10);
|
||
|
}
|
||
|
return line;
|
||
|
}
|
||
|
export function parseOffsets(text) {
|
||
|
const result = new Map();
|
||
|
const regex = /\d+/gs;
|
||
|
while (true) {
|
||
|
const match = regex.exec(text);
|
||
|
if (match === null) {
|
||
|
break;
|
||
|
}
|
||
|
result.set(match.index, parseInt(match[0], 10));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//# sourceMappingURL=data:application/json;charset=utf8;base64,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
|