faststringbuffer.java
来自「JAVA 所有包」· Java 代码 · 共 1,295 行 · 第 1/3 页
JAVA
1,295 行
if (startColumn + length < m_chunkMask && m_innerFSB == null) { return getOneChunkString(startChunk, startColumn, length); } return getString(new StringBuffer(length), startChunk, startColumn, length).toString(); } protected String getOneChunkString(int startChunk, int startColumn, int length) { return new String(m_array[startChunk], startColumn, length); } /** * @param sb StringBuffer to be appended to * @param start Offset of first character in the range. * @param length Number of characters to send. * @return sb with the requested text appended to it */ StringBuffer getString(StringBuffer sb, int start, int length) { return getString(sb, start >>> m_chunkBits, start & m_chunkMask, length); } /** * Internal support for toString() and getString(). * PLEASE NOTE SIGNATURE CHANGE from earlier versions; it now appends into * and returns a StringBuffer supplied by the caller. This simplifies * m_innerFSB support. * <p> * Note that this operation has been somewhat deoptimized by the shift to a * chunked array, as there is no factory method to produce a String object * directly from an array of arrays and hence a double copy is needed. * By presetting length we hope to minimize the heap overhead of building * the intermediate StringBuffer. * <p> * (It really is a pity that Java didn't design String as a final subclass * of MutableString, rather than having StringBuffer be a separate hierarchy. * We'd avoid a <strong>lot</strong> of double-buffering.) * * * @param sb * @param startChunk * @param startColumn * @param length * * @return the contents of the FastStringBuffer as a standard Java string. */ StringBuffer getString(StringBuffer sb, int startChunk, int startColumn, int length) { int stop = (startChunk << m_chunkBits) + startColumn + length; int stopChunk = stop >>> m_chunkBits; int stopColumn = stop & m_chunkMask; // Factored out //StringBuffer sb=new StringBuffer(length); for (int i = startChunk; i < stopChunk; ++i) { if (i == 0 && m_innerFSB != null) m_innerFSB.getString(sb, startColumn, m_chunkSize - startColumn); else sb.append(m_array[i], startColumn, m_chunkSize - startColumn); startColumn = 0; // after first chunk } if (stopChunk == 0 && m_innerFSB != null) m_innerFSB.getString(sb, startColumn, stopColumn - startColumn); else if (stopColumn > startColumn) sb.append(m_array[stopChunk], startColumn, stopColumn - startColumn); return sb; } /** * Get a single character from the string buffer. * * * @param pos character position requested. * @return A character from the requested position. */ public char charAt(int pos) { int startChunk = pos >>> m_chunkBits; if (startChunk == 0 && m_innerFSB != null) return m_innerFSB.charAt(pos & m_chunkMask); else return m_array[startChunk][pos & m_chunkMask]; } /** * Sends the specified range of characters as one or more SAX characters() * events. * Note that the buffer reference passed to the ContentHandler may be * invalidated if the FastStringBuffer is edited; it's the user's * responsibility to manage access to the FastStringBuffer to prevent this * problem from arising. * <p> * Note too that there is no promise that the output will be sent as a * single call. As is always true in SAX, one logical string may be split * across multiple blocks of memory and hence delivered as several * successive events. * * @param ch SAX ContentHandler object to receive the event. * @param start Offset of first character in the range. * @param length Number of characters to send. * @exception org.xml.sax.SAXException may be thrown by handler's * characters() method. */ public void sendSAXcharacters( org.xml.sax.ContentHandler ch, int start, int length) throws org.xml.sax.SAXException { int startChunk = start >>> m_chunkBits; int startColumn = start & m_chunkMask; if (startColumn + length < m_chunkMask && m_innerFSB == null) { ch.characters(m_array[startChunk], startColumn, length); return; } int stop = start + length; int stopChunk = stop >>> m_chunkBits; int stopColumn = stop & m_chunkMask; for (int i = startChunk; i < stopChunk; ++i) { if (i == 0 && m_innerFSB != null) m_innerFSB.sendSAXcharacters(ch, startColumn, m_chunkSize - startColumn); else ch.characters(m_array[i], startColumn, m_chunkSize - startColumn); startColumn = 0; // after first chunk } // Last, or only, chunk if (stopChunk == 0 && m_innerFSB != null) m_innerFSB.sendSAXcharacters(ch, startColumn, stopColumn - startColumn); else if (stopColumn > startColumn) { ch.characters(m_array[stopChunk], startColumn, stopColumn - startColumn); } } /** * Sends the specified range of characters as one or more SAX characters() * events, normalizing the characters according to XSLT rules. * * @param ch SAX ContentHandler object to receive the event. * @param start Offset of first character in the range. * @param length Number of characters to send. * @return normalization status to apply to next chunk (because we may * have been called recursively to process an inner FSB): * <dl> * <dt>0</dt> * <dd>if this output did not end in retained whitespace, and thus whitespace * at the start of the following chunk (if any) should be converted to a * single space. * <dt>SUPPRESS_LEADING_WS</dt> * <dd>if this output ended in retained whitespace, and thus whitespace * at the start of the following chunk (if any) should be completely * suppressed.</dd> * </dd> * </dl> * @exception org.xml.sax.SAXException may be thrown by handler's * characters() method. */ public int sendNormalizedSAXcharacters( org.xml.sax.ContentHandler ch, int start, int length) throws org.xml.sax.SAXException { // This call always starts at the beginning of the // string being written out, either because it was called directly or // because it was an m_innerFSB recursion. This is important since // it gives us a well-known initial state for this flag: int stateForNextChunk=SUPPRESS_LEADING_WS; int stop = start + length; int startChunk = start >>> m_chunkBits; int startColumn = start & m_chunkMask; int stopChunk = stop >>> m_chunkBits; int stopColumn = stop & m_chunkMask; for (int i = startChunk; i < stopChunk; ++i) { if (i == 0 && m_innerFSB != null) stateForNextChunk= m_innerFSB.sendNormalizedSAXcharacters(ch, startColumn, m_chunkSize - startColumn); else stateForNextChunk= sendNormalizedSAXcharacters(m_array[i], startColumn, m_chunkSize - startColumn, ch,stateForNextChunk); startColumn = 0; // after first chunk } // Last, or only, chunk if (stopChunk == 0 && m_innerFSB != null) stateForNextChunk= // %REVIEW% Is this update really needed? m_innerFSB.sendNormalizedSAXcharacters(ch, startColumn, stopColumn - startColumn); else if (stopColumn > startColumn) { stateForNextChunk= // %REVIEW% Is this update really needed? sendNormalizedSAXcharacters(m_array[stopChunk], startColumn, stopColumn - startColumn, ch, stateForNextChunk | SUPPRESS_TRAILING_WS); } return stateForNextChunk; } static final char[] SINGLE_SPACE = {' '}; /** * Internal method to directly normalize and dispatch the character array. * This version is aware of the fact that it may be called several times * in succession if the data is made up of multiple "chunks", and thus * must actively manage the handling of leading and trailing whitespace. * * Note: The recursion is due to the possible recursion of inner FSBs. * * @param ch The characters from the XML document. * @param start The start position in the array. * @param length The number of characters to read from the array. * @param handler SAX ContentHandler object to receive the event. * @param edgeTreatmentFlags How leading/trailing spaces should be handled. * This is a bitfield contining two flags, bitwise-ORed together: * <dl> * <dt>SUPPRESS_LEADING_WS</dt> * <dd>When false, causes leading whitespace to be converted to a single * space; when true, causes it to be discarded entirely. * Should be set TRUE for the first chunk, and (in multi-chunk output) * whenever the previous chunk ended in retained whitespace.</dd> * <dt>SUPPRESS_TRAILING_WS</dt> * <dd>When false, causes trailing whitespace to be converted to a single * space; when true, causes it to be discarded entirely. * Should be set TRUE for the last or only chunk. * </dd> * </dl> * @return normalization status, as in the edgeTreatmentFlags parameter: * <dl> * <dt>0</dt> * <dd>if this output did not end in retained whitespace, and thus whitespace * at the start of the following chunk (if any) should be converted to a * single space. * <dt>SUPPRESS_LEADING_WS</dt> * <dd>if this output ended in retained whitespace, and thus whitespace * at the start of the following chunk (if any) should be completely * suppressed.</dd> * </dd> * </dl> * * * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. */ static int sendNormalizedSAXcharacters(char ch[], int start, int length, org.xml.sax.ContentHandler handler, int edgeTreatmentFlags) throws org.xml.sax.SAXException { boolean processingLeadingWhitespace = ((edgeTreatmentFlags & SUPPRESS_LEADING_WS) != 0); boolean seenWhitespace = ((edgeTreatmentFlags & CARRY_WS) != 0); boolean suppressTrailingWhitespace = ((edgeTreatmentFlags & SUPPRESS_TRAILING_WS) != 0); int currPos = start; int limit = start+length; // Strip any leading spaces first, if required if (processingLeadingWhitespace) { for (; currPos < limit && XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); currPos++) { } // If we've only encountered leading spaces, the // current state remains unchanged if (currPos == limit) { return edgeTreatmentFlags; } } // If we get here, there are no more leading spaces to strip while (currPos < limit) { int startNonWhitespace = currPos; // Grab a chunk of non-whitespace characters for (; currPos < limit && !XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); currPos++) { } // Non-whitespace seen - emit them, along with a single // space for any preceding whitespace characters if (startNonWhitespace != currPos) { if (seenWhitespace) { handler.characters(SINGLE_SPACE, 0, 1); seenWhitespace = false; } handler.characters(ch, startNonWhitespace, currPos - startNonWhitespace); } int startWhitespace = currPos; // Consume any whitespace characters for (; currPos < limit && XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); currPos++) { } if (startWhitespace != currPos) { seenWhitespace = true; } } return (seenWhitespace ? CARRY_WS : 0) | (edgeTreatmentFlags & SUPPRESS_TRAILING_WS); } /** * Directly normalize and dispatch the character array. * * @param ch The characters from the XML document. * @param start The start position in the array. * @param length The number of characters to read from the array. * @param handler SAX ContentHandler object to receive the event. * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. */ public static void sendNormalizedSAXcharacters(char ch[], int start, int length, org.xml.sax.ContentHandler handler) throws org.xml.sax.SAXException { sendNormalizedSAXcharacters(ch, start, length, handler, SUPPRESS_BOTH); } /** * Sends the specified range of characters as sax Comment. * <p> * Note that, unlike sendSAXcharacters, this has to be done as a single * call to LexicalHandler#comment. * * @param ch SAX LexicalHandler object to receive the event. * @param start Offset of first character in the range. * @param length Number of characters to send. * @exception org.xml.sax.SAXException may be thrown by handler's * characters() method. */ public void sendSAXComment( org.xml.sax.ext.LexicalHandler ch, int start, int length) throws org.xml.sax.SAXException { // %OPT% Do it this way for now... String comment = getString(start, length); ch.comment(comment.toCharArray(), 0, length); } /** * Copies characters from this string into the destination character * array. * * @param srcBegin index of the first character in the string * to copy. * @param srcEnd index after the last character in the string * to copy. * @param dst the destination array. * @param dstBegin the start offset in the destination array. * @exception IndexOutOfBoundsException If any of the following * is true: * <ul><li><code>srcBegin</code> is negative. * <li><code>srcBegin</code> is greater than <code>srcEnd</code> * <li><code>srcEnd</code> is greater than the length of this * string * <li><code>dstBegin</code> is negative * <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than * <code>dst.length</code></ul> * @exception NullPointerException if <code>dst</code> is <code>null</code> */ private void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { // %TBD% Joe needs to write this function. Make public when implemented. } /** * Encapsulation c'tor. After this is called, the source FastStringBuffer * will be reset to use the new object as its m_innerFSB, and will have * had its chunk size reset appropriately. IT SHOULD NEVER BE CALLED * EXCEPT WHEN source.length()==1<<(source.m_chunkBits+source.m_rebundleBits) * * NEEDSDOC @param source */ private FastStringBuffer(FastStringBuffer source) { // Copy existing information into new encapsulation m_chunkBits = source.m_chunkBits; m_maxChunkBits = source.m_maxChunkBits; m_rebundleBits = source.m_rebundleBits; m_chunkSize = source.m_chunkSize; m_chunkMask = source.m_chunkMask; m_array = source.m_array; m_innerFSB = source.m_innerFSB; // These have to be adjusted because we're calling just at the time // when we would be about to allocate another chunk m_lastChunk = source.m_lastChunk - 1; m_firstFree = source.m_chunkSize; // Establish capsule as the Inner FSB, reset chunk sizes/addressing source.m_array = new char[16][]; source.m_innerFSB = this; // Since we encapsulated just as we were about to append another // chunk, return ready to create the chunk after the innerFSB // -- 1, not 0. source.m_lastChunk = 1; source.m_firstFree = 0; source.m_chunkBits += m_rebundleBits; source.m_chunkSize = 1 << (source.m_chunkBits); source.m_chunkMask = source.m_chunkSize - 1; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?