Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 0efe34e

Browse files
authored
Switch new TryParse* and TryFormat methods to use span-based format (#15238)
As part of this, I needed to fix-up several functions that parsed strings assuming they end with '\0', which no longer holds once we switch to using spans. Also: - Switched various call sites to using a cast rather than AsReadOnlySpan. - Updated string.Format / StringBuilder.AppendFormat to use the new span-based support to avoid substring allocations. - Removed some TODOs that were left in the codebase from some of my previous changes
1 parent c755e3b commit 0efe34e

25 files changed

+487
-365
lines changed

src/mscorlib/Resources/Strings.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,10 +2369,10 @@
23692369
<value>Index (zero based) must be greater than or equal to zero and less than the size of the argument list.</value>
23702370
</data>
23712371
<data name="Format_InvalidEnumFormatSpecification" xml:space="preserve">
2372-
<value>Format String can be only "G", "g", "X", "x", "F", "f", "D" or "d".</value>
2372+
<value>Format string can be only "G", "g", "X", "x", "F", "f", "D" or "d".</value>
23732373
</data>
23742374
<data name="Format_InvalidGuidFormatSpecification" xml:space="preserve">
2375-
<value>Format String can be only "D", "d", "N", "n", "P", "p", "B", "b", "X" or "x".</value>
2375+
<value>Format string can be only "D", "d", "N", "n", "P", "p", "B", "b", "X" or "x".</value>
23762376
</data>
23772377
<data name="Format_InvalidString" xml:space="preserve">
23782378
<value>Input string was not in a correct format.</value>

src/mscorlib/shared/System/Byte.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,20 @@ public override int GetHashCode()
7373
public static byte Parse(String s)
7474
{
7575
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
76-
return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
76+
return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
7777
}
7878

7979
public static byte Parse(String s, NumberStyles style)
8080
{
8181
NumberFormatInfo.ValidateParseStyleInteger(style);
8282
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
83-
return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
83+
return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
8484
}
8585

8686
public static byte Parse(String s, IFormatProvider provider)
8787
{
8888
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
89-
return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
89+
return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
9090
}
9191

9292
// Parses an unsigned byte from a String in the given style. If
@@ -96,7 +96,7 @@ public static byte Parse(String s, NumberStyles style, IFormatProvider provider)
9696
{
9797
NumberFormatInfo.ValidateParseStyleInteger(style);
9898
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
99-
return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
99+
return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
100100
}
101101

102102
public static byte Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -129,18 +129,14 @@ public static bool TryParse(String s, out Byte result)
129129
return false;
130130
}
131131

132-
return TryParse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
132+
return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
133133
}
134134

135135
public static bool TryParse(ReadOnlySpan<char> s, out byte result)
136136
{
137137
return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
138138
}
139139

140-
// TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
141-
public static bool TryParse(ReadOnlySpan<char> s, out byte result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
142-
TryParse(s, style, provider, out result);
143-
144140
public static bool TryParse(String s, NumberStyles style, IFormatProvider provider, out Byte result)
145141
{
146142
NumberFormatInfo.ValidateParseStyleInteger(style);
@@ -151,7 +147,7 @@ public static bool TryParse(String s, NumberStyles style, IFormatProvider provid
151147
return false;
152148
}
153149

154-
return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
150+
return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
155151
}
156152

157153
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out byte result)
@@ -196,7 +192,11 @@ public String ToString(String format, IFormatProvider provider)
196192
return Number.FormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
197193
}
198194

199-
public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
195+
// TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
196+
public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
197+
TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
198+
199+
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
200200
{
201201
return Number.TryFormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
202202
}

src/mscorlib/shared/System/DateTime.cs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ public static bool IsLeapYear(int year)
10921092
public static DateTime Parse(String s)
10931093
{
10941094
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1095-
return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
1095+
return (DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
10961096
}
10971097

10981098
// Constructs a DateTime from a string. The string must specify a
@@ -1102,14 +1102,14 @@ public static DateTime Parse(String s)
11021102
public static DateTime Parse(String s, IFormatProvider provider)
11031103
{
11041104
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1105-
return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
1105+
return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
11061106
}
11071107

11081108
public static DateTime Parse(String s, IFormatProvider provider, DateTimeStyles styles)
11091109
{
11101110
DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
11111111
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1112-
return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles));
1112+
return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles));
11131113
}
11141114

