std.mem: Improve writeIntSlice performance

This commit is contained in:
joadnacer 2023-10-15 23:14:46 +01:00 committed by Andrew Kelley
parent 14efbf5ed1
commit 7b9165b375

View File

@ -1911,7 +1911,7 @@ pub fn writePackedInt(comptime T: type, bytes: []u8, bit_offset: usize, value: T
/// Any extra bytes in buffer after writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntLittle
/// instead.
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
fn writeIntSliceLittleNative(comptime T: type, buffer: []u8, value: T) void {
assert(buffer.len >= @divExact(@typeInfo(T).Int.bits, 8));
if (@typeInfo(T).Int.bits == 0) {
@ -1921,21 +1921,27 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
buffer[0] = @as(u8, @bitCast(value));
return;
}
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
const uint = std.meta.Int(.unsigned, @typeInfo(T).Int.bits);
var bits = @as(uint, @bitCast(value));
for (buffer) |*b| {
b.* = @as(u8, @truncate(bits));
bits >>= 8;
}
const write_end = @divExact(@typeInfo(T).Int.bits, 8);
@as(*align(1) T, @ptrCast(buffer)).* = value;
@memset(buffer[write_end..], 0);
}
fn writeIntSliceLittleForeign(comptime T: type, buffer: []u8, value: T) void {
return writeIntSliceLittleNative(T, buffer, @byteSwap(value));
}
pub const writeIntSliceLittle = switch (native_endian) {
.Little => writeIntSliceLittleNative,
.Big => writeIntSliceLittleForeign,
};
/// Writes a twos-complement big-endian integer to memory.
/// Asserts that buffer.len >= @typeInfo(T).Int.bits / 8.
/// The bit count of T must be divisible by 8.
/// Any extra bytes in buffer before writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntBig instead.
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
fn writeIntSliceBigNative(comptime T: type, buffer: []u8, value: T) void {
assert(buffer.len >= @divExact(@typeInfo(T).Int.bits, 8));
if (@typeInfo(T).Int.bits == 0) {
@ -1946,25 +1952,28 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
return;
}
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
const uint = std.meta.Int(.unsigned, @typeInfo(T).Int.bits);
var bits = @as(uint, @bitCast(value));
var index: usize = buffer.len;
while (index != 0) {
index -= 1;
buffer[index] = @as(u8, @truncate(bits));
bits >>= 8;
}
const write_start = buffer.len - @divExact(@typeInfo(T).Int.bits, 8);
@memset(buffer[0..write_start], 0);
@as(*align(1) T, @ptrCast(buffer[write_start..])).* = value;
}
fn writeIntSliceBigForeign(comptime T: type, buffer: []u8, value: T) void {
return writeIntSliceBigNative(T, buffer, @byteSwap(value));
}
pub const writeIntSliceBig = switch (native_endian) {
.Little => writeIntSliceBigForeign,
.Big => writeIntSliceBigNative,
};
pub const writeIntSliceNative = switch (native_endian) {
.Little => writeIntSliceLittle,
.Big => writeIntSliceBig,
.Little => writeIntSliceLittleNative,
.Big => writeIntSliceBigNative,
};
pub const writeIntSliceForeign = switch (native_endian) {
.Little => writeIntSliceBig,
.Big => writeIntSliceLittle,
.Little => writeIntSliceBigForeign,
.Big => writeIntSliceLittleForeign,
};
/// Writes a twos-complement integer to memory, with the specified endianness.