From ba445013c472abd874f7b041d9ad8f3c72197807 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Sat, 29 Jan 2022 09:10:22 -0700 Subject: [PATCH] improve comptime windows GUID.parse performance I found that after switching from my custom Guid parser to the one in std that it increased zigwin32 build times substantially (from 40 seconds to over 10 minutes). More information can be found in the benchmark PR I created here: https://github.com/ziglang/gotta-go-fast/pull/21 . This PR ports my GUID parser to std so all projects can leverage the faster comptime performance. --- lib/std/os/windows.zig | 84 ++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 4ddba2f72a4f018839cc85f50a1048dbc76270e2..c8321495775667e86466409465ab771f95308e02 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -2738,50 +2738,54 @@ pub const GUID = extern struct { Data3: u16, Data4: [8]u8, - pub fn parse(str: []const u8) GUID { - var guid: GUID = undefined; - var index: usize = 0; - assert(str[index] == '{'); - index += 1; - - guid.Data1 = std.fmt.parseUnsigned(u32, str[index .. index + 8], 16) catch unreachable; - index += 8; - - assert(str[index] == '-'); - index += 1; - - guid.Data2 = std.fmt.parseUnsigned(u16, str[index .. index + 4], 16) catch unreachable; - index += 4; - - assert(str[index] == '-'); - index += 1; - - guid.Data3 = std.fmt.parseUnsigned(u16, str[index .. index + 4], 16) catch unreachable; - index += 4; - - assert(str[index] == '-'); - index += 1; - - guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable; - index += 2; - guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable; - index += 2; - - assert(str[index] == '-'); - index += 1; - - var i: usize = 2; - while (i < guid.Data4.len) : (i += 1) { - guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable; - index += 2; + const hex_offsets = switch (builtin.target.cpu.arch.endian()) { + .Big => [16]u6{ + 0, 2, 4, 6, + 9, 11, 14, 16, + 19, 21, 24, 26, + 28, 30, 32, 34, + }, + .Little => [16]u6{ + 6, 4, 2, 0, + 11, 9, 16, 14, + 19, 21, 24, 26, + 28, 30, 32, 34, + }, + }; + + pub fn parse(s: []const u8) GUID { + assert(s[0] == '{'); + assert(s[37] == '}'); + return parseNoBraces(s[1 .. s.len - 1]) catch @panic("invalid GUID string"); + } + + pub fn parseNoBraces(s: []const u8) !GUID { + assert(s.len == 36); + assert(s[8] == '-'); + assert(s[13] == '-'); + assert(s[18] == '-'); + assert(s[23] == '-'); + var bytes: [16]u8 = undefined; + for (hex_offsets) |hex_offset, i| { + bytes[i] = (try std.fmt.charToDigit(s[hex_offset], 16)) << 4 | + try std.fmt.charToDigit(s[hex_offset + 1], 16); } - - assert(str[index] == '}'); - index += 1; - return guid; + return @bitCast(GUID, bytes); } }; +test "GUID" { + try std.testing.expectEqual( + GUID{ + .Data1 = 0x01234567, + .Data2 = 0x89ab, + .Data3 = 0xef10, + .Data4 = "\x32\x54\x76\x98\xba\xdc\xfe\x91".*, + }, + GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}"), + ); +} + pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"); pub const KF_FLAG_DEFAULT = 0; -- 2.54.0