|
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