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:
Eric Erhardt 2022-03-08 21:45:21 -06:00
Родитель cc1e48974d
Коммит 9f2e493f4c
6 изменённых файлов: 138 добавлений и 51 удалений

Просмотреть файл

@ -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}")] [DebuggerDisplay("Red={Red}, Green={Green}, Blue={Blue}, Alpha={Alpha}")]
[TypeConverter(typeof(Converters.ColorTypeConverter))] [TypeConverter(typeof(Converters.ColorTypeConverter))]
public class Color public partial class Color
{ {
public readonly float Red; public readonly float Red;
public readonly float Green; public readonly float Green;
@ -382,50 +382,7 @@ namespace Microsoft.Maui.Graphics
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f); return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
} }
public static Color FromArgb(string colorAsHex) public static Color FromArgb(string colorAsHex) => FromArgbImplementation(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 FromHsla(float h, float s, float l, float a = 1) public static Color FromHsla(float h, float s, float l, float a = 1)
{ {

Просмотреть файл

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <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> <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) --> <!-- Optional: Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
<PublishRepositoryUrl>true</PublishRepositoryUrl> <PublishRepositoryUrl>true</PublishRepositoryUrl>
@ -23,9 +23,6 @@
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" Condition="$(TargetFramework.StartsWith('netstandard'))" /> <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'))" /> <PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="$(TargetFramework.Contains('-windows'))" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Windows\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Update="iOS\GraphicsiOS.resx"> <EmbeddedResource Update="iOS\GraphicsiOS.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>

Просмотреть файл

@ -52,10 +52,15 @@
<None Include="**\*.Standard.cs"/> <None Include="**\*.Standard.cs"/>
<Compile Remove="**\Standard\*.cs"/> <Compile Remove="**\Standard\*.cs"/>
<None Include="**\Standard\*.cs"/> <None Include="**\Standard\*.cs"/>
<Compile Remove="**\Standard\*.cs"/>
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" /> <Reference Include="System.Numerics.Vectors" />
</ItemGroup> </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 "> <ItemGroup Condition="$(TargetFramework.StartsWith('netcoreapp')) != true ">
<Compile Remove="**\*.Win32.cs"/> <Compile Remove="**\*.Win32.cs"/>
<None Include="**\*.Win32.cs"/> <None Include="**\*.Win32.cs"/>

Просмотреть файл

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>