c# – Resize an array with unsafe

Question:

Excursion to what you need:

I work with Unity , and have to use its API .

Among the API there is a method AssetBundle.LoadFromMemory(byte[] bytes) , and there are no overloads with offset , length parameters.

This method is used to read files from memory, however, my files are packed into a self-written archive, which I wanted to read through a cacheable buffer, so as not to generate allocations when creating an array.

That is, I am literally locked in by what the API dictates to me. I can't for example store the size of an array separately and have to copy the data into a new separate array whenever I need to use this method.

I'd like to find some way to trick the API method into pushing my obviously larger cacheable buffer to it. The information in this cacheable buffer is simply overwritten on top of the old information, and the resize only happens when there is more data.

For these purposes, I fantasized about "replacing" the size of the array with a smaller one, and after calling the method, return the size back. Literally, I would like to just change the number that Array.Length returns, while leaving the amount of data in it the same.

Is it possible somehow to do this via unsafe ?

Any other ideas are welcome.

Answer:

You can change the size, it is stored immediately before the first element of the array (checked for CLR 2, 4, CoreCLR).

static unsafe void Main(string[] args)
{
    // для примера
    var array = new byte[] {
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa
    };

    Print(array);

    int oldLength = array.Length;
    int newLength = 4;

    // адрес начала массива
    fixed (byte* ptr = array) {
        // адрес, по которому хранится размер массива
        // для x86 он равен ptr - 4, для x64 ptr - 8;
        int* pSize = (int*)(ptr - sizeof(void*));

        // устанавливаем новый размер (только в сторону уменьшения)
        *pSize = newLength;
        Print(array);

        // здесь используйте массив в Unity...

        // возвращаем старый размер
        *pSize = oldLength;
        Print(array);
    }
}

static void Print(byte[] array)
{
    Console.WriteLine("array.Length == " + array.Length);
    foreach (byte a in array)
        Console.Write(a.ToString("X2") + " ");
    Console.WriteLine();
    Console.WriteLine();
}

As a result, the Print function will output:

// исходный массив
array.Length == 10
A1 A2 A3 A4 A5 A6 A7 A8 A9 AA

// измененный массив
array.Length == 4
A1 A2 A3 A4

// восстановленный массив
array.Length == 10
A1 A2 A3 A4 A5 A6 A7 A8 A9 AA

To add an offset, you need to cycle the array to the left by the amount of the offset, then cut off the length to the desired one. Recovery – in reverse order, first change the length to the original, then move the array cyclically to the right.

Scroll to Top