The Labs \ Source Viewer \ SSCLI \ System.Net \ ScatterGatherBuffers

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_ScatterGatherBuffers.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Net
  16. {
  17.     using System;
  18.     using System.Collections;
  19.    
  20.     internal class ScatterGatherBuffers
  21.     {
  22.        
  23.         private MemoryChunk headChunk;
  24.         // = null;
  25.         private MemoryChunk currentChunk;
  26.         // = null;
  27.         private int nextChunkLength = 1024;
  28.         // this could be customized at construction time
  29.         private int totalLength;
  30.         // = 0;
  31.         private int chunkCount;
  32.         // = 0;
  33.         internal ScatterGatherBuffers()
  34.         {
  35.         }
  36.        
  37.         internal ScatterGatherBuffers(long totalSize)
  38.         {
  39.             // We know up front how much data is to be written.
  40.             if (totalSize > 0) {
  41.                 currentChunk = AllocateMemoryChunk(totalSize > Int32.MaxValue ? Int32.MaxValue : (int)totalSize);
  42.             }
  43.         }
  44.        
  45.         internal BufferOffsetSize[] GetBuffers()
  46.         {
  47.             if (Empty) {
  48.                 return null;
  49.             }
  50.             GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() chunkCount:" + chunkCount.ToString());
  51.             BufferOffsetSize[] array = new BufferOffsetSize[chunkCount];
  52.             int index = 0;
  53.             MemoryChunk thisMemoryChunk = headChunk;
  54.             while (thisMemoryChunk != null) {
  55.                 GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() index:" + index.ToString() + " size:" + thisMemoryChunk.FreeOffset);
  56.                 //
  57.                 // buffer itself is referenced by the BufferOffsetSize struct, data is not copied
  58.                 //
  59.                 array[index] = new BufferOffsetSize(thisMemoryChunk.Buffer, 0, thisMemoryChunk.FreeOffset, false);
  60.                 index++;
  61.                 thisMemoryChunk = thisMemoryChunk.Next;
  62.             }
  63.             return array;
  64.         }
  65.        
  66.         private bool Empty {
  67.             get { return headChunk == null || chunkCount == 0; }
  68.         }
  69.        
  70.         internal int Length {
  71.             get { return totalLength; }
  72.         }
  73.        
  74.         internal void Write(byte[] buffer, int offset, int count)
  75.         {
  76.             GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::Add() count:" + count.ToString());
  77.             while (count > 0) {
  78.                 //
  79.                 // compute available space in current allocated buffer (0 if there's no buffer)
  80.                 //
  81.                 int available = Empty ? 0 : currentChunk.Buffer.Length - currentChunk.FreeOffset;
  82.                 GlobalLog.Assert(available >= 0, "ScatterGatherBuffers::Add()|available < 0");
  83.                 //
  84.                 // if the current chunk is is full, allocate a new one
  85.                 //
  86.                 if (available == 0) {
  87.                     // ask for at least count bytes so that we need at most one allocation
  88.                     MemoryChunk newChunk = AllocateMemoryChunk(count);
  89.                     if (currentChunk != null) {
  90.                         currentChunk.Next = newChunk;
  91.                     }
  92.                     //
  93.                     // move ahead in the linked list (or at the beginning if this is the fist buffer)
  94.                     //
  95.                     currentChunk = newChunk;
  96.                 }
  97.                 int copyCount = count < available ? count : available;
  98.                
  99.                     // src
  100.                     // src index
  101.                     // dest
  102.                     // dest index
  103.                 Buffer.BlockCopy(buffer, offset, currentChunk.Buffer, currentChunk.FreeOffset, copyCount);
  104.                 // total size to copy
  105.                 //
  106.                 // update offsets and counts
  107.                 //
  108.                 offset += copyCount;
  109.                 count -= copyCount;
  110.                 totalLength += copyCount;
  111.                 currentChunk.FreeOffset += copyCount;
  112.             }
  113.             GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::Add() totalLength:" + totalLength.ToString());
  114.         }
  115.        
  116.         private MemoryChunk AllocateMemoryChunk(int newSize)
  117.         {
  118.             if (newSize > nextChunkLength) {
  119.                 nextChunkLength = newSize;
  120.             }
  121.             MemoryChunk newChunk = new MemoryChunk(nextChunkLength);
  122.             if (Empty) {
  123.                 headChunk = newChunk;
  124.             }
  125.             //
  126.             // next time allocate twice as much. check fot possible overflows
  127.             //
  128.             nextChunkLength *= 2;
  129.             //
  130.             // update number of chunks in the linked list
  131.             //
  132.             chunkCount++;
  133.             GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::AllocateMemoryChunk() chunkCount:" + chunkCount.ToString() + " nextChunkLength:" + nextChunkLength.ToString());
  134.             return newChunk;
  135.         }
  136.        
  137.         private class MemoryChunk
  138.         {
  139.             internal byte[] Buffer;
  140.             internal int FreeOffset;
  141.             // = 0
  142.             internal MemoryChunk Next;
  143.             // = null
  144.             internal MemoryChunk(int bufferSize)
  145.             {
  146.                 Buffer = new byte[bufferSize];
  147.             }
  148.         }
  149.        
  150.     }
  151.     // class ScatterGatherBuffers
  152.    
  153.    
  154. }
  155. // namespace System.Net

Developer Fusion