Skip to content

Commit beced18

Browse files
committed
Use ValueTokenizerHelper in KeySplineConverter, make it allocation free
1 parent 9e2a7c5 commit beced18

File tree

1 file changed

+52
-77
lines changed

1 file changed

+52
-77
lines changed

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs

Lines changed: 52 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,20 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
//
6-
7-
// Allow suppression of certain presharp messages
8-
#pragma warning disable 1634, 1691
9-
10-
using MS.Internal;
11-
using System;
12-
using System.ComponentModel;
135
using System.ComponentModel.Design.Serialization;
6+
using System.Windows.Media.Animation;
7+
using System.ComponentModel;
148
using System.Globalization;
159
using System.Reflection;
16-
using System.Windows.Media.Animation;
17-
using System.Security;
10+
using MS.Internal;
1811

19-
using SR=MS.Internal.PresentationCore.SR;
12+
using SR = MS.Internal.PresentationCore.SR;
13+
using System.Runtime.CompilerServices;
2014

2115
namespace System.Windows
2216
{
2317
/// <summary>
24-
/// PointConverter - Converter class for converting instances of other types to Point instances
18+
/// Converter class for converting instances of <see cref="KeySpline"/> to <see cref="string"/> and vice versa.
2519
/// </summary>
2620
/// <ExternalAPI/>
2721
public class KeySplineConverter : TypeConverter
@@ -32,14 +26,7 @@ public class KeySplineConverter : TypeConverter
3226
/// <ExternalAPI/>
3327
public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptor, Type destinationType)
3428
{
35-
if (destinationType == typeof(string))
36-
{
37-
return true;
38-
}
39-
else
40-
{
41-
return false;
42-
}
29+
return destinationType == typeof(string);
4330
}
4431

4532
/// <summary>
@@ -51,39 +38,23 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptor, Type
5138
/// <ExternalAPI/>
5239
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
5340
{
54-
if ( destinationType == typeof(InstanceDescriptor)
55-
|| destinationType == typeof(string))
56-
{
57-
return true;
58-
}
59-
else
60-
{
61-
return false;
62-
}
41+
return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string);
6342
}
6443

6544
/// <summary>
6645
/// ConvertFrom
6746
/// </summary>
68-
public override object ConvertFrom(
69-
ITypeDescriptorContext context,
70-
CultureInfo cultureInfo,
71-
object value)
47+
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo cultureInfo, object value)
7248
{
73-
string stringValue = value as string;
74-
75-
if (value == null)
76-
{
49+
if (value is not string stringValue)
7750
throw new NotSupportedException(SR.Converter_ConvertFromNotSupported);
78-
}
7951

80-
TokenizerHelper th = new TokenizerHelper(stringValue, cultureInfo);
52+
ValueTokenizerHelper tokenizer = new(stringValue, cultureInfo);
8153

82-
return new KeySpline(
83-
Convert.ToDouble(th.NextTokenRequired(), cultureInfo),
84-
Convert.ToDouble(th.NextTokenRequired(), cultureInfo),
85-
Convert.ToDouble(th.NextTokenRequired(), cultureInfo),
86-
Convert.ToDouble(th.NextTokenRequired(), cultureInfo));
54+
return new KeySpline(double.Parse(tokenizer.NextTokenRequired(), cultureInfo),
55+
double.Parse(tokenizer.NextTokenRequired(), cultureInfo),
56+
double.Parse(tokenizer.NextTokenRequired(), cultureInfo),
57+
double.Parse(tokenizer.NextTokenRequired(), cultureInfo));
8758
}
8859

8960
/// <summary>
@@ -95,47 +66,51 @@ public override object ConvertFrom(
9566
/// <param name="destinationType">Type to convert to</param>
9667
/// <returns>converted value</returns>
9768
/// <ExternalAPI/>
98-
public override object ConvertTo(
99-
ITypeDescriptorContext context,
100-
CultureInfo cultureInfo,
101-
object value,
102-
Type destinationType)
69+
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo cultureInfo, object value, Type destinationType)
10370
{
104-
KeySpline keySpline = value as KeySpline;
105-
106-
if (keySpline != null && destinationType != null)
71+
if (value is KeySpline keySpline && destinationType is not null)
10772
{
73+
if (destinationType == typeof(string))
74+
return ToString(keySpline, cultureInfo);
75+
10876
if (destinationType == typeof(InstanceDescriptor))
10977
{
110-
ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[]
111-
{
112-
typeof(double), typeof(double),
113-
typeof(double), typeof(double)
114-
});
115-
116-
return new InstanceDescriptor(ci, new object[]
117-
{
118-
keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y,
119-
keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y
120-
});
121-
}
122-
else if (destinationType == typeof(string))
123-
{
124-
#pragma warning disable 56506 // Suppress presharp warning: Parameter 'cultureInfo.TextInfo' to this public method must be validated: A null-dereference can occur here.
125-
return String.Format(
126-
cultureInfo,
127-
"{0}{4}{1}{4}{2}{4}{3}",
128-
keySpline.ControlPoint1.X,
129-
keySpline.ControlPoint1.Y,
130-
keySpline.ControlPoint2.X,
131-
keySpline.ControlPoint2.Y,
132-
cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator);
133-
#pragma warning restore 56506
78+
ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) });
79+
return new InstanceDescriptor(ci, new object[] { keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y, keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y });
13480
}
13581
}
13682

137-
// Pass unhandled cases to base class (which will throw exceptions for null value or destinationType.)
83+
// Pass unhandled cases to base class (which will throw exceptions for null value or destinationType)
13884
return base.ConvertTo(context, cultureInfo, value, destinationType);
13985
}
86+
87+
/// <summary>
88+
/// Converts <paramref name="keySpline"/> to its string representation using the specified <paramref name="cultureInfo"/>.
89+
/// </summary>
90+
/// <param name="keySpline">The <see cref="KeySpline"/> to convert to string.</param>
91+
/// <param name="cultureInfo">Culture to use when formatting doubles and choosing separator.</param>
92+
/// <returns>The formatted <paramref name="keySpline"/> as string using the specified <paramref name="cultureInfo"/>.</returns>
93+
private static string ToString(KeySpline keySpline, CultureInfo cultureInfo)
94+
{
95+
string listSeparator = cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator;
96+
97+
// Initial capacity [64] is an estimate based on a sum of:
98+
// 48 = 4x double (fourteen digits is generous for the range of values likely)
99+
// 3 = 3x separator characters
100+
// 1 = 1x scratch space for alignment
101+
DefaultInterpolatedStringHandler handler = new(3, 4, cultureInfo, stackalloc char[64]);
102+
handler.AppendFormatted(keySpline.ControlPoint1.X);
103+
handler.AppendLiteral(listSeparator);
104+
105+
handler.AppendFormatted(keySpline.ControlPoint1.Y);
106+
handler.AppendLiteral(listSeparator);
107+
108+
handler.AppendFormatted(keySpline.ControlPoint2.X);
109+
handler.AppendLiteral(listSeparator);
110+
111+
handler.AppendFormatted(keySpline.ControlPoint2.Y);
112+
113+
return handler.ToStringAndClear();
114+
}
140115
}
141116
}

0 commit comments

Comments
 (0)