|
5 | 5 | using System; |
6 | 6 | using System.Collections.Generic; |
7 | 7 | using System.Numerics; |
| 8 | +using System.Runtime.CompilerServices; |
8 | 9 | using Windows.UI; |
9 | 10 | using Windows.UI.Composition; |
10 | 11 |
|
@@ -283,10 +284,10 @@ internal void EnsureReferenceInfo() |
283 | 284 |
|
284 | 285 | // Create a map to store the generated paramNames for each CompObj |
285 | 286 | _compObjToParamNameMap = new Dictionary<CompositionObject, string>(); |
286 | | - var paramCount = 0; |
| 287 | + var paramCount = 0u; |
287 | 288 | foreach (var compObj in compObjects) |
288 | 289 | { |
289 | | - string paramName = UniqueParamNameFromIndex(paramCount++); // Guid.NewGuid().ToUppercaseAsciiLetters(); |
| 290 | + string paramName = CreateUniqueParamNameFromIndex(paramCount++); |
290 | 291 |
|
291 | 292 | _compObjToParamNameMap.Add(compObj, paramName); |
292 | 293 | } |
@@ -314,20 +315,35 @@ internal void EnsureReferenceInfo() |
314 | 315 | } |
315 | 316 | } |
316 | 317 |
|
317 | | - // Generates Excel-column-like identifiers, e.g. A, B, ..., Z, AA, AB... |
318 | | - string UniqueParamNameFromIndex(int i) |
| 318 | + // Generates Excel-column-like identifiers, e.g. A, B, ..., Z, AA, BA... |
| 319 | + // This implementation aggregates characters in reverse order to avoid having to |
| 320 | + // precompute the exact number of characters in the resulting string. This is not |
| 321 | + // important in this context as the only critical property to maintain is to have |
| 322 | + // a unique mapping to each input value to the resulting sequence of letters. |
| 323 | + [SkipLocalsInit] |
| 324 | + static unsafe string CreateUniqueParamNameFromIndex(uint i) |
319 | 325 | { |
320 | | - var alphabetLength = 'Z' - 'A' + 1; |
321 | | - var paramName = ((char)('A' + (i % alphabetLength))).ToString(); |
| 326 | + const int alphabetLength = 'Z' - 'A' + 1; |
322 | 327 |
|
323 | | - while (i / alphabetLength > 0) |
| 328 | + // The total length of the resulting sequence is guaranteed to always |
| 329 | + // be less than 8, given that log26(4294967295) ≈ 6.8. In this case we |
| 330 | + // are just allocating the immediate next power of two following that. |
| 331 | + // Note: this is using a char* buffer instead of Span<char> as the latter |
| 332 | + // is not referenced here, and we don't want to pull in an extra package. |
| 333 | + char* characters = stackalloc char[8]; |
| 334 | + |
| 335 | + characters[0] = (char)('A' + (i % alphabetLength)); |
| 336 | + |
| 337 | + int totalCharacters = 1; |
| 338 | + |
| 339 | + while ((i /= alphabetLength) > 0) |
324 | 340 | { |
325 | | - i = (i / alphabetLength) - 1; |
326 | | - var nextCharacter = (char)('A' + (i % alphabetLength)); |
327 | | - paramName = nextCharacter + paramName; |
| 341 | + i--; |
| 342 | + |
| 343 | + characters[totalCharacters++] = (char)('A' + (i % alphabetLength)); |
328 | 344 | } |
329 | 345 |
|
330 | | - return paramName; |
| 346 | + return new string(characters, 0, totalCharacters); |
331 | 347 | } |
332 | 348 | } |
333 | 349 |
|
|
0 commit comments