Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / Xml / System / Xml / BufferBuilder.cs / 1 / BufferBuilder.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- //#define BUFFER_BUILDER_TRACING using System.IO; using System.Text; using System.Diagnostics; namespace System.Xml { // // Buffer Builder // // BufferBuilder is a replacement for StringBuilder for cases when large strings can occur. // StringBuilder stores the string that is being built in one large chunk of memory. If it needs more memory, // it allocates a new chunk of double size and copies the data into it. This results in bad perf and // memory constumption in case the string is very large (>85kB). Large objects are allocated on Large Object // Heap and are not freed by GC as fast as smaller objects. // // BufferBuilder uses a StringBuilder as long as the stored string is smaller that 64kB. If the final string // should be bigger that that, it stores the data in a list of char[] arrays. A StringBuilder object still needs to be // used in order to create the final string in ToString methods, but this is ok since at that point // we already know the resulting string length and we can initialize the StringBuilder with the correct // capacity. // // The BufferBuilder is designed for reusing. The Clear method will clear the state of the builder. // The next string built by BufferBuilder will reuse the string builder and the buffer chunks allocated // in the previous uses. (The string builder it not reused when it was last used to create a string >64kB because // setting Length=0 on the string builder makes it allocate the big string again.) // When the buffer chunks are not in use, they are stored as WeakReferences so they can be freed by GC // in case memory-pressure situation happens. #if BUFFER_BUILDER_TRACING public class BufferBuilder { #else internal class BufferBuilder { #endif // // Private types // private struct Buffer { internal char[] buffer; internal WeakReference recycledBuffer; } // // Fields // StringBuilder stringBuilder; Buffer[] buffers; int buffersCount; char[] lastBuffer; int lastBufferIndex; int length; #if BUFFER_BUILDER_TRACING // // Tracing // public static TextWriter s_TraceOutput = null; static int minLength = int.MaxValue; static int maxLength; static int totalLength; static int toStringCount; static int totalAppendCount; #endif // // Constants // #if DEBUG // make it easier to catch buffer-related bugs on debug builds const int BufferSize = 4*1024; #else const int BufferSize = 64*1024; #endif const int InitialBufferArrayLength = 4; const int MaxStringBuilderLength = BufferSize; const int DefaultSBCapacity = 16; // // Constructor // public BufferBuilder() { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "----------------------------\r\nnew BufferBuilder()\r\n----------------------------" ); } #endif } // // Properties // public int Length { get { return length; } set { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.Length = " + value ); } #endif if ( value < 0 || value > length ) { throw new ArgumentOutOfRangeException( "value" ); } if ( value == 0 ) { Clear(); } else { SetLength( value ); } } } // // Public methods // public void Append( char value ) { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.Append\tLength = 1\tchar '" + value.ToString() + "'" ); totalAppendCount++; } #endif if ( length + 1 <= MaxStringBuilderLength ) { if ( stringBuilder == null ) { stringBuilder = new StringBuilder(); } stringBuilder.Append( value ); } else { if ( lastBuffer == null ) { CreateBuffers(); } if ( lastBufferIndex == lastBuffer.Length ) { AddBuffer(); } lastBuffer[lastBufferIndex++] = value; } length++; } public void Append( char[] value ) { Append( value, 0, value.Length ); } public void Append( char[] value, int start, int count ) { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.Append\tLength = " + count + "\t char array \"" + new string( value, start, count ) + "\"" ); totalAppendCount++; } #endif if ( value == null ) { if ( start == 0 && count == 0 ) { return; } throw new ArgumentNullException( "value" ); } if ( count == 0 ) { return; } if ( start < 0 ) { throw new ArgumentOutOfRangeException( "start" ); } if ( count < 0 || start + count > value.Length ) { throw new ArgumentOutOfRangeException( "count" ); } if ( length + count <= MaxStringBuilderLength ) { if ( stringBuilder == null ) { stringBuilder = new StringBuilder( count < DefaultSBCapacity ? DefaultSBCapacity : count ); } stringBuilder.Append( value, start, count ); length += count; } else { unsafe { fixed( char* source = &value[start] ) { AppendHelper( source, count); } } } } public void Append( string value ) { Append( value, 0, value.Length ); } public void Append( string value, int start, int count) { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.Append\tLength = " + count + "\t string fragment \"" + value.Substring( start, count ) + "\"" ); totalAppendCount++; } #endif if ( value == null ) { if ( start == 0 && count == 0 ) { return; } throw new ArgumentNullException( "value" ); } if ( count == 0 ) { return; } if ( start < 0 ) { throw new ArgumentOutOfRangeException( "start" ); } if ( count < 0 || start + count > value.Length ) { throw new ArgumentOutOfRangeException( "count" ); } if ( length + count <= MaxStringBuilderLength ) { if ( stringBuilder == null ) { stringBuilder = new StringBuilder( value, start, count, 0 ); } else { stringBuilder.Append( value, start, count ); } length += count; } else { unsafe { fixed ( char* source = value ) { AppendHelper( source + start, count ); } } } } public void Clear() { if ( length <= MaxStringBuilderLength ) { if ( stringBuilder != null ) { stringBuilder.Length = 0; } } else { if ( lastBuffer != null ) { ClearBuffers(); } // destroy the string builder because setting its Length or Capacity to 0 makes it allocate the last string again :-| stringBuilder = null; } length = 0; } internal void ClearBuffers() { if ( buffers != null ) { // recycle all but the first the buffer for ( int i = 0; i < buffersCount; i++ ) { Recycle( buffers[i] ); } lastBuffer = null; } else { // just one buffer allocated with no buffers array -> no recycling } lastBufferIndex = 0; buffersCount = 0; } public override string ToString() { string returnString; if ( ( length <= MaxStringBuilderLength ) || ( buffersCount == 1 && lastBufferIndex == 0 ) ) { returnString = ( stringBuilder != null ) ? stringBuilder.ToString() : string.Empty; } else { if ( stringBuilder == null ) { stringBuilder = new StringBuilder( length ); } else { stringBuilder.Capacity = length; } int charsLeft = length - stringBuilder.Length; for ( int i = 0; i < buffersCount - 1; i++ ) { char[] buf = buffers[i].buffer; stringBuilder.Append( buf, 0, buf.Length ); charsLeft -= buf.Length; } stringBuilder.Append( buffers[buffersCount-1].buffer, 0, charsLeft ); ClearBuffers(); returnString = stringBuilder.ToString(); } #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.ToString() Length == " + returnString.Length + "\t \"" + returnString + "\"" ); toStringCount++; totalLength += returnString.Length; if ( minLength > returnString.Length ) { minLength = returnString.Length; } if ( maxLength < returnString.Length ) { maxLength = returnString.Length; } } #endif return returnString; } public string ToString( int startIndex, int len ) { #if BUFFER_BUILDER_TRACING if ( s_TraceOutput != null ) { s_TraceOutput.WriteLine( "BufferBuilder.ToString( " + startIndex + ", " + len + " )" ); } #endif if ( startIndex < 0 || startIndex >= length ) { throw new ArgumentOutOfRangeException( "startIndex" ); } if ( len < 0 || startIndex + len > length ) { throw new ArgumentOutOfRangeException( "len" ); } if ( ( length <= MaxStringBuilderLength ) || ( buffersCount == 1 && lastBufferIndex == 0 ) ) { return ( stringBuilder != null ) ? stringBuilder.ToString( startIndex, len ) : string.Empty; } else { StringBuilder sb = new StringBuilder( len ); if ( stringBuilder != null ) { if ( startIndex < stringBuilder.Length ) { if ( len < stringBuilder.Length ) { return stringBuilder.ToString( startIndex, len ); } else { sb.Append( stringBuilder.ToString( startIndex, stringBuilder.Length ) ); startIndex = 0; } } else { startIndex -= stringBuilder.Length; } } int i; for ( i = 0; i < buffersCount; i++ ) { if ( startIndex < buffers[i].buffer.Length ) { break; } startIndex -= buffers[i].buffer.Length; } if ( i < buffersCount ) { int charsLeft = len; for ( ; i < buffersCount && charsLeft > 0; i++ ) { char[] buf = buffers[i].buffer; int copyCount = ( buf.Length < charsLeft ) ? buf.Length : charsLeft; sb.Append( buf, startIndex, copyCount ); startIndex = 0; charsLeft -= copyCount; } } return sb.ToString(); } } // // Private implementation methods // private void CreateBuffers() { Debug.Assert( lastBuffer == null ); if ( buffers == null ) { lastBuffer = new char[BufferSize]; buffers = new Buffer[InitialBufferArrayLength]; buffers[0].buffer = lastBuffer; buffersCount = 1; } else { AddBuffer(); } } unsafe private void AppendHelper( char* pSource, int count ) { if ( lastBuffer == null ) { CreateBuffers(); } int copyCount = 0; while ( count > 0 ) { if ( lastBufferIndex >= lastBuffer.Length ) { AddBuffer(); } copyCount = count; int free = lastBuffer.Length - lastBufferIndex; if ( free < copyCount ) { copyCount = free; } fixed ( char* pLastBuffer = &lastBuffer[lastBufferIndex] ) { wstrcpy( pLastBuffer, pSource, copyCount ); } pSource += copyCount; length += copyCount; lastBufferIndex += copyCount; count -= copyCount; } } private void AddBuffer() { Debug.Assert( buffers != null ); // if ( buffersCount + 1 == buffers.Length ) { Buffer[] newBuffers = new Buffer[buffers.Length * 2]; Array.Copy( buffers, 0, newBuffers, 0, buffers.Length ); buffers = newBuffers; } // use the recycled buffer if we have one char[] newBuffer; if ( buffers[buffersCount].recycledBuffer != null ) { newBuffer = (char[])buffers[buffersCount].recycledBuffer.Target; if ( newBuffer != null ) { buffers[buffersCount].recycledBuffer.Target = null; goto End; } } newBuffer = new char[BufferSize]; End: // add the buffer to the list lastBuffer = newBuffer; buffers[buffersCount++].buffer = newBuffer; lastBufferIndex = 0; } private void Recycle( Buffer buf ) { // recycled buffers are kept as WeakReferences if ( buf.recycledBuffer == null ) { buf.recycledBuffer = new WeakReference( buf.buffer ); } else { buf.recycledBuffer.Target = buf.buffer; } #if DEBUG for ( int i = 0; i < buf.buffer.Length; i++ ) { buf.buffer[i] = (char)0xCC; } #endif buf.buffer = null; } private void SetLength( int newLength ) { Debug.Assert( newLength <= length ); if ( newLength == length ) { return; } if ( length <= MaxStringBuilderLength ) { stringBuilder.Length = newLength; } else { int newLastIndex = newLength; int i; for ( i = 0; i < buffersCount; i++ ) { if ( newLastIndex < buffers[i].buffer.Length ) { break; } newLastIndex -= buffers[i].buffer.Length; } if ( i < buffersCount ) { lastBuffer = buffers[i].buffer; lastBufferIndex = newLastIndex; i++; int newBuffersCount = i; for ( ; i < buffersCount; i++ ) { Recycle( buffers[i] ); } buffersCount = newBuffersCount; } } length = newLength; } internal static unsafe void wstrcpy( char *dmem, char *smem, int charCount ) { if ( charCount > 0 ) { if ( ( ( (int)dmem ^ (int)smem ) & 3 ) == 0 ) { while ( ( (int) dmem & 3 ) != 0 && charCount > 0) { dmem[0] = smem[0]; dmem += 1; smem += 1; charCount -= 1; } if ( charCount >= 8 ) { charCount -= 8; do { ((uint*)dmem)[0] = ((uint*)smem)[0]; ((uint*)dmem)[1] = ((uint*)smem)[1]; ((uint*)dmem)[2] = ((uint*)smem)[2]; ((uint*)dmem)[3] = ((uint*)smem)[3]; dmem += 8; smem += 8; charCount -= 8; } while ( charCount >= 0 ); } if ( ( charCount & 4 ) != 0 ) { ((uint*)dmem)[0] = ((uint*)smem)[0]; ((uint*)dmem)[1] = ((uint*)smem)[1]; dmem += 4; smem += 4; } if ( ( charCount & 2 ) != 0) { ((uint*)dmem)[0] = ((uint*)smem)[0]; dmem += 2; smem += 2; } } else { if ( charCount >= 8 ) { charCount -= 8; do { dmem[0] = smem[0]; dmem[1] = smem[1]; dmem[2] = smem[2]; dmem[3] = smem[3]; dmem[4] = smem[4]; dmem[5] = smem[5]; dmem[6] = smem[6]; dmem[7] = smem[7]; dmem += 8; smem += 8; charCount -= 8; } while ( charCount >= 0 ); } if ( ( charCount & 4) != 0 ) { dmem[0] = smem[0]; dmem[1] = smem[1]; dmem[2] = smem[2]; dmem[3] = smem[3]; dmem += 4; smem += 4; } if ( ( charCount & 2 ) != 0 ) { dmem[0] = smem[0]; dmem[1] = smem[1]; dmem += 2; smem += 2; } } if ( ( charCount & 1 ) != 0 ) { dmem[0] = smem[0]; } } } #if BUFFER_BUILDER_TRACING public static int ToStringCount { get { return toStringCount; } } public static double AvgAppendCount { get { return toStringCount == 0 ? 0 : (double)totalAppendCount / toStringCount; } } public static int AvgLength { get { return toStringCount == 0 ? 0 : totalLength / toStringCount; } } public static int MaxLength { get { return maxLength; } } public static int MinLength { get { return minLength; } } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EdmScalarPropertyAttribute.cs
- BitmapMetadataBlob.cs
- odbcmetadatafactory.cs
- HtmlTableRow.cs
- ImportedNamespaceContextItem.cs
- ImageCollectionEditor.cs
- StrokeFIndices.cs
- TextOnlyOutput.cs
- ProfileSection.cs
- prompt.cs
- ICollection.cs
- UdpTransportSettingsElement.cs
- IISMapPath.cs
- HandlerFactoryCache.cs
- StorageScalarPropertyMapping.cs
- CleanUpVirtualizedItemEventArgs.cs
- ConfigurationStrings.cs
- DataGridViewIntLinkedList.cs
- InternalBufferOverflowException.cs
- WebEventTraceProvider.cs
- TiffBitmapDecoder.cs
- Sentence.cs
- CommonXSendMessage.cs
- HttpGetClientProtocol.cs
- FixedDocumentPaginator.cs
- RtType.cs
- RuntimeConfig.cs
- DefaultValueConverter.cs
- ZipFileInfo.cs
- ContractUtils.cs
- DisplayMemberTemplateSelector.cs
- TreeViewItemAutomationPeer.cs
- ColumnCollection.cs
- DynamicDataExtensions.cs
- Permission.cs
- SQLDecimal.cs
- RecognizedPhrase.cs
- SafeBuffer.cs
- ResourceReferenceExpressionConverter.cs
- TraceFilter.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- PeerCollaborationPermission.cs
- ResizeBehavior.cs
- CultureSpecificStringDictionary.cs
- HttpContext.cs
- BamlBinaryReader.cs
- StatusBarPanelClickEvent.cs
- ReferencedCollectionType.cs
- XmlSchemaGroupRef.cs
- PackagePartCollection.cs
- KeyValuePair.cs
- SharedRuntimeState.cs
- XsltQilFactory.cs
- SafeHandle.cs
- ViewStateAttachedPropertyFeature.cs
- WpfXamlType.cs
- XmlNodeList.cs
- SyndicationDeserializer.cs
- Cursor.cs
- SingleAnimationBase.cs
- SqlUdtInfo.cs
- ResourceAssociationTypeEnd.cs
- DataGridViewIntLinkedList.cs
- Line.cs
- SqlClientFactory.cs
- XPathDocument.cs
- OpenTypeLayout.cs
- CompositionCommandSet.cs
- NullRuntimeConfig.cs
- TransformPatternIdentifiers.cs
- XmlBaseReader.cs
- MatrixUtil.cs
- ImageBrush.cs
- OdbcHandle.cs
- DetailsViewUpdatedEventArgs.cs
- GradientBrush.cs
- ColumnBinding.cs
- FilterableAttribute.cs
- WindowsScrollBarBits.cs
- COAUTHINFO.cs
- MemberDescriptor.cs
- RuleSettings.cs
- ConfigErrorGlyph.cs
- BmpBitmapEncoder.cs
- ConnectionsZoneAutoFormat.cs
- DynamicValidatorEventArgs.cs
- TabRenderer.cs
- CompositeTypefaceMetrics.cs
- ETagAttribute.cs
- TextRangeBase.cs
- ListViewGroupConverter.cs
- IItemProperties.cs
- SslStream.cs
- EndpointAddressProcessor.cs
- EventLogEntry.cs
- BamlStream.cs
- DigitalSignature.cs
- TrackingAnnotationCollection.cs
- RuntimeConfigLKG.cs
- DiffuseMaterial.cs