#How to read a binary file by `u16`'s instead of `u8`'s?

1 messages · Page 1 of 1 (latest)

rigid shadow
#

I'm trying to develop an emulator, and I'm struggling with finding a performant way to read the file and make an array with its data. The way I'm doing it now feels inefficient; it consists of me using the readToEndAlloc function to convert the data to an array of u8's, then combining the u8's into u16's in a BoundedArray by bitshifting each array[i] value left by 8 and logical OR'ing it with array[i + 1].

mighty citrus
#
std.mem.bytesAsSlice(u16, buffer)

read the file then run it through this

rigid shadow
wary pike
#

if you have an io.Reader, you can call readInt(u16, .little) on it.

#

with .big for big endian

rigid shadow
#

Thank you both! I think I landed on a possible solution. Does this seem efficient?

    const array = try rom.readToEndAlloc(allocator, rom_size);

    const slice = std.mem.bytesAsSlice(u16, array);

    for (0..slice.len) |i| {
        slice[i] = std.mem.toNative(u16, slice[i], .big);
    }
wary pike
#

that seems fine. not sure about mem.toNative just cause i haven't used it before. i might write it like this

    const slice = try allocator.alloc(u16, rom_size/2);

    for (0..slice.len) |i| {
        // if you're on a little platform
        slice[i] = @byteSwap(try rom.readInt(u16, .little));
        // if you're not sure whether you're on big or little
        // slice[i] = std.mem.nativeToBig(u16, try rom.readInt(u16, .little));
    }
wintry karma
#

Thats what toNative would do

#

Fwiw since you control how its allocated, youd be able to ensure that its 2 byte aligned
That way the cpu wont need to load/store one byte at a time
Although ofc idk what the opimized code gen would actually be like
And idk if itd make a real difference

rigid shadow
#

Woah, thanks! I didn't realize that the readInt function would work with iteration! I was struggling with using it, but now I kinda understand how it works.

After doing more research and finding out just how rare big-endianness is, I decided to settle on this approach, which just assumes the host's architecture is little-endian:

    const slice = try allocator.alloc(u16, rom_size / 2);

    for (0..slice.len) |i| {
        slice[i] = try rom.reader().readInt(u16, .big);
    }