Home > database >  How can you fill an entire array pointer with a single value with a single write operation?
How can you fill an entire array pointer with a single value with a single write operation?

Time:01-05

I have a pointer to a byte array, and I need to set the values of a certain region of this array to 0. I'm quite familiar with the methods available through the Marshal/Buffer/Array classes, and this problem is not at all hard.

The problem, however, is that I do not want to create excessive arrays, or write every byte one-by-one. All the methods I'm familiar with require full arrays, though, and they obviously don't work with single values.

I've seen several C methods that would achieve the result I'm looking for, but I don't have believe I have access to these methods without including the whole C library, or without writing platform-specific code.

My current solution is shown below, but I'd like to achieve this without allocating a new byte array.

Marshal.Copy(new byte[Length], 0, ptr   offset, length);

So is there a method in C#, or in an unmanaged language/library that I can use to fill an array (via a pointer) at a certain offset and for a certain length, with one single value (0)?

CodePudding user response:

Miraculously, ChatGPT came rather close when I asked what would be a good solution to this problem. It didn't figure it out, but it suggested that I use spans.

As such, this is the solution I've come up with:

Span<byte> span = new Span<byte>(ptr   offset, Length);
span.Fill(0);

This solution is about 25 times faster than having to allocate a byte array for very large arrays.

Example benchmarks:

    int size = 100_000;
    nint ArrayPointer = Marshal.AllocHGlobal(size);
    int trials = 1_000_000;

    // Runtime was 1582ms
    Benchmark("Fill with span", () =>
    {
        Span<byte> span = new Span<byte>((void*) ArrayPointer, size);
        span.Fill(0);
    }, trials);

    // Runtime was 40681ms
    Benchmark("Fill with allocation", () =>
    {
        Marshal.Copy(new byte[size], 0, ArrayPointer, size);
    }, trials);

    // Far too slow to get a result with these settings
    Benchmark("Fill individually", () =>
    {
        for (int i = 0; i < size; i  )
        {
            Marshal.WriteByte(ArrayPointer   i, 0);
        }
    }, trials);

    // Results with size = 100_000 and trials = 100_000
    // Fill with span: 176ms
    // Fill with allocation: 4382ms
    // Fill individually: 24672ms

CodePudding user response:

You can use Fill for this

arrayName.Fill('X',4,10)  // fill character array at index 4 for 10 elements with character X

https://learn.microsoft.com/en-us/dotnet/api/system.array.fill?view=net-7.0

Note: The documentation for C# is quite good. You can go to the website and see all the Methods for array. If you really care how this is implemented you could even go to github and read the source code.

  • Related