@@ -37,7 +37,6 @@ namespace ServiceStack.Text //Internalize to avoid conflicts
3737 public static class MemoryStreamFactory
3838 {
3939 public static bool UseRecyclableMemoryStream { get ; set ; }
40- public static bool MuteDuplicateDisposeExceptions { get ; set ; }
4140
4241#if ! SL5
4342 public static RecyclableMemoryStreamManager RecyclableInstance = new RecyclableMemoryStreamManager ( ) ;
@@ -722,7 +721,7 @@ public MemoryStream GetStream(string tag, byte[] buffer, int offset, int count)
722721 /// leads to continual memory growth as each stream approaches the maximum allowed size.
723722 /// 3. Memory copying - Each time a MemoryStream grows, all the bytes are copied into new buffers.
724723 /// This implementation only copies the bytes when GetBuffer is called.
725- /// 4. Memory fragmentation - By using homogenous buffer sizes, it ensures that blocks of memory
724+ /// 4. Memory fragmentation - By using homogeneous buffer sizes, it ensures that blocks of memory
726725 /// can be easily reused.
727726 ///
728727 /// The stream is implemented on top of a series of uniformly-sized blocks. As the stream's length grows,
@@ -822,9 +821,8 @@ internal RecyclableMemoryStreamManager MemoryManager
822821 /// </summary>
823822 /// <param name="memoryManager">The memory manager</param>
824823 public RecyclableMemoryStream ( RecyclableMemoryStreamManager memoryManager )
825- : this ( memoryManager , null )
824+ : this ( memoryManager , null , 0 , null )
826825 {
827-
828826 }
829827
830828 /// <summary>
@@ -833,9 +831,8 @@ public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager)
833831 /// <param name="memoryManager">The memory manager</param>
834832 /// <param name="tag">A string identifying this stream for logging and debugging purposes</param>
835833 public RecyclableMemoryStream ( RecyclableMemoryStreamManager memoryManager , string tag )
836- : this ( memoryManager , tag , 0 )
834+ : this ( memoryManager , tag , 0 , null )
837835 {
838-
839836 }
840837
841838 /// <summary>
@@ -890,7 +887,6 @@ internal RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, str
890887 #endregion
891888
892889 #region Dispose and Finalize
893-
894890 ~ RecyclableMemoryStream ( )
895891 {
896892 this . Dispose ( false ) ;
@@ -913,10 +909,7 @@ protected override void Dispose(bool disposing)
913909 }
914910
915911 Events . Write . MemoryStreamDoubleDispose ( this . id , this . tag , this . allocationStack , this . disposeStack , doubleDisposeStack ) ;
916- if ( MemoryStreamFactory . MuteDuplicateDisposeExceptions )
917- return ;
918-
919- throw new InvalidOperationException ( "Cannot dispose of RecyclableMemoryStream twice" ) ;
912+ return ;
920913 }
921914
922915 Events . Write . MemoryStreamDisposed ( this . id , this . tag ) ;
@@ -941,7 +934,6 @@ protected override void Dispose(bool disposing)
941934
942935 Events . Write . MemoryStreamFinalized ( this . id , this . tag , this . allocationStack ) ;
943936
944- #if ! PCL
945937 if ( AppDomain . CurrentDomain . IsFinalizingForUnload ( ) )
946938 {
947939 // If we're being finalized because of a shutdown, don't go any further.
@@ -950,7 +942,6 @@ protected override void Dispose(bool disposing)
950942 base . Dispose ( disposing ) ;
951943 return ;
952944 }
953- #endif
954945
955946 this . memoryManager . ReportStreamFinalized ( ) ;
956947 }
@@ -986,7 +977,6 @@ public void Close()
986977 {
987978 this . Dispose ( true ) ;
988979 }
989-
990980 #endregion
991981
992982 #region MemoryStream overrides
@@ -1016,7 +1006,11 @@ public override int Capacity
10161006 }
10171007 return 0 ;
10181008 }
1019- set { this . EnsureCapacity ( value ) ; }
1009+ set
1010+ {
1011+ this . CheckDisposed ( ) ;
1012+ this . EnsureCapacity ( value ) ;
1013+ }
10201014 }
10211015
10221016 private int length ;
@@ -1049,6 +1043,7 @@ public override long Position
10491043 }
10501044 set
10511045 {
1046+ this . CheckDisposed ( ) ;
10521047 if ( value < 0 )
10531048 {
10541049 throw new ArgumentOutOfRangeException ( "value" , "value must be non-negative" ) ;
@@ -1125,7 +1120,7 @@ public byte[] GetBuffer()
11251120 // it's possible that people will manipulate the buffer directly
11261121 // and set the length afterward. Capacity sets the expectation
11271122 // for the size of the buffer.
1128- var newBuffer = this . MemoryManager . GetLargeBuffer ( this . Capacity , this . tag ) ;
1123+ var newBuffer = this . memoryManager . GetLargeBuffer ( this . Capacity , this . tag ) ;
11291124
11301125 // InternalRead will check for existence of largeBuffer, so make sure we
11311126 // don't set it until after we've copied the data.
@@ -1147,6 +1142,7 @@ public byte[] GetBuffer()
11471142 /// for the sake of completeness.
11481143 /// </summary>
11491144 /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
1145+ [ Obsolete ( "This method has degraded performance vs. GetBuffer and should be avoided." ) ]
11501146 public override byte [ ] ToArray ( )
11511147 {
11521148 this . CheckDisposed ( ) ;
@@ -1232,53 +1228,49 @@ public override void Write(byte[] buffer, int offset, int count)
12321228 throw new ArgumentException ( "count must be greater than buffer.Length - offset" ) ;
12331229 }
12341230
1231+ int blockSize = this . memoryManager . BlockSize ;
1232+ long end = ( long ) this . position + count ;
12351233 // Check for overflow
1236- if ( this . Position + count > MaxStreamLength )
1234+ if ( end > MaxStreamLength )
12371235 {
12381236 throw new IOException ( "Maximum capacity exceeded" ) ;
12391237 }
12401238
1241- int end = ( int ) this . Position + count ;
1242-
1243- int blockSize = this . memoryManager . BlockSize ;
1244-
1245- int requiredBuffers = ( end + blockSize - 1 ) / blockSize ;
1239+ long requiredBuffers = ( end + blockSize - 1 ) / blockSize ;
12461240
12471241 if ( requiredBuffers * blockSize > MaxStreamLength )
12481242 {
12491243 throw new IOException ( "Maximum capacity exceeded" ) ;
12501244 }
12511245
1252- EnsureCapacity ( end ) ;
1246+ this . EnsureCapacity ( ( int ) end ) ;
12531247
12541248 if ( this . largeBuffer == null )
12551249 {
12561250 int bytesRemaining = count ;
12571251 int bytesWritten = 0 ;
1258- int currentBlockIndex = this . OffsetToBlockIndex ( this . position ) ;
1259-
1260- int blockOffset = this . OffsetToBlockOffset ( this . position ) ;
1252+ var blockAndOffset = this . GetBlockAndRelativeOffset ( this . position ) ;
12611253
12621254 while ( bytesRemaining > 0 )
12631255 {
1264- byte [ ] currentBlock = this . blocks [ currentBlockIndex ] ;
1265- int remainingInBlock = blockSize - blockOffset ;
1256+ byte [ ] currentBlock = this . blocks [ blockAndOffset . Block ] ;
1257+ int remainingInBlock = blockSize - blockAndOffset . Offset ;
12661258 int amountToWriteInBlock = Math . Min ( remainingInBlock , bytesRemaining ) ;
12671259
1268- Buffer . BlockCopy ( buffer , offset + bytesWritten , currentBlock , blockOffset , amountToWriteInBlock ) ;
1260+ Buffer . BlockCopy ( buffer , offset + bytesWritten , currentBlock , blockAndOffset . Offset , amountToWriteInBlock ) ;
12691261
12701262 bytesRemaining -= amountToWriteInBlock ;
12711263 bytesWritten += amountToWriteInBlock ;
12721264
1273- currentBlockIndex ++ ;
1274- blockOffset = 0 ;
1265+ ++ blockAndOffset . Block ;
1266+ blockAndOffset . Offset = 0 ;
12751267 }
12761268 }
12771269 else
12781270 {
12791271 Buffer . BlockCopy ( buffer , offset , this . largeBuffer , this . position , count ) ;
12801272 }
1281- this . Position = end ;
1273+ this . position = ( int ) end ;
12821274 this . length = Math . Max ( this . position , this . length ) ;
12831275 }
12841276
@@ -1297,7 +1289,7 @@ public override string ToString()
12971289 /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
12981290 public override void WriteByte ( byte value )
12991291 {
1300- CheckDisposed ( ) ;
1292+ this . CheckDisposed ( ) ;
13011293 this . byteBuffer [ 0 ] = value ;
13021294 this . Write ( this . byteBuffer , 0 , 1 ) ;
13031295 }
@@ -1317,9 +1309,8 @@ public override int ReadByte()
13171309 byte value = 0 ;
13181310 if ( this . largeBuffer == null )
13191311 {
1320- int block = OffsetToBlockIndex ( this . position ) ;
1321- int blockOffset = OffsetToBlockOffset ( this . position ) ;
1322- value = this . blocks [ block ] [ blockOffset ] ;
1312+ var blockAndOffset = this . GetBlockAndRelativeOffset ( this . position ) ;
1313+ value = this . blocks [ blockAndOffset . Block ] [ blockAndOffset . Offset ] ;
13231314 }
13241315 else
13251316 {
@@ -1399,6 +1390,7 @@ public override long Seek(long offset, SeekOrigin loc)
13991390 /// <remarks>Important: This does a synchronous write, which may not be desired in some situations</remarks>
14001391 public override void WriteTo ( Stream stream )
14011392 {
1393+ this . CheckDisposed ( ) ;
14021394 if ( stream == null )
14031395 {
14041396 throw new ArgumentNullException ( "stream" ) ;
@@ -1427,7 +1419,6 @@ public override void WriteTo(Stream stream)
14271419 #endregion
14281420
14291421 #region Helper Methods
1430-
14311422 private void CheckDisposed ( )
14321423 {
14331424 if ( this . disposed )
@@ -1444,21 +1435,20 @@ private int InternalRead(byte[] buffer, int offset, int count, int fromPosition)
14441435 }
14451436 if ( this . largeBuffer == null )
14461437 {
1447- int currentBlock = this . OffsetToBlockIndex ( fromPosition ) ;
1438+ var blockAndOffset = this . GetBlockAndRelativeOffset ( fromPosition ) ;
14481439 int bytesWritten = 0 ;
14491440 int bytesRemaining = Math . Min ( count , this . length - fromPosition ) ;
1450- int blockOffset = this . OffsetToBlockOffset ( fromPosition ) ;
14511441
14521442 while ( bytesRemaining > 0 )
14531443 {
1454- int amountToCopy = Math . Min ( this . blocks [ currentBlock ] . Length - blockOffset , bytesRemaining ) ;
1455- Buffer . BlockCopy ( this . blocks [ currentBlock ] , blockOffset , buffer , bytesWritten + offset , amountToCopy ) ;
1444+ int amountToCopy = Math . Min ( this . blocks [ blockAndOffset . Block ] . Length - blockAndOffset . Offset , bytesRemaining ) ;
1445+ Buffer . BlockCopy ( this . blocks [ blockAndOffset . Block ] , blockAndOffset . Offset , buffer , bytesWritten + offset , amountToCopy ) ;
14561446
14571447 bytesWritten += amountToCopy ;
14581448 bytesRemaining -= amountToCopy ;
14591449
1460- ++ currentBlock ;
1461- blockOffset = 0 ;
1450+ ++ blockAndOffset . Block ;
1451+ blockAndOffset . Offset = 0 ;
14621452 }
14631453 return bytesWritten ;
14641454 }
@@ -1470,14 +1460,22 @@ private int InternalRead(byte[] buffer, int offset, int count, int fromPosition)
14701460 }
14711461 }
14721462
1473- private int OffsetToBlockIndex ( int offset )
1463+ private struct BlockAndOffset
14741464 {
1475- return offset / this . memoryManager . BlockSize ;
1465+ public int Block ;
1466+ public int Offset ;
1467+
1468+ public BlockAndOffset ( int block , int offset )
1469+ {
1470+ this . Block = block ;
1471+ this . Offset = offset ;
1472+ }
14761473 }
14771474
1478- private int OffsetToBlockOffset ( int offset )
1475+ private BlockAndOffset GetBlockAndRelativeOffset ( int offset )
14791476 {
1480- return offset % this . memoryManager . BlockSize ;
1477+ var blockSize = this . memoryManager . BlockSize ;
1478+ return new BlockAndOffset ( offset / blockSize , offset % blockSize ) ;
14811479 }
14821480
14831481 private void EnsureCapacity ( int newCapacity )
@@ -1502,7 +1500,7 @@ private void EnsureCapacity(int newCapacity)
15021500 {
15031501 while ( this . Capacity < newCapacity )
15041502 {
1505- blocks . Add ( ( this . MemoryManager . GetBlock ( ) ) ) ;
1503+ blocks . Add ( ( this . memoryManager . GetBlock ( ) ) ) ;
15061504 }
15071505 }
15081506 }
0 commit comments