Skip to content

Commit 90fc9ce

Browse files
committed
getenvW: Reduce the amount of parsing done on unmatchable keys
Instead of parsing the full key and value for each environment variable before checking the key for (case-insensitive) equality, we skip to the next environment variable once it's no longer possible for the key to match. This makes getting environment variables about 2x faster across the board on Windows. However, most/all of this gain actually comes from the usage of `std.mem.sliceTo` to find the end of the current environment variable since it uses SIMD when available. Note: We still have to scan to find the end of each environment variable (even the ones that are skipped; we only know where it ends by a NUL terminator), so this strategy doesn't provide the same speedup on Windows as it does on POSIX
1 parent 379effb commit 90fc9ce

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

lib/std/process.zig

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -526,32 +526,29 @@ pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
526526
if (native_os != .windows) {
527527
@compileError("Windows-only");
528528
}
529-
const key_slice = mem.sliceTo(key, 0);
530529
const ptr = windows.peb().ProcessParameters.Environment;
531530
var i: usize = 0;
532-
while (ptr[i] != 0) {
531+
while (ptr[i] != 0) : (i += mem.sliceTo(ptr[i..], 0).len + 1) {
533532
const key_start = i;
534533

535534
// There are some special environment variables that start with =,
536535
// so we need a special case to not treat = as a key/value separator
537536
// if it's the first character.
538537
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
539-
if (ptr[key_start] == '=') i += 1;
540-
541-
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
542-
const this_key = ptr[key_start..i];
543-
544-
if (ptr[i] == '=') i += 1;
545-
546-
const value_start = i;
547-
while (ptr[i] != 0) : (i += 1) {}
548-
const this_value = ptr[value_start..i :0];
538+
if (ptr[key_start] == '=') {
539+
if (key[0] != '=') continue;
540+
i += 1;
541+
}
549542

550-
if (windows.eqlIgnoreCaseWTF16(key_slice, this_key)) {
551-
return this_value;
543+
// Note: A '=' being present after the name is enforced by CreateProcess.
544+
// If violated, CreateProcess will fail with INVALID_PARAMETER.
545+
const upcaseW = windows.ntdll.RtlUpcaseUnicodeChar;
546+
while (ptr[i] != 0 and key[i - key_start] != 0) : (i += 1) {
547+
if (upcaseW(ptr[i]) != upcaseW(key[i - key_start])) break;
552548
}
549+
if ((key[i - key_start] != 0) or (ptr[i] != '=')) continue;
553550

554-
i += 1; // skip over null byte
551+
return mem.sliceTo(ptr[i + 1 ..], 0);
555552
}
556553
return null;
557554
}

0 commit comments

Comments
 (0)