Home > database >  How to add zero-padding to a single Span<byte> without allocate memory?
How to add zero-padding to a single Span<byte> without allocate memory?

Time:01-21

I have a method to convert Span<byte> to int:

int ConvertToInt32(Span<byte> buffer)
{
    if (buffer.Length != 4)
    {
        // add zero-padding to the buffer
    }

    return BitConverter.ToInt32(buffer);
    // or MemoryMarshal....
}

If the input parameter (buffer) length is 4, so the conversion works, but if it has less than 4 bytes it doesn't. I'm looking for a non-allocating method to do this. So how can I add zero-padding to the buffer before conversion, or is there any other solution?

CodePudding user response:

You can allocate on stack with stackalloc which should be cheaper then allocating on the heap and is usual approach in high-performance scenarios AFAIK:

Span<byte> buffer = stackalloc byte[3] {0,0,1};
if (buffer.Length != 4)
{
    Span<byte> interimBuffer = stackalloc byte[4];
    // ..
}

Note that you can just convert to type with corresponding size and then cast to int:

if (buffer.Length == 2)
{
    var int16 = (int)BitConverter.ToInt16(buffer);
}

But due to branching it can have worse performance.

Also do not forget about endianness computer's architecture as written in the docs.

CodePudding user response:

You could waste four bytes on a static buffer:

// buffer used for converting fewer than 4 bytes
private static byte convertBuffer[] = new byte[4];
int ConvertToInt32(Span<byte> buffer)
{
    if (buffer.Length != 4)
    {
        // copy the bytes from buffer to convertBuffer
        // and then . . .
        return BitConverter.ToInt32(buffer);
    }

    return BitConverter.ToInt32(buffer);
    // or MemoryMarshal....
}

The question here will be where to copy the bytes. Do you pad left or pad right? As the documentation says:

The order of bytes in the array must reflect the endianness of the computer system's architecture. For more information, see the Remarks section of BitConverter.

In truth, that 4-byte buffer will likely require more than 4 bytes, what with allocation overhead and such. I'd figure somewhere between 12 and 24 bytes, depending on if you're running on the 32-bit or 64-bit runtime. Still, it prevents having to do a memory allocation every time you use it.

The only other way I can think of is to write a loop that'll do the conversion: basically, re-create the logic of BitConverter.ToInt32(), but modified to handle fewer than 4 bytes. That's not too tough, but again you need to make allowances for the endianness of the computer. If you're interested in how BitConverter works, take a look at the source.

  • Related