Optimize Color Parsing
This method was showing up in a profile of the startup of the .NET Podcasts app. Optimize it to not allocate intermediate strings on .NET Core, and instead use Span operations.
This commit is contained in:
Родитель
cc1e48974d
Коммит
9f2e493f4c
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Maui.Graphics
|
||||
{
|
||||
public partial class Color
|
||||
{
|
||||
private static Color FromArgbImplementation(string colorAsHex)
|
||||
{
|
||||
ReadOnlySpan<char> colorAsHexSpan = colorAsHex;
|
||||
|
||||
//Skip # if present
|
||||
if (colorAsHexSpan[0] == '#')
|
||||
colorAsHexSpan = colorAsHexSpan.Slice(1);
|
||||
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int alpha = 255;
|
||||
|
||||
if (colorAsHexSpan.Length == 6)
|
||||
{
|
||||
//#RRGGBB
|
||||
red = ParseInt(colorAsHexSpan.Slice(0, 2));
|
||||
green = ParseInt(colorAsHexSpan.Slice(2, 2));
|
||||
blue = ParseInt(colorAsHexSpan.Slice(4, 2));
|
||||
}
|
||||
else if (colorAsHexSpan.Length == 3)
|
||||
{
|
||||
//#RGB
|
||||
Span<char> temp = stackalloc char[2];
|
||||
temp[0] = temp[1] = colorAsHexSpan[0];
|
||||
red = ParseInt(temp);
|
||||
|
||||
temp[0] = temp[1] = colorAsHexSpan[1];
|
||||
green = ParseInt(temp);
|
||||
|
||||
temp[0] = temp[1] = colorAsHexSpan[2];
|
||||
blue = ParseInt(temp);
|
||||
}
|
||||
else if (colorAsHexSpan.Length == 4)
|
||||
{
|
||||
//#ARGB
|
||||
Span<char> temp = stackalloc char[2];
|
||||
temp[0] = temp[1] = colorAsHexSpan[0];
|
||||
alpha = ParseInt(temp);
|
||||
|
||||
temp[0] = temp[1] = colorAsHexSpan[1];
|
||||
red = ParseInt(temp);
|
||||
|
||||
temp[0] = temp[1] = colorAsHexSpan[2];
|
||||
green = ParseInt(temp);
|
||||
|
||||
temp[0] = temp[1] = colorAsHexSpan[3];
|
||||
blue = ParseInt(temp);
|
||||
}
|
||||
else if (colorAsHexSpan.Length == 8)
|
||||
{
|
||||
//#AARRGGBB
|
||||
alpha = ParseInt(colorAsHexSpan.Slice(0, 2));
|
||||
red = ParseInt(colorAsHexSpan.Slice(2, 2));
|
||||
green = ParseInt(colorAsHexSpan.Slice(4, 2));
|
||||
blue = ParseInt(colorAsHexSpan.Slice(6, 2));
|
||||
}
|
||||
|
||||
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
|
||||
}
|
||||
|
||||
private static int ParseInt(ReadOnlySpan<char> s) =>
|
||||
int.Parse(s, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Maui.Graphics
|
||||
{
|
||||
public partial class Color
|
||||
{
|
||||
private static Color FromArgbImplementation(string colorAsHex)
|
||||
{
|
||||
//Skip # if present
|
||||
if (colorAsHex[0] == '#')
|
||||
colorAsHex = colorAsHex.Substring(1);
|
||||
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int alpha = 255;
|
||||
|
||||
if (colorAsHex.Length == 6)
|
||||
{
|
||||
//#RRGGBB
|
||||
red = ParseInt(colorAsHex.Substring(0, 2));
|
||||
green = ParseInt(colorAsHex.Substring(2, 2));
|
||||
blue = ParseInt(colorAsHex.Substring(4, 2));
|
||||
}
|
||||
else if (colorAsHex.Length == 3)
|
||||
{
|
||||
//#RGB
|
||||
red = ParseInt($"{colorAsHex[0]}{colorAsHex[0]}");
|
||||
green = ParseInt($"{colorAsHex[1]}{colorAsHex[1]}");
|
||||
blue = ParseInt($"{colorAsHex[2]}{colorAsHex[2]}");
|
||||
}
|
||||
else if (colorAsHex.Length == 4)
|
||||
{
|
||||
//#ARGB
|
||||
alpha = ParseInt($"{colorAsHex[0]}{colorAsHex[0]}");
|
||||
red = ParseInt($"{colorAsHex[1]}{colorAsHex[1]}");
|
||||
green = ParseInt($"{colorAsHex[2]}{colorAsHex[2]}");
|
||||
blue = ParseInt($"{colorAsHex[3]}{colorAsHex[3]}");
|
||||
}
|
||||
else if (colorAsHex.Length == 8)
|
||||
{
|
||||
//#AARRGGBB
|
||||
alpha = ParseInt(colorAsHex.Substring(0, 2));
|
||||
red = ParseInt(colorAsHex.Substring(2, 2));
|
||||
green = ParseInt(colorAsHex.Substring(4, 2));
|
||||
blue = ParseInt(colorAsHex.Substring(6, 2));
|
||||
}
|
||||
|
||||
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
|
||||
}
|
||||
|
||||
private static int ParseInt(string s) =>
|
||||
int.Parse(s, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace Microsoft.Maui.Graphics
|
|||
{
|
||||
[DebuggerDisplay("Red={Red}, Green={Green}, Blue={Blue}, Alpha={Alpha}")]
|
||||
[TypeConverter(typeof(Converters.ColorTypeConverter))]
|
||||
public class Color
|
||||
public partial class Color
|
||||
{
|
||||
public readonly float Red;
|
||||
public readonly float Green;
|
||||
|
@ -382,50 +382,7 @@ namespace Microsoft.Maui.Graphics
|
|||
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
|
||||
}
|
||||
|
||||
public static Color FromArgb(string colorAsHex)
|
||||
{
|
||||
//Remove # if present
|
||||
if (colorAsHex.IndexOf('#') != -1)
|
||||
colorAsHex = colorAsHex.Replace("#", "");
|
||||
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int alpha = 255;
|
||||
|
||||
if (colorAsHex.Length == 6)
|
||||
{
|
||||
//#RRGGBB
|
||||
red = int.Parse(colorAsHex.Substring(0, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
green = int.Parse(colorAsHex.Substring(2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
blue = int.Parse(colorAsHex.Substring(4, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (colorAsHex.Length == 3)
|
||||
{
|
||||
//#RGB
|
||||
red = int.Parse($"{colorAsHex[0]}{colorAsHex[0]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
green = int.Parse($"{colorAsHex[1]}{colorAsHex[1]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
blue = int.Parse($"{colorAsHex[2]}{colorAsHex[2]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (colorAsHex.Length == 4)
|
||||
{
|
||||
//#ARGB
|
||||
alpha = int.Parse($"{colorAsHex[0]}{colorAsHex[0]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
red = int.Parse($"{colorAsHex[1]}{colorAsHex[1]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
green = int.Parse($"{colorAsHex[2]}{colorAsHex[2]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
blue = int.Parse($"{colorAsHex[3]}{colorAsHex[3]}", NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (colorAsHex.Length == 8)
|
||||
{
|
||||
//#AARRGGBB
|
||||
alpha = int.Parse(colorAsHex.Substring(0, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
red = int.Parse(colorAsHex.Substring(2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
green = int.Parse(colorAsHex.Substring(4, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
blue = int.Parse(colorAsHex.Substring(6, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
|
||||
}
|
||||
public static Color FromArgb(string colorAsHex) => FromArgbImplementation(colorAsHex);
|
||||
|
||||
public static Color FromHsla(float h, float s, float l, float a = 1)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0-ios;net6.0-android;net6.0-maccatalyst;net6.0-macos;net6.0-tizen6.5</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net6.0-ios;net6.0-android;net6.0-maccatalyst;net6.0-macos;net6.0-tizen6.5</TargetFrameworks>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows')) and '$(MSBuildRuntimeType)' == 'Full'">$(TargetFrameworks);net6.0-windows10.0.18362</TargetFrameworks>
|
||||
<!-- Optional: Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
|
@ -23,9 +23,6 @@
|
|||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" Condition="$(TargetFramework.StartsWith('netstandard'))" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="$(TargetFramework.Contains('-windows'))" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Windows\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="iOS\GraphicsiOS.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
|
|
|
@ -52,10 +52,15 @@
|
|||
<None Include="**\*.Standard.cs"/>
|
||||
<Compile Remove="**\Standard\*.cs"/>
|
||||
<None Include="**\Standard\*.cs"/>
|
||||
<Compile Remove="**\Standard\*.cs"/>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
|
||||
<Compile Remove="**\*.NETCoreApp.cs"/>
|
||||
<None Include="**\*.NETCoreApp.cs"/>
|
||||
<Compile Remove="**\NETCoreApp\*.cs"/>
|
||||
<None Include="**\NETCoreApp\*.cs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith('netcoreapp')) != true ">
|
||||
<Compile Remove="**\*.Win32.cs"/>
|
||||
<None Include="**\*.Win32.cs"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче