From d47a24c1c241cfe54247b452bb65aaa26fbc906d Mon Sep 17 00:00:00 2001 From: Poppyto Date: Mon, 5 Dec 2022 04:49:45 +0100 Subject: [PATCH] Remove char[] allocations from RegistryKey and List copy to Array (#78737) * Avoid redondant verification EnsureNotDisposed() already called by SubKeyCount & ValueCount. * Replace List by string[] to avoid List.ToArray() copy (it must handle rare cases where there are more or less elements during the loop). * Apply suggestions from code review Co-authored-by: Stephen Toub --- .../src/Microsoft/Win32/RegistryKey.cs | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs index 31168f59d2719..023b22f198ee8 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs @@ -784,7 +784,6 @@ public static RegistryKey FromHandle(SafeRegistryHandle handle, RegistryView vie /// All subkey names. public string[] GetSubKeyNames() { - EnsureNotDisposed(); int subkeys = SubKeyCount; if (subkeys <= 0) @@ -792,16 +791,17 @@ public string[] GetSubKeyNames() return Array.Empty(); } - List names = new List(subkeys); - Span name = stackalloc char[MaxKeyLength + 1]; + string[] names = new string[subkeys]; + Span nameSpan = stackalloc char[MaxKeyLength + 1]; int result; - int nameLength = name.Length; + int nameLength = nameSpan.Length; + int cpt = 0; while ((result = Interop.Advapi32.RegEnumKeyEx( _hkey, - names.Count, - ref MemoryMarshal.GetReference(name), + cpt, + ref MemoryMarshal.GetReference(nameSpan), ref nameLength, null, null, @@ -811,9 +811,15 @@ ref MemoryMarshal.GetReference(name), switch (result) { case Interop.Errors.ERROR_SUCCESS: - names.Add(new string(name.Slice(0, nameLength))); - nameLength = name.Length; + if (cpt >= names.Length) // possible new item during loop + { + Array.Resize(ref names, names.Length * 2); + } + + names[cpt++] = new string(nameSpan.Slice(0, nameLength)); + nameLength = nameSpan.Length; break; + default: // Throw the error Win32Error(result, null); @@ -821,7 +827,13 @@ ref MemoryMarshal.GetReference(name), } } - return names.ToArray(); + // Shrink array to fit found items, if necessary + if (cpt < names.Length) + { + Array.Resize(ref names, cpt); + } + + return names; } /// Retrieves the count of values. @@ -858,8 +870,6 @@ public int ValueCount /// All value names. public unsafe string[] GetValueNames() { - EnsureNotDisposed(); - int values = ValueCount; if (values <= 0)