I'm writing an UnmanagedRewindBuffer and I want to implement dynamic resizing of the buffer. I've tried several different things, but I can't seem to be able to get it right. The basic idea is that:
- I allocate a new block of unmanaged memory.
- Create a new UnmanagedMemoryStream(UMS).
- Copy the contents from the old UMS to the new UMS.
- Dispose of the old UMS and free the old allocated block.
- Replace the old UMS and memory block with the new ones.
Here is my resize function:
private void DynamicallyResizeBuffer(long spaceNeeded)
{
    while (_ums.Length < spaceNeeded)
    {
        // Allocate a new buffer
        int length = (int)((double)spaceNeeded * RESIZE_FACTOR);
        IntPtr tempMemoryPointer = Marshal.AllocHGlobal(length);
        // Set the temporary pointer to null
        //MemSet(tempMemoryPointer, length, 0);
        byte* bytePointer = (byte*)tempMemoryPointer.ToPointer();
        for (int i = 0; i < length; i++)
        {
            *(bytePointer + i) = 0;
        }
        // Copy the data
        // MoveMemory(bytePointer, _memoryPointer.ToPointer(), _length);
        // Create a new UnmanagedMemoryStream
        UnmanagedMemoryStream tempUms = new UnmanagedMemoryStream(bytePointer, length, length, FileAccess.ReadWrite);
        // Set up the reader and writers
        BinaryReader tempReader = new BinaryReader(tempUms);
        BinaryWriter tempWriter = new BinaryWriter(tempUms);
        // Copy the data
        _ums.Position = 0;
        tempWriter.Write(ReadBytes(_length));
        // I had deleted this line while I was using the writers and 
        // I forgot to copy it over, but the line was here when I used 
        // the MoveMemory function
        tempUms.Position = _ums.Position;
        // Free the old resources
        Free(true);
        _ums = tempUms;
        _reader = tempReader;
        _writer = tempWriter;
        _length = length;
    }
}
And here is my test for resizing:
public void DynamicResizeTest()
{
    Int32 expected32 = 32;
    Int32 actual32 = 0;
    UInt64 expected64 = 64;
    UInt64 actual64 = 0;
    string expected = "expected";
    string actual = string.Empty;
    string actualFromBytes = string.Empty;
    byte[] expectedBytes = Encoding.UTF8.GetBytes(expected);
    // Create an 4 byte buffer
    UnmanagedRewindBuffer ubs = null;
    try
    {
        ubs = new UnmanagedRewindBuffer(4, 1);
        ubs.WriteInt32(expected32);
        // should dynamically resize for the 64 bit integer
        ubs.WriteUInt64(expected64);
        ubs.WriteString(expected);
        // should dynamically resize for the bytes
        ubs.WriteByte(expectedBytes);
        ubs.Rewind();
        actual32 = ubs.ReadInt32();
        actual64 = ubs.ReadUInt64();
        actual = ubs.ReadString();
        actualFromBytes = Encoding.UTF8.GetString(ubs.ReadBytes(expected.Length));
    }
    finally
    {
        if (ubs != null)
        {
            ubs.Clear();
            ubs.Dispose();
        }
        ubs = null;
    }
    Assert.AreEqual(expected32, actual32);
    Assert.AreEqual(expected64, actual64);
    Assert.AreEqual(expected, actual);
    Assert.AreEqual(expected, actualFromBytes);
}
I've tried calling MoveMemory, which is just an unsafe extern to the kernel32 RtlMoveMemory, but when I run the test I get the following results:
actual32 is 32, expected 32
actual64 is 0, expected 64
actual is "", expected "expected"
actualFromBytes is some gibberish, expected "expected"
When I use the reader/writer to directly read from the old UMS to the new UMS, I get the following results:
actual32 is 32, expected 32
actual64 is 64, expected 64
actual is "", expected "expected"
actualFromBytes is "\b\0expect", expected "expected"
If I allocate enough space right from the start, then I have no issues with reading the values and I get the correct expected results.
What's the right way to copy the data?
Update:
Per Alexi's comment, here is the Free method which disposes of the reader/writer and the UnmanagedMemoryStream:
private void Free(bool disposeManagedResources)
{
    // Dispose unmanaged resources
    Marshal.FreeHGlobal(_memoryPointer);
    // Dispose managed resources. Should not be called from destructor.
    if (disposeManagedResources)
    {
        _reader.Close();
        _writer.Close();
        _reader = null;
        _writer = null;
        _ums.Dispose();
        _ums = null;
    }
}
 
     
     
    