Wednesday, December 15, 2010

Using Array.Copy to shift array elements

I wrote a network communications class that will perform socket reads into a pre-allocated Byte buffer.  This buffer is always the target of socket reads, so that I can avoid doing (perhaps many) unnecessary memory allocations.  For this byte buffer, I need to keep track of where “active” data in the buffer lives.  Initially there is no active data, so both START and END equal zero.  Later on, however, START and END may not be pointing to the beginning of the buffer and I need to SHIFT the active bytes to the front of the buffer and adjust the START and END pointers accordingly.  This way the next socket read can read “BUFFER_SIZE – END” bytes.

But how do we shift the bytes in the array down?  Some might create a new array and use Array.Copy to copy the active bytes over.  But we really want to use the same buffer, so we just want to shift the active bytes down to element 0.  Will Array.Copy do this correctly?  Doing a “shift left” (moving elements towards the beginning of the array) requires that the bytes are shifted in ascending array-index order.  If you go the other way, descending, you’ll clobber your data if there is any overlap.  Similarly, you need to shift in descending order when you are doing a “shift right” and moving elements up the array.

In order for Array.Copy to work correctly in both cases, it needs to detect that when there is an overlap between the source and target range and then move the elements in the proper order.  Does it do this?  Well.. YES!

In the example below, I take an array of bytes with 13 elements and shift the middle 9 bytes left; then I do it again, but shift right.

Here’s the output:

image

Here’s the code:

 
Imports System.Text
 
Module Module1
 
    Sub Main()
 
        Console.WriteLine("Testing Array.Copy on Byte array to shift contents up and down:" & vbCrLf)
 
        Dim A() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} 
        Console.WriteLine("FROM A(" & (A.Length() - 1).ToString() & ") = " & BitConverter.ToString(A))
        Console.WriteLine()
        Console.WriteLine("Array.Copy(A, 2, A, 0, 9)")
        Console.WriteLine()
        Array.Copy(A, 2, A, 0, 9)
        Console.WriteLine("   = A(" & (A.Length() - 1).ToString() & ") = " & BitConverter.ToString(A))
 
        A = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
        Console.WriteLine()
        Console.WriteLine("FROM A(" & (A.Length() - 1).ToString() & ") = " & BitConverter.ToString(A))
        Console.WriteLine()
        Console.WriteLine("Array.Copy(A, 2, A, 4, 9)")
        Console.WriteLine()
        Array.Copy(A, 2, A, 4, 9)
        Console.WriteLine("   = A(" & (A.Length() - 1).ToString() & ") = " & BitConverter.ToString(A))
 
    End Sub
 
 
End Module

No comments: