提交 e52476e7 编写于 作者: R redestad

8224202: Speed up Properties.load

Reviewed-by: rriggs, igerasim
上级 6b125420
......@@ -404,17 +404,15 @@ class Properties extends Hashtable<Object,Object> {
load0(new LineReader(inStream));
}
private void load0 (LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
private void load0(LineReader lr) throws IOException {
StringBuilder outBuffer = new StringBuilder();
int limit;
int keyLen;
int valueStart;
char c;
boolean hasSep;
boolean precedingBackslash;
while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
......@@ -422,7 +420,7 @@ class Properties extends Hashtable<Object,Object> {
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false;
while (keyLen < limit) {
c = lr.lineBuf[keyLen];
char c = lr.lineBuf[keyLen];
//need check if escaped.
if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
......@@ -440,7 +438,7 @@ class Properties extends Hashtable<Object,Object> {
keyLen++;
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
char c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
......@@ -450,8 +448,8 @@ class Properties extends Hashtable<Object,Object> {
}
valueStart++;
}
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
String key = loadConvert(lr.lineBuf, 0, keyLen, outBuffer);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, outBuffer);
put(key, value);
}
}
......@@ -462,64 +460,56 @@ class Properties extends Hashtable<Object,Object> {
* Method returns the char length of the "logical line" and stores
* the line in "lineBuf".
*/
class LineReader {
public LineReader(InputStream inStream) {
private static class LineReader {
LineReader(InputStream inStream) {
this.inStream = inStream;
inByteBuf = new byte[8192];
}
public LineReader(Reader reader) {
LineReader(Reader reader) {
this.reader = reader;
inCharBuf = new char[8192];
}
byte[] inByteBuf;
char[] inCharBuf;
char[] lineBuf = new char[1024];
int inLimit = 0;
int inOff = 0;
InputStream inStream;
Reader reader;
private byte[] inByteBuf;
private char[] inCharBuf;
private int inLimit = 0;
private int inOff = 0;
private InputStream inStream;
private Reader reader;
int readLine() throws IOException {
// use locals to optimize for interpreted performance
int len = 0;
char c = 0;
int off = inOff;
int limit = inLimit;
boolean skipWhiteSpace = true;
boolean isCommentLine = false;
boolean isNewLine = true;
boolean appendedLineBegin = false;
boolean precedingBackslash = false;
boolean skipLF = false;
boolean fromStream = inStream != null;
byte[] byteBuf = inByteBuf;
char[] charBuf = inCharBuf;
char[] lineBuf = this.lineBuf;
char c;
while (true) {
if (inOff >= inLimit) {
inLimit = (inStream==null)?reader.read(inCharBuf)
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {
if (len == 0 || isCommentLine) {
if (off >= limit) {
inLimit = limit = fromStream ? inStream.read(byteBuf)
: reader.read(charBuf);
if (limit <= 0) {
if (len == 0) {
return -1;
}
if (precedingBackslash) {
len--;
}
return len;
}
}
if (inStream != null) {
//The line below is equivalent to calling a
//ISO8859-1 decoder.
c = (char)(inByteBuf[inOff++] & 0xFF);
} else {
c = inCharBuf[inOff++];
}
if (skipLF) {
skipLF = false;
if (c == '\n') {
continue;
return precedingBackslash ? len - 1 : len;
}
off = 0;
}
// (char)(byte & 0xFF) is equivalent to calling a ISO8859-1 decoder.
c = (fromStream) ? (char)(byteBuf[off++] & 0xFF) : charBuf[off++];
if (skipWhiteSpace) {
if (c == ' ' || c == '\t' || c == '\f') {
continue;
......@@ -529,81 +519,106 @@ class Properties extends Hashtable<Object,Object> {
}
skipWhiteSpace = false;
appendedLineBegin = false;
}
if (isNewLine) {
isNewLine = false;
if (len == 0) { // Still on a new logical line
if (c == '#' || c == '!') {
// Comment, quickly consume the rest of the line,
// resume on line-break and backslash.
if (inStream != null) {
while (inOff < inLimit) {
byte b = inByteBuf[inOff++];
if (b == '\n' || b == '\r' || b == '\\') {
c = (char)(b & 0xFF);
break;
// Comment, quickly consume the rest of the line
// When checking for new line characters a range check,
// starting with the higher bound ('\r') means one less
// branch in the common case.
commentLoop: while (true) {
if (fromStream) {
byte b;
while (off < limit) {
b = byteBuf[off++];
if (b <= '\r' && (b == '\r' || b == '\n'))
break commentLoop;
}
}
} else {
while (inOff < inLimit) {
c = inCharBuf[inOff++];
if (c == '\n' || c == '\r' || c == '\\') {
break;
if (off == limit) {
inLimit = limit = inStream.read(byteBuf);
if (limit <= 0) { // EOF
return -1;
}
off = 0;
}
} else {
while (off < limit) {
c = charBuf[off++];
if (c <= '\r' && (c == '\r' || c == '\n'))
break commentLoop;
}
if (off == limit) {
inLimit = limit = reader.read(charBuf);
if (limit <= 0) { // EOF
return -1;
}
off = 0;
}
}
}
isCommentLine = true;
skipWhiteSpace = true;
continue;
}
}
if (c != '\n' && c != '\r') {
lineBuf[len++] = c;
if (len == lineBuf.length) {
int newLength = lineBuf.length * 2;
if (newLength < 0) {
newLength = Integer.MAX_VALUE;
int maxLen = Integer.MAX_VALUE - 8; // VM allocation limit
int newLen = len * 2;
if (newLen < 0 || newLen > maxLen) { // check for under/overflow
newLen = maxLen;
}
char[] buf = new char[newLength];
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
lineBuf = buf;
}
//flip the preceding backslash flag
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
if (newLen <= len) { // still not good? last-ditch attempt then
if (len != Integer.MAX_VALUE) {
newLen = len + 1;
} else {
throw new OutOfMemoryError("Required array length too large");
}
}
lineBuf = new char[newLen];
System.arraycopy(this.lineBuf, 0, lineBuf, 0, len);
this.lineBuf = lineBuf;
}
}
else {
// flip the preceding backslash flag
precedingBackslash = (c == '\\') ? !precedingBackslash : false;
} else {
// reached EOL
if (isCommentLine || len == 0) {
isCommentLine = false;
isNewLine = true;
if (len == 0) {
skipWhiteSpace = true;
len = 0;
continue;
}
if (inOff >= inLimit) {
inLimit = (inStream==null)
?reader.read(inCharBuf)
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {
if (precedingBackslash) {
len--;
}
return len;
if (off >= limit) {
inLimit = limit = fromStream ? inStream.read(byteBuf)
: reader.read(charBuf);
off = 0;
if (limit <= 0) { // EOF
return precedingBackslash ? len - 1 : len;
}
}
if (precedingBackslash) {
// backslash at EOL is not part of the line
len -= 1;
//skip the leading whitespace characters in following line
// skip leading whitespace characters in the following line
skipWhiteSpace = true;
appendedLineBegin = true;
precedingBackslash = false;
// take care not to include any subsequent \n
if (c == '\r') {
skipLF = true;
if (fromStream) {
if (byteBuf[off] == '\n') {
off++;
}
} else {
if (charBuf[off] == '\n') {
off++;
}
}
}
} else {
inOff = off;
return len;
}
}
......@@ -615,18 +630,24 @@ class Properties extends Hashtable<Object,Object> {
* Converts encoded &#92;uxxxx to unicode chars
* and changes special saved chars to their original forms
*/
private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
if (convtBuf.length < len) {
int newLen = len * 2;
if (newLen < 0) {
newLen = Integer.MAX_VALUE;
}
convtBuf = new char[newLen];
}
private String loadConvert(char[] in, int off, int len, StringBuilder out) {
char aChar;
char[] out = convtBuf;
int outLen = 0;
int end = off + len;
int start = off;
while (off < end) {
aChar = in[off++];
if (aChar == '\\') {
break;
}
}
if (off == end) { // No backslash
return new String(in, start, len);
}
// backslash found at off - 1, reset the shared buffer, rewind offset
out.setLength(0);
off--;
out.append(in, start, off - start);
while (off < end) {
aChar = in[off++];
......@@ -654,20 +675,20 @@ class Properties extends Hashtable<Object,Object> {
throw new IllegalArgumentException(
"Malformed \\uxxxx encoding.");
}
}
out[outLen++] = (char)value;
}
out.append((char)value);
} else {
if (aChar == 't') aChar = '\t';
else if (aChar == 'r') aChar = '\r';
else if (aChar == 'n') aChar = '\n';
else if (aChar == 'f') aChar = '\f';
out[outLen++] = aChar;
out.append(aChar);
}
} else {
out[outLen++] = aChar;
out.append(aChar);
}
}
return new String (out, 0, outLen);
return out.toString();
}
/*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册