The Labs \ Source Viewer \ SSCLI \ System \ Buffer

  1. // ==++==
  2. //
  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. //
  14. // ==--==
  15. namespace System
  16. {
  17.    
  18.     //Only contains static methods. Does not require serialization
  19.    
  20.     using System;
  21.     using System.Runtime.CompilerServices;
  22.     [System.Runtime.InteropServices.ComVisible(true)]
  23.     public static class Buffer
  24.     {
  25.         // Copies from one primitive array to another primitive array without
  26.         // respecting types. This calls memmove internally.
  27.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  28.         public static extern void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count);
  29.        
  30.         // A very simple and efficient array copy that assumes all of the
  31.         // parameter validation has already been done. All counts here are
  32.         // in bytes.
  33.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  34.         static internal extern void InternalBlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count);
  35.        
  36.         // This is ported from the optimized CRT assembly in memchr.asm. The JIT generates
  37.         // pretty good code here and this ends up being within a couple % of the CRT asm.
  38.         // It is however cross platform as the CRT hasn't ported their fast version to 64-bit
  39.         // platforms.
  40.         //
  41.         unsafe static internal int IndexOfByte(byte* src, byte value, int index, int count)
  42.         {
  43.             BCLDebug.Assert(src != null, "src should not be null");
  44.            
  45.             byte* pByte = src + index;
  46.            
  47.             // Align up the pointer to sizeof(int).
  48.             while (((int)pByte & 3) != 0) {
  49.                 if (count == 0)
  50.                     return -1;
  51.                 else if (*pByte == value)
  52.                     return (int)(pByte - src);
  53.                
  54.                 count--;
  55.                 pByte++;
  56.             }
  57.            
  58.             // Fill comparer with value byte for comparisons
  59.             //
  60.             // comparer = 0/0/value/value
  61.             uint comparer = (((uint)value << 8) + (uint)value);
  62.             // comparer = value/value/value/value
  63.             comparer = (comparer << 16) + comparer;
  64.            
  65.             // Run through buffer until we hit a 4-byte section which contains
  66.             // the byte we're looking for or until we exhaust the buffer.
  67.             while (count > 3) {
  68.                 // Test the buffer for presence of value. comparer contains the byte
  69.                 // replicated 4 times.
  70.                 uint t1 = *(uint*)pByte;
  71.                 t1 = t1 ^ comparer;
  72.                 uint t2 = 2130640639 + t1;
  73.                 t1 = t1 ^ 4294967295u;
  74.                 t1 = t1 ^ t2;
  75.                 t1 = t1 & 2164326656u;
  76.                
  77.                 // if t1 is non-zero then these 4-bytes don't contain a match
  78.                 if (t1 == 0) {
  79.                     count -= 4;
  80.                     pByte += 4;
  81.                     continue;
  82.                 }
  83.                
  84.                 // We've found a match for value, figure out which position it's in.
  85.                 int foundIndex = (int)(pByte - src);
  86.                 if (pByte[0] == value)
  87.                     return foundIndex;
  88.                 else if (pByte[1] == value)
  89.                     return foundIndex + 1;
  90.                 else if (pByte[2] == value)
  91.                     return foundIndex + 2;
  92.                 else if (pByte[3] == value)
  93.                     return foundIndex + 3;
  94.             }
  95.            
  96.             // Catch any bytes that might be left at the tail of the buffer
  97.             while (count > 0) {
  98.                 if (*pByte == value)
  99.                     return (int)(pByte - src);
  100.                
  101.                 count--;
  102.                 pByte++;
  103.             }
  104.            
  105.             // If we don't have a match return -1;
  106.             return -1;
  107.         }
  108.        
  109.         // Gets a particular byte out of the array. The array must be an
  110.         // array of primitives.
  111.         //
  112.         // This essentially does the following:
  113.         // return ((byte*)array) + index.
  114.         //
  115.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  116.         public static extern byte GetByte(Array array, int index);
  117.        
  118.         // Sets a particular byte in an the array. The array must be an
  119.         // array of primitives.
  120.         //
  121.         // This essentially does the following:
  122.         // *(((byte*)array) + index) = value.
  123.         //
  124.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  125.         public static extern void SetByte(Array array, int index, byte value);
  126.        
  127.         // Gets a particular byte out of the array. The array must be an
  128.         // array of primitives.
  129.         //
  130.         // This essentially does the following:
  131.         // return array.length * sizeof(array.UnderlyingElementType).
  132.         //
  133.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  134.         public static extern int ByteLength(Array array);
  135.        
  136.         unsafe static internal void ZeroMemory(byte* src, long len)
  137.         {
  138.             while (len-- > 0)
  139.                 *(src + len) = 0;
  140.         }
  141.        
  142.         unsafe static internal void memcpy(byte* src, int srcIndex, byte[] dest, int destIndex, int len)
  143.         {
  144.             BCLDebug.Assert((srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
  145.             BCLDebug.Assert(dest.Length - destIndex >= len, "not enough bytes in dest");
  146.             // If dest has 0 elements, the fixed statement will throw an
  147.             // IndexOutOfRangeException. Special-case 0-byte copies.
  148.             if (len == 0)
  149.                 return;
  150.             fixed (byte* pDest = dest) {
  151.                 memcpyimpl(src + srcIndex, pDest + destIndex, len);
  152.             }
  153.         }
  154.        
  155.         unsafe static internal void memcpy(byte[] src, int srcIndex, byte* pDest, int destIndex, int len)
  156.         {
  157.             BCLDebug.Assert((srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
  158.             BCLDebug.Assert(src.Length - srcIndex >= len, "not enough bytes in src");
  159.             // If dest has 0 elements, the fixed statement will throw an
  160.             // IndexOutOfRangeException. Special-case 0-byte copies.
  161.             if (len == 0)
  162.                 return;
  163.             fixed (byte* pSrc = src) {
  164.                 memcpyimpl(pSrc + srcIndex, pDest + destIndex, len);
  165.             }
  166.         }
  167.        
  168.         unsafe static internal void memcpy(char* pSrc, int srcIndex, char* pDest, int destIndex, int len)
  169.         {
  170.             BCLDebug.Assert((srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
  171.            
  172.             // No boundary check for buffer overruns - dangerous
  173.             if (len == 0)
  174.                 return;
  175.             memcpyimpl((byte*)(char*)(pSrc + srcIndex), (byte*)(char*)(pDest + destIndex), len * 2);
  176.         }
  177.        
  178.         // Note - using a long instead of an int for the length parameter
  179.         // slows this method down by ~18%.
  180.         unsafe static internal void memcpyimpl(byte* src, byte* dest, int len)
  181.         {
  182.             BCLDebug.Assert(len >= 0, "Negative length in memcopy!");
  183.            
  184.             // Portable naive implementation
  185.             while (len-- > 0)
  186.                 *dest++ = *src++;
  187.         }
  188.     }
  189. }

Developer Fusion