Skip to content

Commit 18b86b7

Browse files
Merge pull request #4112 from arcadiogarcia/user/arcadiog/shorterExpressionStrings
Generate shorter expression animation strings from ExpressionNode
2 parents ee93385 + 1918c0d commit 18b86b7

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ExpressionNode.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Numerics;
8+
using System.Runtime.CompilerServices;
89
using Windows.UI;
910
using Windows.UI.Composition;
1011

@@ -283,9 +284,10 @@ internal void EnsureReferenceInfo()
283284

284285
// Create a map to store the generated paramNames for each CompObj
285286
_compObjToParamNameMap = new Dictionary<CompositionObject, string>();
287+
var paramCount = 0u;
286288
foreach (var compObj in compObjects)
287289
{
288-
string paramName = Guid.NewGuid().ToUppercaseAsciiLetters();
290+
string paramName = CreateUniqueParamNameFromIndex(paramCount++);
289291

290292
_compObjToParamNameMap.Add(compObj, paramName);
291293
}
@@ -312,6 +314,37 @@ internal void EnsureReferenceInfo()
312314
refNode.ParamName = paramName;
313315
}
314316
}
317+
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)
325+
{
326+
const int alphabetLength = 'Z' - 'A' + 1;
327+
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)
340+
{
341+
i--;
342+
343+
characters[totalCharacters++] = (char)('A' + (i % alphabetLength));
344+
}
345+
346+
return new string(characters, 0, totalCharacters);
347+
}
315348
}
316349

317350
/// <summary>
@@ -670,4 +703,4 @@ public ReferenceInfo(string paramName, CompositionObject compObj)
670703
/// <value>The subchannels.</value>
671704
protected internal string[] Subchannels { get; set; }
672705
}
673-
}
706+
}

Microsoft.Toolkit.Uwp.UI.Animations/Microsoft.Toolkit.Uwp.UI.Animations.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFrameworks>uap10.0.17763</TargetFrameworks>
5+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
56
</PropertyGroup>
67

78
<PropertyGroup>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Runtime.CompilerServices
6+
{
7+
/// <summary>
8+
/// Used to indicate to the compiler that the <c>.locals init</c> flag should not be set in method headers.
9+
/// </summary>
10+
/// <remarks>Internal copy from the BCL attribute.</remarks>
11+
[AttributeUsage(
12+
AttributeTargets.Module |
13+
AttributeTargets.Class |
14+
AttributeTargets.Struct |
15+
AttributeTargets.Interface |
16+
AttributeTargets.Constructor |
17+
AttributeTargets.Method |
18+
AttributeTargets.Property |
19+
AttributeTargets.Event,
20+
Inherited = false)]
21+
internal sealed class SkipLocalsInitAttribute : Attribute
22+
{
23+
}
24+
}

0 commit comments

Comments
 (0)