Improve VariableMap.forBytes performance
@@ -21,7 +21,6 @@ import static java.util.Map.Entry.comparingByKey;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
@@ -122,23 +121,30 @@ public final class VariableMap {
return baos.toByteArray();
}
- @GwtIncompatible("com.google.common.base.Splitter.onPattern()")
- private static final Splitter LINE_SPLITTER
- = Splitter.onPattern("\\r?\\n").omitEmptyStrings();
-
/**
* Deserializes the variable map from a byte array returned by
* {@link #toBytes()}.
*/
@GwtIncompatible("com.google.common.base.Splitter.onPattern()")
public static VariableMap fromBytes(byte[] bytes) throws ParseException {
- Iterable<String> lines = LINE_SPLITTER.split(
- new String(bytes, UTF_8));
-
+ String string = new String(bytes, UTF_8);
ImmutableMap.Builder<String, String> map = ImmutableMap.builder();
-
- for (String line : lines) {
- int pos = findIndexOfChar(line, SEPARATOR);
+ int startOfLine = 0;
+ while (startOfLine < string.length()) {
+ int newLine = string.indexOf('\n', startOfLine);
+ if (newLine == -1) {
+ newLine = string.length();
+ }
+ int endOfLine = newLine;
+ if (string.charAt(newLine - 1) == '\r') {
+ newLine--;
+ }
+ String line = string.substring(startOfLine, newLine);
+ startOfLine = endOfLine + 1; // update index for next iteration
+ if (line.isEmpty()) {
+ continue;
+ }
+ int pos = findIndexOfUnescapedChar(line, SEPARATOR);
if (pos <= 0) {
throw new ParseException("Bad line: " + line, 0);
}
@@ -155,23 +161,31 @@ public final class VariableMap {
.replace("\n", "\\n");
}
- private static int findIndexOfChar(String value, char stopChar) {
+ private static int findIndexOfUnescapedChar(String value, char stopChar) {
int len = value.length();
- for (int i = 0; i < len; i++) {
- char c = value.charAt(i);
- if (c == '\\' && ++i < len) {
- c = value.charAt(i);
- } else if (c == stopChar){
- return i;
+ for (int i = 0; i < len; ) {
+ int stopCharIndex = value.indexOf(stopChar, i);
+ if (stopCharIndex == -1) {
+ return -1;
}
+ if (value.charAt(stopCharIndex - 1) != '\\') {
+ // it isn't escaped, return
+ return stopCharIndex;
+ }
+ i = stopCharIndex + 1;
}
return -1;
}
- private static String unescape(CharSequence value) {
- StringBuilder sb = new StringBuilder();
+ private static String unescape(String value) {
+ int slashIndex = value.indexOf('\\');
+ if (slashIndex == -1) {
+ return value;
+ }
+ StringBuilder sb = new StringBuilder(value.length() - 1);
+ sb.append(value, 0, slashIndex);
int len = value.length();
- for (int i = 0; i < len; i++) {
+ for (int i = slashIndex; i < len; i++) {
char c = value.charAt(i);
if (c == '\\' && ++i < len) {
c = value.charAt(i);
