authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-03-16 17:37:31-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-03-22 16:02:58-07:00
log66dcebcc76d41b125e9c6de9fecd61a8b3a272da
treebf361e49b7d84a0692d8ae8d6b3c6bf0548eaf33
parent78ecf3bb3a8022eaaf2c59b590fc165e5491c73c

getenvW: Take advantage of sliceTo/indexOfScalarPos optimizations

Both sliceTo and indexOfScalarPos use SIMD when available to speed up the search. On my x86_64 machine, this leads to getenvW being around 2-3x faster overall. Additionally, any future improvements to sliceTo/indexOfScalarPos will benefit getenvW.

1 files changed, 15 insertions(+), 13 deletions(-)

lib/std/process.zig+15-13
...@@ -527,31 +527,33 @@ pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {...@@ -527,31 +527,33 @@ pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
527 @compileError("Windows-only");527 @compileError("Windows-only");
528 }528 }
529 const key_slice = mem.sliceTo(key, 0);529 const key_slice = mem.sliceTo(key, 0);
530 // '=' anywhere but the start makes this an invalid environment variable name
531 if (key_slice.len > 0 and std.mem.indexOfScalar(u16, key_slice[1..], '=') != null) {
532 return null;
533 }
530 const ptr = windows.peb().ProcessParameters.Environment;534 const ptr = windows.peb().ProcessParameters.Environment;
531 var i: usize = 0;535 var i: usize = 0;
532 while (ptr[i] != 0) {536 while (ptr[i] != 0) {
533 const key_start = i;537 const key_value = mem.sliceTo(ptr[i..], 0);
534538
535 // There are some special environment variables that start with =,539 // There are some special environment variables that start with =,
536 // so we need a special case to not treat = as a key/value separator540 // so we need a special case to not treat = as a key/value separator
537 // if it's the first character.541 // if it's the first character.
538 // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133542 // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
539 if (ptr[key_start] == '=') i += 1;543 const equal_search_start: usize = if (key_value[0] == '=') 1 else 0;
540544 const equal_index = std.mem.indexOfScalarPos(u16, key_value, equal_search_start, '=') orelse {
541 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}545 // This is enforced by CreateProcess.
542 const this_key = ptr[key_start..i];546 // If violated, CreateProcess will fail with INVALID_PARAMETER.
543547 unreachable; // must contain a =
544 if (ptr[i] == '=') i += 1;548 };
545
546 const value_start = i;
547 while (ptr[i] != 0) : (i += 1) {}
548 const this_value = ptr[value_start..i :0];
549549
550 const this_key = key_value[0..equal_index];
550 if (windows.eqlIgnoreCaseWTF16(key_slice, this_key)) {551 if (windows.eqlIgnoreCaseWTF16(key_slice, this_key)) {
551 return this_value;552 return key_value[equal_index + 1 ..];
552 }553 }
553554
554 i += 1; // skip over null byte555 // skip past the NUL terminator
556 i += key_value.len + 1;
555 }557 }
556 return null;558 return null;
557}559}