Commit 7b9165b375

joadnacer <joad.nacer@gmail.com>
2023-10-16 00:14:46
std.mem: Improve writeIntSlice performance
1 parent 14efbf5
Changed files (1)
lib
lib/std/mem.zig
@@ -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.