-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Remove allocations on all base converters, improve TokenizerHelper #9364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
h3xds1nz
wants to merge
20
commits into
dotnet:main
Choose a base branch
from
h3xds1nz:remove-allocs-on-lengthconverter
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
10731fe
Simplify CanConvertTo
h3xds1nz 209820d
Simplify ConvertFrom
h3xds1nz 1b2b68d
Simplify ConvertTo, use pattern matching
h3xds1nz 6c384c2
Remove allocations on Tokenizer for standard converters
h3xds1nz 0c8afb0
Remove allocations on Tokenizer for generated structs
h3xds1nz 50835dd
Remove allocations on Tokenizer for generated collections
h3xds1nz ed46efe
Adjust MilCodeGen to generate code that corresponds to edits on gener…
h3xds1nz 7b87ece
Simplify CanConvertTo in Corner/Cache
h3xds1nz fb3ba6f
Simplify ConvertFrom methods
h3xds1nz e7b2662
Simplify ConvertTo methods
h3xds1nz 8c87862
Final formatting, clean up redundant usings
h3xds1nz 3e94449
Stop double checking in IsWhiteSpace, convert fields that could be re…
h3xds1nz cb6fe8e
Add a ref struct implementation of TokenizerHelper, use it in Present…
h3xds1nz db159b5
Use ValueTokenizerHelper in generated structs/collections
h3xds1nz c578f70
Use ValueTokenizerHelper in KeySplineConverter, make it allocation free
h3xds1nz a239e7c
Remove double inclusion of ValueTokenizerHelper
h3xds1nz 3d23f75
Comments/code style adjustments, some documentation, no code changes
h3xds1nz e65a468
Fix string comparisons
h3xds1nz 3c551cb
Fix ValueTokenizerHelper IDE0073 and move to file-scoped namespace
h3xds1nz 8b733a1
CR notes
h3xds1nz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
142 changes: 69 additions & 73 deletions
142
...soft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,125 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using MS.Internal; | ||
using System.ComponentModel; | ||
using System.ComponentModel.Design.Serialization; | ||
using System.Runtime.CompilerServices; | ||
using System.Windows.Media.Animation; | ||
using System.ComponentModel; | ||
using System.Globalization; | ||
using System.Reflection; | ||
using System.Windows.Media.Animation; | ||
using MS.Internal; | ||
|
||
namespace System.Windows | ||
{ | ||
/// <summary> | ||
/// PointConverter - Converter class for converting instances of other types to Point instances | ||
/// Converter class for converting instances of <see cref="KeySpline"/> to <see cref="string"/> and vice versa. | ||
/// </summary> | ||
/// <ExternalAPI/> | ||
public class KeySplineConverter : TypeConverter | ||
{ | ||
/// <summary> | ||
/// CanConvertFrom - Returns whether or not this class can convert from a given type | ||
/// </summary> | ||
/// <ExternalAPI/> | ||
/// <returns> | ||
/// <see langword="true"/> if the given <paramref name="sourceType"/> can be converted from, <see langword="false"/> otherwise. | ||
/// </returns> | ||
/// <param name="typeDescriptor">The <see cref="ITypeDescriptorContext"/> for this call.</param> | ||
/// <param name="destinationType">The <see cref="Type"/> being queried for support.</param> | ||
public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptor, Type destinationType) | ||
{ | ||
if (destinationType == typeof(string)) | ||
{ | ||
return true; | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
return destinationType == typeof(string); | ||
} | ||
|
||
/// <summary> | ||
/// TypeConverter method override. | ||
/// </summary> | ||
/// <param name="context">ITypeDescriptorContext</param> | ||
/// <param name="destinationType">Type to convert to</param> | ||
/// <returns>true if conversion is possible</returns> | ||
/// <ExternalAPI/> | ||
/// <returns> | ||
/// <see langword="true"/> if this class can convert to <paramref name="destinationType"/>, <see langword="false"/> otherwise. | ||
/// </returns> | ||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) | ||
{ | ||
if ( destinationType == typeof(InstanceDescriptor) | ||
|| destinationType == typeof(string)) | ||
{ | ||
return true; | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string); | ||
} | ||
|
||
/// <summary> | ||
/// ConvertFrom | ||
/// Converts <paramref name="value"/> of <see langword="string"/> type to its <see cref="KeySpline"/> represensation. | ||
/// </summary> | ||
public override object ConvertFrom( | ||
ITypeDescriptorContext context, | ||
CultureInfo cultureInfo, | ||
object value) | ||
/// <param name="context">The <see cref="ITypeDescriptorContext"/> for this call.</param> | ||
/// <param name="cultureInfo">The <see cref="CultureInfo"/> which is respected during conversion.</param> | ||
/// <param name="value"> The object to convert to a <see cref="KeySpline"/>.</param> | ||
/// <returns>A new instance of <see cref="KeySpline"/> class representing the data contained in <paramref name="value"/>.</returns> | ||
/// <exception cref="NotSupportedException">Thrown in case the <paramref name="value"/> was not a <see cref="string"/>.</exception> | ||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo cultureInfo, object value) | ||
{ | ||
string stringValue = value as string; | ||
|
||
if (value == null) | ||
{ | ||
if (value is not string stringValue) | ||
throw new NotSupportedException(SR.Converter_ConvertFromNotSupported); | ||
} | ||
|
||
TokenizerHelper th = new TokenizerHelper(stringValue, cultureInfo); | ||
ValueTokenizerHelper tokenizer = new(stringValue, cultureInfo); | ||
|
||
return new KeySpline( | ||
Convert.ToDouble(th.NextTokenRequired(), cultureInfo), | ||
Convert.ToDouble(th.NextTokenRequired(), cultureInfo), | ||
Convert.ToDouble(th.NextTokenRequired(), cultureInfo), | ||
Convert.ToDouble(th.NextTokenRequired(), cultureInfo)); | ||
double.Parse(tokenizer.NextTokenRequired(), cultureInfo), | ||
double.Parse(tokenizer.NextTokenRequired(), cultureInfo), | ||
double.Parse(tokenizer.NextTokenRequired(), cultureInfo), | ||
double.Parse(tokenizer.NextTokenRequired(), cultureInfo)); | ||
} | ||
|
||
/// <summary> | ||
/// TypeConverter method implementation. | ||
/// Attempt to convert a <see cref="KeySpline"/> class to the <paramref name="destinationType"/>. | ||
/// </summary> | ||
/// <param name="context">ITypeDescriptorContext</param> | ||
/// <param name="cultureInfo">current culture (see CLR specs), null is a valid value</param> | ||
/// <param name="value">value to convert from</param> | ||
/// <param name="destinationType">Type to convert to</param> | ||
/// <returns>converted value</returns> | ||
/// <ExternalAPI/> | ||
public override object ConvertTo( | ||
ITypeDescriptorContext context, | ||
CultureInfo cultureInfo, | ||
object value, | ||
Type destinationType) | ||
/// <returns> | ||
/// The formatted <paramref name="value"/> as <see cref="string"/> using the specified <paramref name="cultureInfo"/> or an <see cref="InstanceDescriptor"/>. | ||
/// </returns> | ||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo cultureInfo, object value, Type destinationType) | ||
{ | ||
KeySpline keySpline = value as KeySpline; | ||
|
||
if (keySpline != null && destinationType != null) | ||
if (value is KeySpline keySpline && destinationType is not null) | ||
{ | ||
if (destinationType == typeof(InstanceDescriptor)) | ||
{ | ||
ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[] | ||
{ | ||
typeof(double), typeof(double), | ||
typeof(double), typeof(double) | ||
}); | ||
if (destinationType == typeof(string)) | ||
return ToString(keySpline, cultureInfo); | ||
|
||
return new InstanceDescriptor(ci, new object[] | ||
{ | ||
keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y, | ||
keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y | ||
}); | ||
} | ||
else if (destinationType == typeof(string)) | ||
if (destinationType == typeof(InstanceDescriptor)) | ||
{ | ||
return String.Format( | ||
cultureInfo, | ||
"{0}{4}{1}{4}{2}{4}{3}", | ||
keySpline.ControlPoint1.X, | ||
keySpline.ControlPoint1.Y, | ||
keySpline.ControlPoint2.X, | ||
keySpline.ControlPoint2.Y, | ||
cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator); | ||
ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) }); | ||
return new InstanceDescriptor(ci, new object[] { keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y, keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y }); | ||
} | ||
} | ||
|
||
// Pass unhandled cases to base class (which will throw exceptions for null value or destinationType.) | ||
// Pass unhandled cases to base class (which will throw exceptions for null value or destinationType) | ||
return base.ConvertTo(context, cultureInfo, value, destinationType); | ||
} | ||
|
||
/// <summary> | ||
/// Converts <paramref name="keySpline"/> to its <see cref="string"/> representation using the specified <paramref name="cultureInfo"/>. | ||
/// </summary> | ||
/// <param name="keySpline">The <see cref="KeySpline"/> to convert to string.</param> | ||
/// <param name="cultureInfo">Culture to use when formatting doubles and choosing separator.</param> | ||
/// <returns>The formatted <paramref name="keySpline"/> as <see cref="string"/> using the specified <paramref name="cultureInfo"/>.</returns> | ||
private static string ToString(KeySpline keySpline, CultureInfo cultureInfo) | ||
{ | ||
string listSeparator = cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator; | ||
|
||
// Initial capacity [64] is an estimate based on a sum of: | ||
// 60 = 4x double (fifteen digits is generous for the range of values) | ||
// 3 = 3x separator characters | ||
// 1 = 1x scratch space for alignment | ||
DefaultInterpolatedStringHandler handler = new(3, 4, cultureInfo, stackalloc char[64]); | ||
handler.AppendFormatted(keySpline.ControlPoint1.X); | ||
handler.AppendLiteral(listSeparator); | ||
|
||
handler.AppendFormatted(keySpline.ControlPoint1.Y); | ||
handler.AppendLiteral(listSeparator); | ||
|
||
handler.AppendFormatted(keySpline.ControlPoint2.X); | ||
handler.AppendLiteral(listSeparator); | ||
|
||
handler.AppendFormatted(keySpline.ControlPoint2.Y); | ||
|
||
return handler.ToStringAndClear(); | ||
h3xds1nz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.