diff --git a/debug/org.eclipse.cdt.debug.mi.core/src/org/eclipse/cdt/debug/mi/core/output/MIParser.java b/debug/org.eclipse.cdt.debug.mi.core/src/org/eclipse/cdt/debug/mi/core/output/MIParser.java index 8a1a767a89e..b4c8d6fb310 100644 --- a/debug/org.eclipse.cdt.debug.mi.core/src/org/eclipse/cdt/debug/mi/core/output/MIParser.java +++ b/debug/org.eclipse.cdt.debug.mi.core/src/org/eclipse/cdt/debug/mi/core/output/MIParser.java @@ -121,7 +121,7 @@ public class MIParser { if (token.charAt(0) == '^') { token.deleteCharAt(0); rr = processMIResultRecord(token, id); - } else if(token.toString().startsWith(MIOutput.terminator)) { + } else if (token.toString().startsWith(MIOutput.terminator)) { //break; // Do nothing. } else { MIOOBRecord band = processMIOOBRecord(token, id); @@ -166,7 +166,7 @@ public class MIParser { // Results are separated by commas. if (buffer.length() > 0 && buffer.charAt(0) == ',') { buffer.deleteCharAt(0); - MIResult[] res = processMIResults(buffer); + MIResult[] res = processMIResults(new FSB(buffer)); rr.setMIResults(res); } return rr; @@ -207,7 +207,7 @@ public class MIParser { async.setAsyncClass(buffer.toString().trim()); buffer.setLength(0); } - MIResult[] res = processMIResults(buffer); + MIResult[] res = processMIResults(new FSB(buffer)); async.setMIResults(res); oob = async; } else if (c == '~' || c == '@' || c == '&') { @@ -231,7 +231,7 @@ public class MIParser { if (buffer.length() > 0 && buffer.charAt(0) == '"') { buffer.deleteCharAt(0); } - stream.setCString(translateCString(buffer)); + stream.setCString(translateCString(new FSB(buffer))); oob = stream; } return oob; @@ -241,7 +241,7 @@ public class MIParser { * Assuming that the usual leading comma was consumed. * Extract the MI Result comma seperated responses. */ - private MIResult[] processMIResults(StringBuffer buffer) { + private MIResult[] processMIResults(FSB buffer) { List aList = new ArrayList(); MIResult result = processMIResult(buffer); if (result != null) { @@ -261,11 +261,10 @@ public class MIParser { * Construct the MIResult. Characters will be consume/delete * moving forward constructing the AST. */ - private MIResult processMIResult(StringBuffer buffer) { + private MIResult processMIResult(FSB buffer) { MIResult result = new MIResult(); int equal; - if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0)) - && (equal = buffer.toString().indexOf('=')) != -1) { + if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0)) && (equal = buffer.indexOf('=')) != -1) { String variable = buffer.substring(0, equal); result.setVariable(variable); buffer.delete(0, equal + 1); @@ -282,7 +281,7 @@ public class MIParser { /** * Find a MIValue implementation or return null. */ - private MIValue processMIValue(StringBuffer buffer) { + private MIValue processMIValue(FSB buffer) { MIValue value = null; if (buffer.length() > 0) { if (buffer.charAt(0) == '{') { @@ -306,7 +305,7 @@ public class MIParser { * go to the closing '}' consuming/deleting all the characters. * This is usually call by processMIvalue(); */ - private MIValue processMITuple(StringBuffer buffer) { + private MIValue processMITuple(FSB buffer) { MITuple tuple = new MITuple(); MIResult[] results = null; // Catch closing '}' @@ -327,7 +326,7 @@ public class MIParser { * Assuming the leading '[' was deleted, find the closing * ']' consuming/delete chars from the StringBuffer. */ - private MIValue processMIList(StringBuffer buffer) { + private MIValue processMIList(FSB buffer) { MIList list = new MIList(); List valueList = new ArrayList(); List resultList = new ArrayList(); @@ -337,7 +336,7 @@ public class MIParser { MIValue value = processMIValue(buffer); if (value != null) { valueList.add(value); - } else { + } else { MIResult result = processMIResult(buffer); if (result != null) { resultList.add(result); @@ -350,8 +349,8 @@ public class MIParser { if (buffer.length() > 0 && buffer.charAt(0) == ']') { buffer.deleteCharAt(0); } - MIValue[] values = (MIValue[])valueList.toArray(new MIValue[valueList.size()]); - MIResult[] res = (MIResult[])resultList.toArray(new MIResult[resultList.size()]); + MIValue[] values = (MIValue[]) valueList.toArray(new MIValue[valueList.size()]); + MIResult[] res = (MIResult[]) resultList.toArray(new MIResult[resultList.size()]); list.setMIValues(values); list.setMIResults(res); return list; @@ -365,7 +364,7 @@ public class MIParser { * backslach escaping and return the string __without__ the enclosing double quotes * The orignal StringBuffer will move forward. */ - private String translateCString(StringBuffer buffer) { + private String translateCString(FSB buffer) { boolean escape = false; boolean closingQuotes = false; @@ -383,7 +382,7 @@ public class MIParser { } } else if (c == '"') { if (escape) { - sb.append(c);; + sb.append(c); escape = false; } else { // Bail out. @@ -400,4 +399,111 @@ public class MIParser { buffer.delete(0, index); return sb.toString(); } + + /** + * Fast String Buffer class. MIParser does a lot + * of deleting off the front of a string, that's clearly + * an order N operation for StringBuffer which makes + * the MIParser an order N^2 operation. There are "issues" + * with this for large arrays. Use of FSB rather than String + * Buffer makes MIParser N rather than N^2 because FSB can + * delete from the front in constant time. + */ + public class FSB { + StringBuffer buf; + int pos; + boolean shared; + + public FSB(StringBuffer buf) { + this.buf = buf; + pos = 0; + shared = false; + } + + public FSB(FSB fbuf) { + pos = fbuf.pos; + buf = fbuf.buf; + shared = true; + } + + public int length() { + int res = buf.length() - pos; + if (res < 0) + return 0; + + return res; + } + + public char charAt(int index) { + return buf.charAt(index + pos); + } + + private void resolveCopy() { + if (shared) { + buf = new StringBuffer(buf.toString()); + shared = false; + } + } + + public FSB deleteCharAt(int index) { + if (index == 0) { + pos++; + } else { + resolveCopy(); + buf = buf.deleteCharAt(pos + index); + } + + return this; + } + + public FSB delete(int start, int end) { + if (start == 0) { + pos = pos + end - start; + } else { + resolveCopy(); + buf.delete(start + pos, end + pos); + } + + return this; + } + + public void setLength(int a) { + if (a == 0) + pos = buf.length(); + else { + // panic! fortunately we don't do this. + } + } + + public String substring(int start, int end) { + return buf.substring(start + pos, end + pos); + } + + public String toString() { + return buf.substring(pos, buf.length()); + } + + int indexOf(char c) { + int len = buf.length(); + for (int i = pos; i < len; i++) { + if (buf.charAt(i) == c) + return i - pos; + } + + return -1; + } + + boolean startsWith(String s) { + int len = Math.min(s.length(), length()); + if (len < s.length()) + return false; + + for (int i = 0; i < len; i++) { + if (s.charAt(i) != buf.charAt(pos + i)) + return false; + } + + return true; + } + } }