11151115
public static DateTime Parse(ReadOnlySpan<char> s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None)
@@ -1125,7 +1125,8 @@ public static DateTime Parse(ReadOnlySpan<char> s, IFormatProvider provider = nu
11251125
public static DateTime ParseExact(String s, String format, IFormatProvider provider)
11261126
{
11271127
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1128-
return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
1128+
if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1129+
return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
11291130
}
11301131

11311132
// Constructs a DateTime from a string. The string must specify a
@@ -1136,10 +1137,18 @@ public static DateTime ParseExact(String s, String format, IFormatProvider provi
11361137
{
11371138
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
11381139
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1139-
return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style));
1140+
if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1141+
return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style));
11401142
}
11411143

1142-
public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
1144+
// TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
1145+
public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style)
1146+
{
1147+
if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1148+
return ParseExact(s, (ReadOnlySpan<char>)format, provider, style);
1149+
}
1150+
1151+
public static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
11431152
{
11441153
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
11451154
return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style);
@@ -1149,7 +1158,7 @@ public static DateTime ParseExact(String s, String[] formats, IFormatProvider pr
11491158
{
11501159
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
11511160
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1152-
return DateTimeParse.ParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style);
1161+
return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style);
11531162
}
11541163

11551164
public static DateTime ParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
@@ -1291,7 +1300,11 @@ public String ToString(String format, IFormatProvider provider)
12911300
return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
12921301
}
12931302

1294-
public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null) =>
1303+
// TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
1304+
public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
1305+
TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
1306+
1307+
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null) =>
12951308
DateTimeFormat.TryFormat(this, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(provider));
12961309

12971310
public DateTime ToUniversalTime()
@@ -1303,10 +1316,10 @@ public static Boolean TryParse(String s, out DateTime result)
13031316
{
13041317
if (s == null)
13051318
{
1306-
result = default(DateTime);
1319+
result = default;
13071320
return false;
13081321
}
1309-
return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
1322+
return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
13101323
}
13111324

13121325
public static bool TryParse(ReadOnlySpan<char> s, out DateTime result)
@@ -1320,11 +1333,11 @@ public static Boolean TryParse(String s, IFormatProvider provider, DateTimeStyle
13201333

13211334
if (s == null)
13221335
{
1323-
result = default(DateTime);
1336+
result = default;
13241337
return false;
13251338
}
13261339

1327-
return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles, out result);
1340+
return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
13281341
}
13291342

13301343
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
@@ -1337,16 +1350,28 @@ public static Boolean TryParseExact(String s, String format, IFormatProvider pro
13371350
{
13381351
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
13391352

1340-
if (s == null)
1353+
if (s == null || format == null)
13411354
{
1342-
result = default(DateTime);
1355+
result = default;
13431356
return false;
13441357
}
13451358

1346-
return DateTimeParse.TryParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style, out result);
1359+
return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
13471360
}
13481361

1362+
// TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
13491363
public static bool TryParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1364+
{
1365+
if (format == null)
1366+
{
1367+
result = default;
1368+
return false;
1369+
}
1370+
1371+
return TryParseExact(s, (ReadOnlySpan<char>)format, provider, style, out result);
1372+
}
1373+
1374+
public static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
13501375
{
13511376
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
13521377
return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
@@ -1358,11 +1383,11 @@ public static Boolean TryParseExact(String s, String[] formats, IFormatProvider
13581383

13591384
if (s == null)
13601385
{
1361-
result = default(DateTime);
1386+
result = default;
13621387
return false;
13631388
}
13641389

1365-
return DateTimeParse.TryParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
1390+
return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
13661391
}
13671392

13681393
public static bool TryParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)

0 commit comments

Comments
 (0)