org.conqat.lib.commons.string.LineRangeStringParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of teamscale-lib-commons Show documentation
Show all versions of teamscale-lib-commons Show documentation
Provides common utility functions
package org.conqat.lib.commons.string;
import java.util.ArrayList;
import java.util.List;
import org.conqat.lib.commons.assertion.CCSMAssert;
import org.conqat.lib.commons.collections.CompactLines;
/**
* Parses a list of line numbers in the format like 1,3-5,8-10.
*
* We do the parsing in here manually as using StringTokenizer and {@link String#split(String)} is
* around 10-20x slower and produces a lot of pressure on the garbage collector.
*/
public class LineRangeStringParser {
/** The current (partial) line number. */
private int currentLine = 0;
/** The already parsed start line of a range while the end line is parsed. */
private int startLine = 0;
/**
* Whether the {@link #currentLine} refers to the start or end line number of a range.
*/
private boolean isParsingEndLine = false;
/**
* Parses a list of line numbers in the format like 1,3-5,8-10.
*
* @return A collection of integers, which are described by the given string
*/
public CompactLines parse(String lineNumbersString) {
reset();
CompactLines lineNumbers = new CompactLines();
for (int characterIndex = 0; characterIndex < lineNumbersString.length(); characterIndex++) {
char currentChar = lineNumbersString.charAt(characterIndex);
if (Character.isDigit(currentChar)) {
currentLine = currentLine * 10 + Character.digit(currentChar, 10);
} else if (currentChar == '-') {
if (isParsingEndLine) {
CCSMAssert.fail("Line number pattern at character " + characterIndex + " is invalid in: "
+ lineNumbersString);
}
startLine = currentLine;
currentLine = 0;
isParsingEndLine = true;
} else if (currentChar == ',') {
appendLines(lineNumbers);
reset();
} else if (!Character.isWhitespace(currentChar)) {
CCSMAssert.fail("Unexpected character " + currentChar + " in " + lineNumbersString);
}
}
appendLines(lineNumbers);
return lineNumbers;
}
/**
* Creates a list of {@link LineRange}s from a sorted and distinct plain list of line numbers.
*/
public static List compactifyToRanges(CompactLines lines) {
if (lines.isEmpty()) {
return new ArrayList<>();
}
int firstLine = lines.iterator().next();
LineRange currentRange = new LineRange(firstLine, firstLine);
List compactifiedRanges = new ArrayList<>();
compactifiedRanges.add(currentRange);
for (int currentLine : lines) {
if (currentRange.getEnd() == currentLine || currentRange.getEnd() == currentLine - 1) {
currentRange.setEnd(currentLine);
} else {
currentRange = new LineRange(currentLine, currentLine);
compactifiedRanges.add(currentRange);
}
}
return compactifiedRanges;
}
/** Parses the currently parsed line or line range to the lineNumbers. */
private void appendLines(CompactLines lineNumbers) {
if (currentLine == 0) {
return;
}
if (isParsingEndLine) {
lineNumbers.addRange(startLine, currentLine);
} else {
lineNumbers.add(currentLine);
}
}
/** Resets all internal parsing state. */
private void reset() {
currentLine = 0;
startLine = 0;
isParsingEndLine = false;
}
}