authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2022-01-29 09:10:22-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-29 18:10:22+02:00
logba445013c472abd874f7b041d9ad8f3c72197807
treed2c3cb01fc822639cc9c279320848d6decbf248c
parent8d0c17f5e4adf83a2a1e20f2c2230a64dad78121
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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.

1 files changed, 43 insertions(+), 39 deletions(-)

lib/std/os/windows.zig+43-39
......@@ -2738,50 +2738,54 @@ pub const GUID = extern struct {
27382738 Data3: u16,
27392739 Data4: [8]u8,
27402740
2741 pub fn parse(str: []const u8) GUID {
2742 var guid: GUID = undefined;
2743 var index: usize = 0;
2744 assert(str[index] == '{');
2745 index += 1;
2746
2747 guid.Data1 = std.fmt.parseUnsigned(u32, str[index .. index + 8], 16) catch unreachable;
2748 index += 8;
2749
2750 assert(str[index] == '-');
2751 index += 1;
2752
2753 guid.Data2 = std.fmt.parseUnsigned(u16, str[index .. index + 4], 16) catch unreachable;
2754 index += 4;
2755
2756 assert(str[index] == '-');
2757 index += 1;
2758
2759 guid.Data3 = std.fmt.parseUnsigned(u16, str[index .. index + 4], 16) catch unreachable;
2760 index += 4;
2761
2762 assert(str[index] == '-');
2763 index += 1;
2764
2765 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
2766 index += 2;
2767 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
2768 index += 2;
2769
2770 assert(str[index] == '-');
2771 index += 1;
2741 const hex_offsets = switch (builtin.target.cpu.arch.endian()) {
2742 .Big => [16]u6{
2743 0, 2, 4, 6,
2744 9, 11, 14, 16,
2745 19, 21, 24, 26,
2746 28, 30, 32, 34,
2747 },
2748 .Little => [16]u6{
2749 6, 4, 2, 0,
2750 11, 9, 16, 14,
2751 19, 21, 24, 26,
2752 28, 30, 32, 34,
2753 },
2754 };
27722755
2773 var i: usize = 2;
2774 while (i < guid.Data4.len) : (i += 1) {
2775 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
2776 index += 2;
2756 pub fn parse(s: []const u8) GUID {
2757 assert(s[0] == '{');
2758 assert(s[37] == '}');
2759 return parseNoBraces(s[1 .. s.len - 1]) catch @panic("invalid GUID string");
2760 }
2761
2762 pub fn parseNoBraces(s: []const u8) !GUID {
2763 assert(s.len == 36);
2764 assert(s[8] == '-');
2765 assert(s[13] == '-');
2766 assert(s[18] == '-');
2767 assert(s[23] == '-');
2768 var bytes: [16]u8 = undefined;
2769 for (hex_offsets) |hex_offset, i| {
2770 bytes[i] = (try std.fmt.charToDigit(s[hex_offset], 16)) << 4 |
2771 try std.fmt.charToDigit(s[hex_offset + 1], 16);
27772772 }
2778
2779 assert(str[index] == '}');
2780 index += 1;
2781 return guid;
2773 return @bitCast(GUID, bytes);
27822774 }
27832775};
27842776
2777test "GUID" {
2778 try std.testing.expectEqual(
2779 GUID{
2780 .Data1 = 0x01234567,
2781 .Data2 = 0x89ab,
2782 .Data3 = 0xef10,
2783 .Data4 = "\x32\x54\x76\x98\xba\xdc\xfe\x91".*,
2784 },
2785 GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}"),
2786 );
2787}
2788
27852789pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
27862790
27872791pub const KF_FLAG_DEFAULT = 0;