Switch new TryParse* and TryFormat methods to use span-based format (#15238)
authorStephen Toub <stoub@microsoft.com>
Tue, 28 Nov 2017 03:05:47 +0000 (22:05 -0500)
committerGitHub <noreply@github.com>
Tue, 28 Nov 2017 03:05:47 +0000 (22:05 -0500)
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

25 files changed:
src/mscorlib/Resources/Strings.resx
src/mscorlib/shared/System/Byte.cs
src/mscorlib/shared/System/DateTime.cs
src/mscorlib/shared/System/DateTimeOffset.cs
src/mscorlib/shared/System/Double.cs
src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
src/mscorlib/shared/System/Globalization/DateTimeParse.cs
src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs
src/mscorlib/shared/System/Globalization/TimeSpanParse.cs
src/mscorlib/shared/System/Guid.cs
src/mscorlib/shared/System/ISpanFormattable.cs
src/mscorlib/shared/System/Int16.cs
src/mscorlib/shared/System/Int32.cs
src/mscorlib/shared/System/Int64.cs
src/mscorlib/shared/System/Number.Formatting.cs
src/mscorlib/shared/System/SByte.cs
src/mscorlib/shared/System/Single.cs
src/mscorlib/shared/System/Text/StringBuilder.cs
src/mscorlib/shared/System/TimeSpan.cs
src/mscorlib/shared/System/UInt16.cs
src/mscorlib/shared/System/UInt32.cs
src/mscorlib/shared/System/UInt64.cs
src/mscorlib/shared/System/Version.cs
src/mscorlib/src/System/Decimal.cs
src/mscorlib/src/System/ThrowHelper.cs

index e40b410..79f9339 100644 (file)
     <value>Index (zero based) must be greater than or equal to zero and less than the size of the argument list.</value>
   </data>
   <data name="Format_InvalidEnumFormatSpecification" xml:space="preserve">
-    <value>Format String can be only "G", "g", "X", "x", "F", "f", "D" or "d".</value>
+    <value>Format string can be only "G", "g", "X", "x", "F", "f", "D" or "d".</value>
   </data>
   <data name="Format_InvalidGuidFormatSpecification" xml:space="preserve">
-    <value>Format String can be only "D", "d", "N", "n", "P", "p", "B", "b", "X" or "x".</value>
+    <value>Format string can be only "D", "d", "N", "n", "P", "p", "B", "b", "X" or "x".</value>
   </data>
   <data name="Format_InvalidString" xml:space="preserve">
     <value>Input string was not in a correct format.</value>
index 91c0b0f..a453a6f 100644 (file)
@@ -73,20 +73,20 @@ namespace System
         public static byte Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         public static byte Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static byte Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         // Parses an unsigned byte from a String in the given style.  If
@@ -96,7 +96,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static byte Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -129,7 +129,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out byte result)
@@ -137,10 +137,6 @@ namespace System
             return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out byte result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(String s, NumberStyles style, IFormatProvider provider, out Byte result)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
@@ -151,7 +147,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out byte result)
@@ -196,7 +192,11 @@ namespace System
             return Number.FormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
index 219aefd..b5deefa 100644 (file)
@@ -1092,7 +1092,7 @@ namespace System
         public static DateTime Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
+            return (DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
         }
 
         // Constructs a DateTime from a string. The string must specify a
@@ -1102,14 +1102,14 @@ namespace System
         public static DateTime Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
+            return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
         }
 
         public static DateTime Parse(String s, IFormatProvider provider, DateTimeStyles styles)
         {
             DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles));
+            return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles));
         }
 
         public static DateTime Parse(ReadOnlySpan<char> s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None)
@@ -1125,7 +1125,8 @@ namespace System
         public static DateTime ParseExact(String s, String format, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
         }
 
         // Constructs a DateTime from a string. The string must specify a
@@ -1136,10 +1137,18 @@ namespace System
         {
             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style));
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style));
         }
 
-        public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style)
+        {
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return ParseExact(s, (ReadOnlySpan<char>)format, provider, style);
+        }
+
+        public static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
         {
             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
             return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style);
@@ -1149,7 +1158,7 @@ namespace System
         {
             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return DateTimeParse.ParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style);
+            return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style);
         }
 
         public static DateTime ParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
@@ -1291,7 +1300,11 @@ namespace System
             return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null) =>
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null) =>
             DateTimeFormat.TryFormat(this, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(provider));
 
         public DateTime ToUniversalTime()
@@ -1303,10 +1316,10 @@ namespace System
         {
             if (s == null)
             {
-                result = default(DateTime);
+                result = default;
                 return false;
             }
-            return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
+            return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out DateTime result)
@@ -1320,11 +1333,11 @@ namespace System
 
             if (s == null)
             {
-                result = default(DateTime);
+                result = default;
                 return false;
             }
 
-            return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles, out result);
+            return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
@@ -1337,17 +1350,29 @@ namespace System
         {
             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
 
-            if (s == null)
+            if (s == null || format == null)
             {
-                result = default(DateTime);
+                result = default;
                 return false;
             }
 
-            return DateTimeParse.TryParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style, out result);
+            return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
         }
 
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
         public static bool TryParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
         {
+            if (format == null)
+            {
+                result = default;
+                return false;
+            }
+
+            return TryParseExact(s, (ReadOnlySpan<char>)format, provider, style, out result);
+        }
+
+        public static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
+        {
             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
             return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
         }
@@ -1358,11 +1383,11 @@ namespace System
 
             if (s == null)
             {
-                result = default(DateTime);
+                result = default;
                 return false;
             }
 
-            return DateTimeParse.TryParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
+            return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
         }
 
         public static bool TryParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)
index f36ed20..bb21963 100644 (file)
@@ -599,10 +599,10 @@ namespace System
         // 
         public static DateTimeOffset Parse(String input)
         {
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
 
             TimeSpan offset;
-            DateTime dateResult = DateTimeParse.Parse(input.AsReadOnlySpan(),
+            DateTime dateResult = DateTimeParse.Parse(input,
                                                       DateTimeFormatInfo.CurrentInfo,
                                                       DateTimeStyles.None,
                                                       out offset);
@@ -615,17 +615,17 @@ namespace System
         // 
         public static DateTimeOffset Parse(String input, IFormatProvider formatProvider)
         {
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
             return Parse(input, formatProvider, DateTimeStyles.None);
         }
 
         public static DateTimeOffset Parse(String input, IFormatProvider formatProvider, DateTimeStyles styles)
         {
             styles = ValidateStyles(styles, nameof(styles));
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
 
             TimeSpan offset;
-            DateTime dateResult = DateTimeParse.Parse(input.AsReadOnlySpan(),
+            DateTime dateResult = DateTimeParse.Parse(input,
                                                       DateTimeFormatInfo.GetInstance(formatProvider),
                                                       styles,
                                                       out offset);
@@ -645,7 +645,8 @@ namespace System
         // 
         public static DateTimeOffset ParseExact(String input, String format, IFormatProvider formatProvider)
         {
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
             return ParseExact(input, format, formatProvider, DateTimeStyles.None);
         }
 
@@ -656,10 +657,11 @@ namespace System
         public static DateTimeOffset ParseExact(String input, String format, IFormatProvider formatProvider, DateTimeStyles styles)
         {
             styles = ValidateStyles(styles, nameof(styles));
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
 
             TimeSpan offset;
-            DateTime dateResult = DateTimeParse.ParseExact(input.AsReadOnlySpan(),
+            DateTime dateResult = DateTimeParse.ParseExact(input,
                                                            format,
                                                            DateTimeFormatInfo.GetInstance(formatProvider),
                                                            styles,
@@ -667,7 +669,14 @@ namespace System
             return new DateTimeOffset(dateResult.Ticks, offset);
         }
 
-        public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None)
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles)
+        {
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return ParseExact(input, (ReadOnlySpan<char>)format, formatProvider, styles);
+        }
+
+        public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None)
         {
             styles = ValidateStyles(styles, nameof(styles));
             DateTime dateResult = DateTimeParse.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset);
@@ -677,10 +686,10 @@ namespace System
         public static DateTimeOffset ParseExact(String input, String[] formats, IFormatProvider formatProvider, DateTimeStyles styles)
         {
             styles = ValidateStyles(styles, nameof(styles));
-            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+            if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
 
             TimeSpan offset;
-            DateTime dateResult = DateTimeParse.ParseExactMultiple(input.AsReadOnlySpan(),
+            DateTime dateResult = DateTimeParse.ParseExactMultiple(input,
                                                                    formats,
                                                                    DateTimeFormatInfo.GetInstance(formatProvider),
                                                                    styles,
@@ -771,7 +780,11 @@ namespace System
             return DateTimeFormat.Format(ClockDateTime, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider formatProvider = null) =>
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider formatProvider = null) =>
             DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
 
         public DateTimeOffset ToUniversalTime()
@@ -783,7 +796,7 @@ namespace System
         {
             TimeSpan offset;
             DateTime dateResult;
-            Boolean parsed = DateTimeParse.TryParse(input.AsReadOnlySpan(),
+            Boolean parsed = DateTimeParse.TryParse(input,
                                                     DateTimeFormatInfo.CurrentInfo,
                                                     DateTimeStyles.None,
                                                     out dateResult,
@@ -810,7 +823,7 @@ namespace System
 
             TimeSpan offset;
             DateTime dateResult;
-            Boolean parsed = DateTimeParse.TryParse(input.AsReadOnlySpan(),
+            Boolean parsed = DateTimeParse.TryParse(input,
                                                     DateTimeFormatInfo.GetInstance(formatProvider),
                                                     styles,
                                                     out dateResult,
@@ -831,7 +844,7 @@ namespace System
                                             out DateTimeOffset result)
         {
             styles = ValidateStyles(styles, nameof(styles));
-            if (input == null)
+            if (input == null || format == null)
             {
                 result = default(DateTimeOffset);
                 return false;
@@ -839,7 +852,7 @@ namespace System
 
             TimeSpan offset;
             DateTime dateResult;
-            Boolean parsed = DateTimeParse.TryParseExact(input.AsReadOnlySpan(),
+            Boolean parsed = DateTimeParse.TryParseExact(input,
                                                          format,
                                                          DateTimeFormatInfo.GetInstance(formatProvider),
                                                          styles,
@@ -849,8 +862,20 @@ namespace System
             return parsed;
         }
 
+        // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
+        public static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
+        {
+            if (format == null)
+            {
+                result = default;
+                return false;
+            }
+
+            return TryParseExact(input, (ReadOnlySpan<char>)format, formatProvider, styles, out result);
+        }
+
         public static bool TryParseExact(
-            ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
+            ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
         {
             styles = ValidateStyles(styles, nameof(styles));
             bool parsed = DateTimeParse.TryParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset);
@@ -870,7 +895,7 @@ namespace System
 
             TimeSpan offset;
             DateTime dateResult;
-            Boolean parsed = DateTimeParse.TryParseExactMultiple(input.AsReadOnlySpan(),
+            Boolean parsed = DateTimeParse.TryParseExactMultiple(input,
                                                                  formats,
                                                                  DateTimeFormatInfo.GetInstance(formatProvider),
                                                                  styles,
index 610aa61..78c161c 100644 (file)
@@ -256,27 +256,27 @@ namespace System
         public static double Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDouble(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
+            return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
         }
 
         public static double Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDouble(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseDouble(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static double Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDouble(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
         }
 
         public static double Parse(String s, NumberStyles style, IFormatProvider provider)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDouble(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         // Parses a double from a String in the given style.  If
@@ -303,7 +303,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out double result)
@@ -321,13 +321,9 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out double result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out double result)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
index ac5d8a0..d15cc1c 100644 (file)
@@ -210,7 +210,7 @@ namespace System
             outputBuffer.Append(HebrewNumber.ToString(digits));
         }
 
-        internal static int ParseRepeatPattern(String format, int pos, char patternChar)
+        internal static int ParseRepeatPattern(ReadOnlySpan<char> format, int pos, char patternChar)
         {
             int len = format.Length;
             int index = pos + 1;
@@ -298,7 +298,7 @@ namespace System
         // The pos should point to a quote character. This method will
         // append to the result StringBuilder the string encloed by the quote character.
         //
-        internal static int ParseQuoteString(String format, int pos, StringBuilder result)
+        internal static int ParseQuoteString(ReadOnlySpan<char> format, int pos, StringBuilder result)
         {
             //
             // NOTE : pos will be the index of the quote character in the 'format' string.
@@ -361,7 +361,7 @@ namespace System
         // Return value of -1 means 'pos' is already at the end of the 'format' string.
         // Otherwise, return value is the int value of the next character.
         //
-        internal static int ParseNextChar(String format, int pos)
+        internal static int ParseNextChar(ReadOnlySpan<char> format, int pos)
         {
             if (pos >= format.Length - 1)
             {
@@ -383,7 +383,7 @@ namespace System
         //      tokenLen    The len of the current pattern character.  This indicates how many "M" that we have.
         //      patternToMatch  The pattern that we want to search. This generally uses "d"
         //
-        private static bool IsUseGenitiveForm(String format, int index, int tokenLen, char patternToMatch)
+        private static bool IsUseGenitiveForm(ReadOnlySpan<char> format, int index, int tokenLen, char patternToMatch)
         {
             int i;
             int repeat = 0;
@@ -446,12 +446,19 @@ namespace System
         //
         //  Actions: Format the DateTime instance using the specified format.
         // 
-        private static StringBuilder FormatCustomized(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
+        private static StringBuilder FormatCustomized(
+            DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset, StringBuilder result)
         {
             Calendar cal = dtfi.Calendar;
-            StringBuilder result = StringBuilderCache.Acquire();
-            // This is a flag to indicate if we are format the dates using Hebrew calendar.
 
+            bool resultBuilderIsPooled = false;
+            if (result == null)
+            {
+                resultBuilderIsPooled = true;
+                result = StringBuilderCache.Acquire();
+            }
+            
+            // This is a flag to indicate if we are format the dates using Hebrew calendar.
             bool isHebrewCalendar = (cal.ID == CalendarId.HEBREW);
             // This is a flag to indicate if we are formating hour/minute/second only.
             bool bTimeOnly = true;
@@ -532,7 +539,10 @@ namespace System
                         }
                         else
                         {
-                            StringBuilderCache.Release(result);
+                            if (resultBuilderIsPooled)
+                            {
+                                StringBuilderCache.Release(result);
+                            }
                             throw new FormatException(SR.Format_InvalidString);
                         }
                         break;
@@ -690,9 +700,11 @@ namespace System
                         nextChar = ParseNextChar(format, i);
                         // nextChar will be -1 if we already reach the end of the format string.
                         // Besides, we will not allow "%%" appear in the pattern.
-                        if (nextChar >= 0 && nextChar != (int)'%')
+                        if (nextChar >= 0 && nextChar != '%')
                         {
-                            result.Append(FormatCustomized(dateTime, ((char)nextChar).ToString(), dtfi, offset));
+                            char nextCharChar = (char)nextChar;
+                            StringBuilder origStringBuilder = FormatCustomized(dateTime, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, offset, result);
+                            Debug.Assert(ReferenceEquals(origStringBuilder, result));
                             tokenLen = 2;
                         }
                         else
@@ -701,7 +713,10 @@ namespace System
                             // This means that '%' is at the end of the format string or
                             // "%%" appears in the format string.
                             //
-                            StringBuilderCache.Release(result);
+                            if (resultBuilderIsPooled)
+                            {
+                                StringBuilderCache.Release(result);
+                            }
                             throw new FormatException(SR.Format_InvalidString);
                         }
                         break;
@@ -725,7 +740,10 @@ namespace System
                             //
                             // This means that '\' is at the end of the formatting string.
                             //
-                            StringBuilderCache.Release(result);
+                            if (resultBuilderIsPooled)
+                            {
+                                StringBuilderCache.Release(result);
+                            }
                             throw new FormatException(SR.Format_InvalidString);
                         }
                         break;
@@ -745,7 +763,7 @@ namespace System
 
 
         // output the 'z' famliy of formats, which output a the offset from UTC, e.g. "-07:30"
-        private static void FormatCustomizedTimeZone(DateTime dateTime, TimeSpan offset, String format, Int32 tokenLen, Boolean timeOnly, StringBuilder result)
+        private static void FormatCustomizedTimeZone(DateTime dateTime, TimeSpan offset, ReadOnlySpan<char> format, Int32 tokenLen, Boolean timeOnly, StringBuilder result)
         {
             // See if the instance already has an offset
             Boolean dateTimeFormat = (offset == NullOffset);
@@ -838,8 +856,7 @@ namespace System
             AppendNumber(result, offset.Minutes, 2);
         }
 
-
-        internal static String GetRealFormat(String format, DateTimeFormatInfo dtfi)
+        internal static String GetRealFormat(ReadOnlySpan<char> format, DateTimeFormatInfo dtfi)
         {
             String realFormat = null;
 
@@ -906,7 +923,7 @@ namespace System
         // This method also convert the dateTime if necessary (e.g. when the format is in Universal time),
         // and change dtfi if necessary (e.g. when the format should use invariant culture).
         //
-        private static String ExpandPredefinedFormat(String format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset)
+        private static String ExpandPredefinedFormat(ReadOnlySpan<char> format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset)
         {
             switch (format[0])
             {
@@ -960,8 +977,7 @@ namespace System
                     dateTime = dateTime.ToUniversalTime();
                     break;
             }
-            format = GetRealFormat(format, dtfi);
-            return (format);
+            return GetRealFormat(format, dtfi);
         }
 
         internal static String Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi)
@@ -972,10 +988,10 @@ namespace System
         internal static string Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset) =>
             StringBuilderCache.GetStringAndRelease(FormatStringBuilder(dateTime, format, dtfi, offset));
 
-        internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, string format, DateTimeFormatInfo dtfi) =>
+        internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi) =>
             TryFormat(dateTime, destination, out charsWritten, format, dtfi, NullOffset);
 
-        internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, string format, DateTimeFormatInfo dtfi, TimeSpan offset)
+        internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset)
         {
             StringBuilder sb = FormatStringBuilder(dateTime, format, dtfi, offset);
 
@@ -994,10 +1010,10 @@ namespace System
             return success;
         }
 
-        internal static StringBuilder FormatStringBuilder(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
+        internal static StringBuilder FormatStringBuilder(DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset)
         {
             Debug.Assert(dtfi != null);
-            if (format == null || format.Length == 0)
+            if (format.Length == 0)
             {
                 Boolean timeOnlySpecialCase = false;
                 if (dateTime.Ticks < Calendar.TicksPerDay)
@@ -1032,26 +1048,12 @@ namespace System
                 if (offset == NullOffset)
                 {
                     // Default DateTime.ToString case.
-                    if (timeOnlySpecialCase)
-                    {
-                        format = "s";
-                    }
-                    else
-                    {
-                        format = "G";
-                    }
+                    format = timeOnlySpecialCase ? "s" : "G";
                 }
                 else
                 {
                     // Default DateTimeOffset.ToString case.
-                    if (timeOnlySpecialCase)
-                    {
-                        format = RoundtripDateTimeUnfixed;
-                    }
-                    else
-                    {
-                        format = dtfi.DateTimeOffsetPattern;
-                    }
+                    format = timeOnlySpecialCase ? RoundtripDateTimeUnfixed : dtfi.DateTimeOffsetPattern;
                 }
             }
 
@@ -1070,7 +1072,7 @@ namespace System
                 format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset);
             }
 
-            return FormatCustomized(dateTime, format, dtfi, offset);
+            return FormatCustomized(dateTime, format, dtfi, offset, result: null);
         }
 
         internal static StringBuilder FastFormatRfc1123(DateTime dateTime, TimeSpan offset, DateTimeFormatInfo dtfi)
@@ -1227,7 +1229,7 @@ namespace System
 
         // This is a placeholder for an MDA to detect when the user is using a
         // local DateTime with a format that will be interpreted as UTC.
-        internal static void InvalidFormatForLocal(String format, DateTime dateTime)
+        internal static void InvalidFormatForLocal(ReadOnlySpan<char> format, DateTime dateTime)
         {
         }
     }
index 756211f..c6f51d6 100644 (file)
@@ -17,7 +17,7 @@ namespace System
 
         internal static MatchNumberDelegate m_hebrewNumberParser = new MatchNumberDelegate(DateTimeParse.MatchHebrewDigits);
 
-        internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)
+        internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
             result.Init();
@@ -31,7 +31,7 @@ namespace System
             }
         }
 
-        internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
+        internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
             offset = TimeSpan.Zero;
@@ -48,7 +48,7 @@ namespace System
             }
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
         {
             result = DateTime.MinValue;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
@@ -61,7 +61,7 @@ namespace System
             return false;
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
         {
             result = DateTime.MinValue;
             offset = TimeSpan.Zero;
@@ -77,13 +77,8 @@ namespace System
             return false;
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
         {
-            if (format == null)
-            {
-                result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(format));
-                return false;
-            }
             if (s.Length == 0)
             {
                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
@@ -3776,7 +3771,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         // This method also set the dtfi according/parseInfo to some special pre-defined
         // formats.
         //
-        private static String ExpandPredefinedFormat(String format, ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result)
+        private static String ExpandPredefinedFormat(ReadOnlySpan<char> format, ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result)
         {
             //
             // Check the format to see if we need to override the dtfi to be InvariantInfo,
@@ -4431,7 +4426,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
         private static bool DoStrictParse(
             ReadOnlySpan<char> s,
-            String formatParam,
+            ReadOnlySpan<char> formatParam,
             DateTimeStyles styles,
             DateTimeFormatInfo dtfi,
             ref DateTimeResult result)
@@ -4443,9 +4438,6 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             parseInfo.fAllowInnerWhite = ((styles & DateTimeStyles.AllowInnerWhite) != 0);
             parseInfo.fAllowTrailingWhite = ((styles & DateTimeStyles.AllowTrailingWhite) != 0);
 
-            // We need the original values of the following two below.
-            String originalFormat = formatParam;
-
             if (formatParam.Length == 1)
             {
                 if (((result.flags & ParseFlags.CaptureOffset) != 0) && formatParam[0] == 'U')
@@ -4470,7 +4462,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // if we have parsed every item twice.
             result.Hour = result.Minute = result.Second = -1;
 
-            __DTString format = new __DTString(formatParam.AsReadOnlySpan(), dtfi, false);
+            __DTString format = new __DTString(formatParam, dtfi, false);
             __DTString str = new __DTString(s, dtfi, false);
 
             if (parseInfo.fAllowTrailingWhite)
@@ -4749,7 +4741,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return buffer.ToString();
         }
         // return a string in the form: "Sun"
-        private static string Hex(string str) => Hex(str.AsReadOnlySpan());
+        private static string Hex(string str) => Hex((ReadOnlySpan<char>)str);
         private static string Hex(ReadOnlySpan<char> str)
         {
             StringBuilder buffer = new StringBuilder();
index 6801ea8..bf12b24 100644 (file)
@@ -46,7 +46,7 @@ namespace System.Globalization
             StringBuilderCache.GetStringAndRelease(FormatToBuilder(value, format, formatProvider));
 
         /// <summary>Main method called from TimeSpan.TryFormat.</summary>
-        internal static bool TryFormat(TimeSpan value, Span<char> destination, out int charsWritten, string format, IFormatProvider formatProvider)
+        internal static bool TryFormat(TimeSpan value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider formatProvider)
         {
             StringBuilder sb = FormatToBuilder(value, format, formatProvider);
             if (sb.Length <= destination.Length)
@@ -64,9 +64,9 @@ namespace System.Globalization
             }
         }
 
-        private static StringBuilder FormatToBuilder(TimeSpan value, string format, IFormatProvider formatProvider)
+        private static StringBuilder FormatToBuilder(TimeSpan value, ReadOnlySpan<char> format, IFormatProvider formatProvider)
         {
-            if (format == null || format.Length == 0)
+            if (format.Length == 0)
             {
                 format = "c";
             }
@@ -101,11 +101,11 @@ namespace System.Globalization
             }
 
             // Custom formats
-            return FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider));
+            return FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider), result: null);
         }
 
         /// <summary>Format the TimeSpan instance using the specified format.</summary>
-        private static StringBuilder FormatStandard(TimeSpan value, bool isInvariant, string format, Pattern pattern)
+        private static StringBuilder FormatStandard(TimeSpan value, bool isInvariant, ReadOnlySpan<char> format, Pattern pattern)
         {
             StringBuilder sb = StringBuilderCache.Acquire(InternalGlobalizationHelper.StringBuilderDefaultCapacity);
             int day = (int)(value.Ticks / TimeSpan.TicksPerDay);
@@ -186,10 +186,17 @@ namespace System.Globalization
         }
 
         /// <summary>Format the TimeSpan instance using the specified format.</summary>
-        private static StringBuilder FormatCustomized(TimeSpan value, string format, DateTimeFormatInfo dtfi)
+        private static StringBuilder FormatCustomized(TimeSpan value, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, StringBuilder result)
         {
             Debug.Assert(dtfi != null);
 
+            bool resultBuilderIsPooled = false;
+            if (result == null)
+            {
+                result = StringBuilderCache.Acquire(InternalGlobalizationHelper.StringBuilderDefaultCapacity);
+                resultBuilderIsPooled = true;
+            }
+
             int day = (int)(value.Ticks / TimeSpan.TicksPerDay);
             long time = value.Ticks % TimeSpan.TicksPerDay;
 
@@ -206,7 +213,6 @@ namespace System.Globalization
             long tmp = 0;
             int i = 0;
             int tokenLen;
-            StringBuilder result = StringBuilderCache.Acquire(InternalGlobalizationHelper.StringBuilderDefaultCapacity);
 
             while (i < format.Length)
             {
@@ -218,7 +224,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > 2)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
                         DateTimeFormat.FormatDigits(result, hours, tokenLen);
                         break;
@@ -226,7 +232,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > 2)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
                         DateTimeFormat.FormatDigits(result, minutes, tokenLen);
                         break;
@@ -234,7 +240,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > 2)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
                         DateTimeFormat.FormatDigits(result, seconds, tokenLen);
                         break;
@@ -245,7 +251,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
 
                         tmp = fraction;
@@ -259,7 +265,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
 
                         tmp = fraction;
@@ -290,7 +296,7 @@ namespace System.Globalization
                         tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                         if (tokenLen > 8)
                         {
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
 
                         DateTimeFormat.FormatDigits(result, day, tokenLen, true);
@@ -308,7 +314,9 @@ namespace System.Globalization
                         // Besides, we will not allow "%%" appear in the pattern.
                         if (nextChar >= 0 && nextChar != (int)'%')
                         {
-                            result.Append(TimeSpanFormat.FormatCustomized(value, ((char)nextChar).ToString(), dtfi));
+                            char nextCharChar = (char)nextChar;
+                            StringBuilder origStringBuilder = FormatCustomized(value, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, result);
+                            Debug.Assert(ReferenceEquals(origStringBuilder, result));
                             tokenLen = 2;
                         }
                         else
@@ -317,7 +325,7 @@ namespace System.Globalization
                             // This means that '%' is at the end of the format string or
                             // "%%" appears in the format string.
                             //
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
                         break;
                     case '\\':
@@ -335,10 +343,15 @@ namespace System.Globalization
                             //
                             // This means that '\' is at the end of the formatting string.
                             //
-                            throw new FormatException(SR.Format_InvalidString);
+                            goto default; // to release the builder and throw
                         }
                         break;
                     default:
+                        // Invalid format string
+                        if (resultBuilderIsPooled)
+                        {
+                            StringBuilderCache.Release(result);
+                        }
                         throw new FormatException(SR.Format_InvalidString);
                 }
                 i += tokenLen;
@@ -388,7 +401,7 @@ namespace System.Globalization
             // the constants guaranteed to include DHMSF ordered greatest to least significant.
             // Once the data becomes more complex than this we will need to write a proper tokenizer for
             // parsing and formatting
-            internal void Init(string format, bool useInvariantFieldLengths)
+            internal void Init(ReadOnlySpan<char> format, bool useInvariantFieldLengths)
             {
                 dd = hh = mm = ss = ff = 0;
                 _literals = new string[6];
index 8f511b7..ae77957 100644 (file)
@@ -49,7 +49,6 @@
 ////////////////////////////////////////////////////////////////////////////
 
 using System.Diagnostics;
-using System.Runtime.CompilerServices;
 using System.Text;
 
 namespace System.Globalization
@@ -589,7 +588,7 @@ namespace System.Globalization
             return false;
         }
 
-        internal static TimeSpan ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles)
+        internal static TimeSpan ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, TimeSpanStyles styles)
         {
             var parseResult = new TimeSpanResult(throwOnFailure: true);
             bool success = TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult);
@@ -597,7 +596,7 @@ namespace System.Globalization
             return parseResult.parsedTimeSpan;
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
+        internal static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
         {
             var parseResult = new TimeSpanResult(throwOnFailure: false);
 
@@ -1171,13 +1170,8 @@ namespace System.Globalization
         }
 
         /// <summary>Common private ParseExact method called by both ParseExact and TryParseExact.</summary>
-        private static bool TryParseExactTimeSpan(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles, ref TimeSpanResult result)
+        private static bool TryParseExactTimeSpan(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, TimeSpanStyles styles, ref TimeSpanResult result)
         {
-            if (format == null)
-            {
-                return result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), argumentName: nameof(format));
-            }
-
             if (format.Length == 0)
             {
                 return result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier));
@@ -1207,10 +1201,8 @@ namespace System.Globalization
         }
 
         /// <summary>Parse the TimeSpan instance using the specified format.  Used by TryParseExactTimeSpan.</summary>
-        private static bool TryParseByFormat(ReadOnlySpan<char> input, string format, TimeSpanStyles styles, ref TimeSpanResult result)
+        private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char> format, TimeSpanStyles styles, ref TimeSpanResult result)
         {
-            Debug.Assert(format != null, "format != null");
-
             bool seenDD = false;      // already processed days?
             bool seenHH = false;      // already processed hours?
             bool seenMM = false;      // already processed minutes?
@@ -1293,7 +1285,7 @@ namespace System.Globalization
                     case '\'':
                     case '\"':
                         StringBuilder enquotedString = StringBuilderCache.Acquire();
-                        if (!DateTimeParse.TryParseQuoteString(format.AsReadOnlySpan(), i, enquotedString, out tokenLen))
+                        if (!DateTimeParse.TryParseQuoteString(format, i, enquotedString, out tokenLen))
                         {
                             StringBuilderCache.Release(enquotedString);
                             return result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch);
index e784192..921f205 100644 (file)
@@ -246,7 +246,7 @@ namespace System
 
             GuidResult result = new GuidResult();
             result.Init(GuidParseThrowStyle.All);
-            if (TryParseGuid(g.AsReadOnlySpan(), GuidStyles.Any, ref result))
+            if (TryParseGuid(g, GuidStyles.Any, ref result))
             {
                 this = result._parsedGuid;
             }
@@ -257,7 +257,7 @@ namespace System
         }
 
         public static Guid Parse(string input) =>
-            Parse(input != null ? input.AsReadOnlySpan() : throw new ArgumentNullException(nameof(input)));
+            Parse(input != null ? (ReadOnlySpan<char>)input : throw new ArgumentNullException(nameof(input)));
 
         public static Guid Parse(ReadOnlySpan<char> input)
         {
@@ -281,7 +281,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(input.AsReadOnlySpan(), out result);
+            return TryParse((ReadOnlySpan<char>)input, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> input, out Guid result)
@@ -301,14 +301,18 @@ namespace System
         }
 
         public static Guid ParseExact(string input, string format) =>
-            ParseExact(input != null ? input.AsReadOnlySpan() : throw new ArgumentNullException(nameof(input)), format);
+            ParseExact(
+                input != null ? (ReadOnlySpan<char>)input : throw new ArgumentNullException(nameof(input)),
+                format != null ? (ReadOnlySpan<char>)format : throw new ArgumentNullException(nameof(format)));
 
-        public static Guid ParseExact(ReadOnlySpan<char> input, string format)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public static Guid ParseExact(ReadOnlySpan<char> input, string format) =>
+            ParseExact(
+                input,
+                format != null ? (ReadOnlySpan<char>)format : throw new ArgumentNullException(nameof(format)));
+
+        public static Guid ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format)
         {
-            if (format == null)
-            {
-                throw new ArgumentNullException(nameof(format));
-            }
             if (format.Length != 1)
             {
                 // all acceptable format strings are of length 1
@@ -362,12 +366,16 @@ namespace System
                 return false;
             }
 
-            return TryParseExact(input.AsReadOnlySpan(), format, out result);
+            return TryParseExact((ReadOnlySpan<char>)input, format, out result);
         }
 
-        public static bool TryParseExact(ReadOnlySpan<char> input, string format, out Guid result)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public static bool TryParseExact(ReadOnlySpan<char> input, string format, out Guid result) =>
+            TryParseExact(input, (ReadOnlySpan<char>)format, out result);
+
+        public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, out Guid result)
         {
-            if (format == null || format.Length != 1)
+            if (format.Length != 1)
             {
                 result = default(Guid);
                 return false;
@@ -1306,10 +1314,14 @@ namespace System
             return guidString;
         }
 
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format);
+
         // Returns whether the guid is successfully formatted as a span. 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null)
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default)
         {
-            if (format == null || format.Length == 0)
+            if (format.Length == 0)
                 format = "D";
 
             // all acceptable format strings are of length 1
@@ -1427,7 +1439,7 @@ namespace System
             return true;
         }
 
-        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider)
+        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
         {
             // Like with the IFormattable implementation, provider is ignored.
             return TryFormat(destination, out charsWritten, format);
index 6fc3886..df46b5b 100644 (file)
@@ -6,6 +6,6 @@ namespace System
 {
     internal interface ISpanFormattable
     {
-        bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null);
+        bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider);
     }
 }
index 6fec038..2fadb1f 100644 (file)
@@ -87,11 +87,15 @@ namespace System
             return ToString(format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-            if (m_value < 0 && format != null && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            if (m_value < 0 && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
             {
                 uint temp = (uint)(m_value & 0x0000FFFF);
                 return Number.TryFormatUInt32(temp, format, info, destination, out charsWritten);
@@ -112,27 +116,27 @@ namespace System
         public static short Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         public static short Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static short Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         public static short Parse(String s, NumberStyles style, IFormatProvider provider)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static short Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -176,7 +180,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out short result)
@@ -194,13 +198,9 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out Int16 result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out short result)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
index 466eaf3..7a44a4a 100644 (file)
@@ -96,7 +96,11 @@ namespace System
             return Number.FormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -104,14 +108,14 @@ namespace System
         public static int Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         public static int Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseInt32(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         // Parses an integer from a String in the given style.  If
@@ -121,7 +125,7 @@ namespace System
         public static int Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         // Parses an integer from a String in the given style.  If
@@ -132,7 +136,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseInt32(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static int Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -152,7 +156,7 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return Number.TryParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out int result)
@@ -173,13 +177,9 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return Number.TryParseInt32(s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out int result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out int result)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
index 3cad473..c198f18 100644 (file)
@@ -93,7 +93,11 @@ namespace System
             return Number.FormatInt64(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatInt64(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -101,20 +105,20 @@ namespace System
         public static long Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         public static long Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseInt64(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static long Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
 
@@ -126,7 +130,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseInt64(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static long Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -143,7 +147,7 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return Number.TryParseInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out long result)
@@ -161,13 +165,9 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return Number.TryParseInt64(s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out long result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out long result)
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
index 919c06b..b860849 100644 (file)
@@ -50,7 +50,7 @@ namespace System
             "(#)", "-#", "- #", "#-", "# -",
         };
 
-        public static string FormatDecimal(decimal value, string format, NumberFormatInfo info)
+        public static string FormatDecimal(decimal value, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             char fmt = ParseFormatSpecifier(format, out int digits);
 
@@ -76,7 +76,7 @@ namespace System
             return sb.GetString();
         }
 
-        public static bool TryFormatDecimal(decimal value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+        public static bool TryFormatDecimal(decimal value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
         {
             char fmt = ParseFormatSpecifier(format, out int digits);
 
@@ -131,7 +131,7 @@ namespace System
             *dst = '\0';
         }
 
-        public static string FormatInt32(int value, string format, NumberFormatInfo info)
+        public static string FormatInt32(int value, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -171,7 +171,7 @@ namespace System
             }
         }
 
-        public static bool TryFormatInt32(int value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+        public static bool TryFormatInt32(int value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -211,7 +211,7 @@ namespace System
             }
         }
 
-        public static string FormatUInt32(uint value, string format, NumberFormatInfo info)
+        public static string FormatUInt32(uint value, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -249,7 +249,7 @@ namespace System
             }
         }
 
-        public static bool TryFormatUInt32(uint value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+        public static bool TryFormatUInt32(uint value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -287,7 +287,7 @@ namespace System
             }
         }
 
-        public static string FormatInt64(long value, string format, NumberFormatInfo info)
+        public static string FormatInt64(long value, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -328,7 +328,7 @@ namespace System
             }
         }
 
-        public static bool TryFormatInt64(long value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+        public static bool TryFormatInt64(long value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -369,7 +369,7 @@ namespace System
             }
         }
 
-        public static string FormatUInt64(ulong value, string format, NumberFormatInfo info)
+        public static string FormatUInt64(ulong value, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -408,7 +408,7 @@ namespace System
             }
         }
 
-        public static bool TryFormatUInt64(ulong value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+        public static bool TryFormatUInt64(ulong value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
         {
             int digits;
             char fmt = ParseFormatSpecifier(format, out digits);
@@ -849,45 +849,70 @@ namespace System
             return TryCopyTo(p, (int)(buffer + bufferSize - p), destination, out charsWritten);
         }
 
-        internal static unsafe char ParseFormatSpecifier(string format, out int digits)
+        internal static unsafe char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
         {
-            if (format != null)
-            {
-                fixed (char* pFormat = format)
+            char c = default;
+            if (format.Length > 0)
+            {
+                // If the format begins with a symbol, see if it's a standard format
+                // with or without a specified number of digits.
+                c = format[0];
+                if ((uint)(c - 'A') <= 'Z' - 'A' ||
+                    (uint)(c - 'a') <= 'z' - 'a')
                 {
-                    char ch = *pFormat;
-                    if (ch != 0)
+                    // Fast path for sole symbol, e.g. "D"
+                    if (format.Length == 1)
                     {
-                        if ((uint)(ch - 'A') <= 'Z' - 'A' ||
-                            (uint)(ch - 'a') <= 'z' - 'a')
+                        digits = -1;
+                        return c;
+                    }
+
+                    if (format.Length == 2)
+                    {
+                        // Fast path for symbol and single digit, e.g. "X4"
+                        int d = format[1] - '0';
+                        if ((uint)d < 10)
                         {
-                            int i = 1;
-                            int n = -1;
-                            if ((uint)(pFormat[i] - '0') <= '9' - '0')
-                            {
-                                n = pFormat[i++] - '0';
-                                while ((uint)(pFormat[i] - '0') <= '9' - '0')
-                                {
-                                    n = (n * 10) + pFormat[i++] - '0';
-                                    if (n >= 10)
-                                        break;
-                                }
-                            }
-                            if (pFormat[i] == 0)
-                            {
-                                digits = n;
-                                return ch;
-                            }
+                            digits = d;
+                            return c;
                         }
+                    }
+                    else if (format.Length == 3)
+                    {
+                        // Fast path for symbol and double digit, e.g. "F12"
+                        int d1 = format[1] - '0', d2 = format[2] - '0';
+                        if ((uint)d1 < 10 && (uint)d2 < 10)
+                        {
+                            digits = d1 * 10 + d2;
+                            return c;
+                        }
+                    }
 
-                        digits = -1;
-                        return '\0';
+                    // Fallback for symbol and any length digits.  The digits value must be >= 0 && <= 99,
+                    // but it can begin with any number of 0s, and thus we may need to check more than two
+                    // digits.  Further, for compat, we need to stop when we hit a null char.
+                    int n = 0;
+                    int i = 1;
+                    while (i < format.Length && (((uint)format[i] - '0') < 10) && n < 10)
+                    {
+                        n = (n * 10) + format[i++] - '0';
+                    }
+
+                    // If we're at the end of the digits rather than having stopped because we hit something
+                    // other than a digit or overflowed, return the standard format info.
+                    if (i == format.Length || format[i] == '\0')
+                    {
+                        digits = n;
+                        return c;
                     }
                 }
             }
 
+            // Default empty format to be "G"; custom format is signified with '\0'.
             digits = -1;
-            return 'G';
+            return format.Length == 0 || c == '\0' ? // For compat, treat '\0' as the end of the specifier, even if the specifer extends beyond it.
+                'G' : 
+                '\0';
         }
 
         internal static unsafe void NumberToString(ref ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info, bool isDecimal)
@@ -1024,7 +1049,7 @@ namespace System
             }
         }
 
-        internal static unsafe void NumberToStringFormat(ref ValueStringBuilder sb, ref NumberBuffer number, string format, NumberFormatInfo info)
+        internal static unsafe void NumberToStringFormat(ref ValueStringBuilder sb, ref NumberBuffer number, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
             int digitCount;
             int decimalPos;
@@ -1057,9 +1082,9 @@ namespace System
                 scaleAdjust = 0;
                 src = section;
 
-                fixed (char* pFormat = format)
+                fixed (char* pFormat = &format.DangerousGetPinnableReference())
                 {
-                    while ((ch = pFormat[src++]) != 0 && ch != ';')
+                    while (src < format.Length && (ch = pFormat[src++]) != 0 && ch != ';')
                     {
                         switch (ch)
                         {
@@ -1100,19 +1125,19 @@ namespace System
                                 break;
                             case '\'':
                             case '"':
-                                while (pFormat[src] != 0 && pFormat[src++] != ch)
+                                while (src < format.Length && pFormat[src] != 0 && pFormat[src++] != ch)
                                     ;
                                 break;
                             case '\\':
-                                if (pFormat[src] != 0)
+                                if (src < format.Length && pFormat[src] != 0)
                                     src++;
                                 break;
                             case 'E':
                             case 'e':
-                                if (pFormat[src] == '0' || ((pFormat[src] == '+' || pFormat[src] == '-') && pFormat[src + 1] == '0'))
+                                if ((src < format.Length && pFormat[src] == '0') ||
+                                    (src + 1 < format.Length && (pFormat[src] == '+' || pFormat[src] == '-') && pFormat[src + 1] == '0'))
                                 {
-                                    while (pFormat[++src] == '0')
-                                        ;
+                                    while (++src < format.Length && pFormat[src] == '0');
                                     scientific = true;
                                 }
                                 break;
@@ -1227,11 +1252,11 @@ namespace System
 
             bool decimalWritten = false;
 
-            fixed (char* pFormat = format)
+            fixed (char* pFormat = &format.DangerousGetPinnableReference())
             {
                 char* cur = dig;
 
-                while ((ch = pFormat[src++]) != 0 && ch != ';')
+                while (src < format.Length && (ch = pFormat[src++]) != 0 && ch != ';')
                 {
                     if (adjust > 0)
                     {
@@ -1315,13 +1340,13 @@ namespace System
                             break;
                         case '\'':
                         case '"':
-                            while (pFormat[src] != 0 && pFormat[src] != ch)
+                            while (src < format.Length && pFormat[src] != 0 && pFormat[src] != ch)
                                 sb.Append(pFormat[src++]);
-                            if (pFormat[src] != 0)
+                            if (src < format.Length && pFormat[src] != 0)
                                 src++;
                             break;
                         case '\\':
-                            if (pFormat[src] != 0)
+                            if (src < format.Length && pFormat[src] != 0)
                                 sb.Append(pFormat[src++]);
                             break;
                         case 'E':
@@ -1331,17 +1356,17 @@ namespace System
                                 int i = 0;
                                 if (scientific)
                                 {
-                                    if (pFormat[src] == '0')
+                                    if (src < format.Length && pFormat[src] == '0')
                                     {
                                         // Handles E0, which should format the same as E-0
                                         i++;
                                     }
-                                    else if (pFormat[src] == '+' && pFormat[src + 1] == '0')
+                                    else if (src+1 < format.Length && pFormat[src] == '+' && pFormat[src + 1] == '0')
                                     {
                                         // Handles E+0
                                         positiveSign = true;
                                     }
-                                    else if (pFormat[src] == '-' && pFormat[src + 1] == '0')
+                                    else if (src+1 < format.Length && pFormat[src] == '-' && pFormat[src + 1] == '0')
                                     {
                                         // Handles E-0
                                         // Do nothing, this is just a place holder s.t. we don't break out of the loop.
@@ -1352,7 +1377,7 @@ namespace System
                                         break;
                                     }
 
-                                    while (pFormat[++src] == '0')
+                                    while (++src < format.Length && pFormat[src] == '0')
                                         i++;
                                     if (i > 10)
                                         i = 10;
@@ -1364,10 +1389,13 @@ namespace System
                                 else
                                 {
                                     sb.Append(ch); // Copy E or e to output
-                                    if (pFormat[src] == '+' || pFormat[src] == '-')
-                                        sb.Append(pFormat[src++]);
-                                    while (pFormat[src] == '0')
-                                        sb.Append(pFormat[src++]);
+                                    if (src < format.Length)
+                                    {
+                                        if (pFormat[src] == '+' || pFormat[src] == '-')
+                                            sb.Append(pFormat[src++]);
+                                        while (src < format.Length && pFormat[src] == '0')
+                                            sb.Append(pFormat[src++]);
+                                    }
                                 }
                                 break;
                             }
@@ -1676,7 +1704,7 @@ namespace System
             dig[i] = '\0';
         }
 
-        private static unsafe int FindSection(string format, int section)
+        private static unsafe int FindSection(ReadOnlySpan<char> format, int section)
         {
             int src;
             char ch;
@@ -1684,26 +1712,31 @@ namespace System
             if (section == 0)
                 return 0;
 
-            fixed (char* pFormat = format)
+            fixed (char* pFormat = &format.DangerousGetPinnableReference())
             {
                 src = 0;
                 for (;;)
                 {
+                    if (src >= format.Length)
+                    {
+                        return 0;
+                    }
+
                     switch (ch = pFormat[src++])
                     {
                         case '\'':
                         case '"':
-                            while (pFormat[src] != 0 && pFormat[src++] != ch)
+                            while (src < format.Length && pFormat[src] != 0 && pFormat[src++] != ch)
                                 ;
                             break;
                         case '\\':
-                            if (pFormat[src] != 0)
+                            if (src < format.Length && pFormat[src] != 0)
                                 src++;
                             break;
                         case ';':
                             if (--section != 0)
                                 break;
-                            if (pFormat[src] != 0 && pFormat[src] != ';')
+                            if (src < format.Length && pFormat[src] != 0 && pFormat[src] != ';')
                                 return src;
                             goto case '\0';
                         case '\0':
index 3122174..dc4f6ad 100644 (file)
@@ -91,11 +91,15 @@ namespace System
             return ToString(format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-            if (m_value < 0 && format != null && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            if (m_value < 0 && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
             {
                 uint temp = (uint)(m_value & 0x000000FF);
                 return Number.TryFormatUInt32(temp, format, info, destination, out charsWritten);
@@ -117,7 +121,7 @@ namespace System
         public static sbyte Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
@@ -125,14 +129,14 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
         public static sbyte Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         // Parses a signed byte from a String in the given style.  If
@@ -144,7 +148,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -157,7 +161,7 @@ namespace System
         private static sbyte Parse(String s, NumberStyles style, NumberFormatInfo info)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, info);
+            return Parse((ReadOnlySpan<char>)s, style, info);
         }
 
         private static sbyte Parse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
@@ -194,7 +198,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         [CLSCompliant(false)]
@@ -214,14 +218,9 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        [CLSCompliant(false)]
-        public static bool TryParse(ReadOnlySpan<char> s, out sbyte result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         [CLSCompliant(false)]
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out sbyte result)
         {
index fe5f570..c357676 100644 (file)
@@ -256,27 +256,27 @@ namespace System
         public static float Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseSingle(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
+            return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
         }
 
         public static float Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseSingle(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseSingle(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static float Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseSingle(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
         }
 
         public static float Parse(String s, NumberStyles style, IFormatProvider provider)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseSingle(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static float Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -293,7 +293,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out float result)
@@ -311,13 +311,9 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static Boolean TryParse(ReadOnlySpan<char> s, out Single result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out float result)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
index 8d3961a..ceeb911 100644 (file)
@@ -1552,6 +1552,7 @@ namespace System.Text
                 //
                 Object arg = args[index];
                 String itemFormat = null;
+                ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
                 // Is current character a colon? which indicates start of formatting parameter.
                 if (ch == ':')
                 {
@@ -1606,13 +1607,13 @@ namespace System.Text
                         if (startPos != pos)
                         {
                             // There was no brace escaping, extract the item format as a single string
-                            itemFormat = format.Substring(startPos, pos - startPos);
+                            itemFormatSpan = format.AsReadOnlySpan().Slice(startPos, pos - startPos);
                         }
                     }
                     else
                     {
                         unescapedItemFormat.Append(format, startPos, pos - startPos);
-                        itemFormat = unescapedItemFormat.ToString();
+                        itemFormatSpan = itemFormat = unescapedItemFormat.ToString();
                         unescapedItemFormat.Clear();
                     }
                 }
@@ -1623,6 +1624,10 @@ namespace System.Text
                 String s = null;
                 if (cf != null)
                 {
+                    if (itemFormatSpan.Length != 0 && itemFormat == null)
+                    {
+                        itemFormat = new string(itemFormatSpan);
+                    }
                     s = cf.Format(itemFormat, arg, provider);
                 }
 
@@ -1632,7 +1637,7 @@ namespace System.Text
                     // try formatting it into the remaining current chunk.
                     if (arg is ISpanFormattable spanFormattableArg &&
                         (leftJustify || width == 0) &&
-                        spanFormattableArg.TryFormat(RemainingCurrentChunk, out int charsWritten, itemFormat, provider))
+                        spanFormattableArg.TryFormat(RemainingCurrentChunk, out int charsWritten, itemFormatSpan, provider))
                     {
                         m_ChunkLength += charsWritten;
 
@@ -1647,6 +1652,10 @@ namespace System.Text
                     // Otherwise, fallback to trying IFormattable or calling ToString.
                     if (arg is IFormattable formattableArg)
                     {
+                        if (itemFormatSpan.Length != 0 && itemFormat == null)
+                        {
+                            itemFormat = new string(itemFormatSpan);
+                        }
                         s = formattableArg.ToString(itemFormat, provider);
                     }
                     else if (arg != null)
index a233538..3ada83e 100644 (file)
@@ -314,12 +314,12 @@ namespace System
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
             /* Constructs a TimeSpan from a string.  Leading and trailing white space characters are allowed. */
-            return TimeSpanParse.Parse(s.AsReadOnlySpan(), null);
+            return TimeSpanParse.Parse(s, null);
         }
         public static TimeSpan Parse(String input, IFormatProvider formatProvider)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
-            return TimeSpanParse.Parse(input.AsReadOnlySpan(), formatProvider);
+            return TimeSpanParse.Parse(input, formatProvider);
         }
         public static TimeSpan Parse(ReadOnlySpan<char> input, IFormatProvider formatProvider = null)
         {
@@ -328,20 +328,30 @@ namespace System
         public static TimeSpan ParseExact(String input, String format, IFormatProvider formatProvider)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
-            return TimeSpanParse.ParseExact(input.AsReadOnlySpan(), format, formatProvider, TimeSpanStyles.None);
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return TimeSpanParse.ParseExact(input, format, formatProvider, TimeSpanStyles.None);
         }
         public static TimeSpan ParseExact(String input, String[] formats, IFormatProvider formatProvider)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
-            return TimeSpanParse.ParseExactMultiple(input.AsReadOnlySpan(), formats, formatProvider, TimeSpanStyles.None);
+            return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None);
         }
         public static TimeSpan ParseExact(String input, String format, IFormatProvider formatProvider, TimeSpanStyles styles)
         {
             ValidateStyles(styles, nameof(styles));
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
-            return TimeSpanParse.ParseExact(input.AsReadOnlySpan(), format, formatProvider, styles);
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
+        }
+
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public static TimeSpan ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles)
+        {
+            if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
+            return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
         }
-        public static TimeSpan ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles = TimeSpanStyles.None)
+
+        public static TimeSpan ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, TimeSpanStyles styles = TimeSpanStyles.None)
         {
             ValidateStyles(styles, nameof(styles));
             return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
@@ -350,7 +360,7 @@ namespace System
         {
             ValidateStyles(styles, nameof(styles));
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
-            return TimeSpanParse.ParseExactMultiple(input.AsReadOnlySpan(), formats, formatProvider, styles);
+            return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles);
         }
         public static TimeSpan ParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles = TimeSpanStyles.None)
         {
@@ -364,17 +374,13 @@ namespace System
                 result = default(TimeSpan);
                 return false;
             }
-            return TimeSpanParse.TryParse(s.AsReadOnlySpan(), null, out result);
+            return TimeSpanParse.TryParse(s, null, out result);
         }
         public static bool TryParse(ReadOnlySpan<char> s, out TimeSpan result)
         {
             return TimeSpanParse.TryParse(s, null, out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> input, out TimeSpan result, IFormatProvider formatProvider = null) =>
-            TryParse(input, formatProvider, out result);
-
         public static Boolean TryParse(String input, IFormatProvider formatProvider, out TimeSpan result)
         {
             if (input == null)
@@ -382,7 +388,7 @@ namespace System
                 result = default(TimeSpan);
                 return false;
             }
-            return TimeSpanParse.TryParse(input.AsReadOnlySpan(), formatProvider, out result);
+            return TimeSpanParse.TryParse(input, formatProvider, out result);
         }
         public static bool TryParse(ReadOnlySpan<char> input, IFormatProvider formatProvider, out TimeSpan result)
         {
@@ -390,15 +396,28 @@ namespace System
         }
         public static Boolean TryParseExact(String input, String format, IFormatProvider formatProvider, out TimeSpan result)
         {
-            if (input == null)
+            if (input == null || format == null)
             {
-                result = default(TimeSpan);
+                result = default;
                 return false;
             }
-            return TimeSpanParse.TryParseExact(input.AsReadOnlySpan(), format, formatProvider, TimeSpanStyles.None, out result);
+            return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result);
         }
+
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
         public static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, out TimeSpan result)
         {
+            if (format == null)
+            {
+                result = default;
+                return false;
+            }
+
+            return TryParseExact(input, (ReadOnlySpan<char>)format, formatProvider, out result);
+        }
+
+        public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, out TimeSpan result)
+        {
             return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result);
         }
         public static Boolean TryParseExact(String input, String[] formats, IFormatProvider formatProvider, out TimeSpan result)
@@ -408,29 +427,39 @@ namespace System
                 result = default(TimeSpan);
                 return false;
             }
-            return TimeSpanParse.TryParseExactMultiple(input.AsReadOnlySpan(), formats, formatProvider, TimeSpanStyles.None, out result);
+            return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result);
         }
         public static bool TryParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, out TimeSpan result)
         {
             return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, out TimeSpan result, TimeSpanStyles styles = TimeSpanStyles.None) =>
-            TryParseExact(input, format, formatProvider, styles, out result);
-
         public static Boolean TryParseExact(String input, String format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
         {
             ValidateStyles(styles, nameof(styles));
-            if (input == null)
+            if (input == null || format == null)
             {
-                result = default(TimeSpan);
+                result = default;
                 return false;
             }
-            return TimeSpanParse.TryParseExact(input.AsReadOnlySpan(), format, formatProvider, styles, out result);
+
+            return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
         }
+
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
         public static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
         {
+            if (format == null)
+            {
+                result = default;
+                return false;
+            }
+
+            return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
+        }
+
+        public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
+        {
             ValidateStyles(styles, nameof(styles));
             return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
         }
@@ -442,13 +471,9 @@ namespace System
                 result = default(TimeSpan);
                 return false;
             }
-            return TimeSpanParse.TryParseExactMultiple(input.AsReadOnlySpan(), formats, formatProvider, styles, out result);
+            return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, out TimeSpan result, TimeSpanStyles styles = TimeSpanStyles.None) =>
-            TryParseExact(input, formats, formatProvider, styles, out result);
-
         public static bool TryParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
         {
             ValidateStyles(styles, nameof(styles));
@@ -466,7 +491,12 @@ namespace System
         {
             return TimeSpanFormat.Format(this, format, formatProvider);
         }
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider formatProvider = null)
+
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider formatProvider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, formatProvider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider formatProvider = null)
         {
             return TimeSpanFormat.TryFormat(this, destination, out charsWritten, format, formatProvider);
         }
index ea74931..5d21225 100644 (file)
@@ -88,7 +88,11 @@ namespace System
             return Number.FormatUInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatUInt32(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -97,7 +101,7 @@ namespace System
         public static ushort Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
@@ -105,7 +109,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
         }
 
 
@@ -113,7 +117,7 @@ namespace System
         public static ushort Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -121,7 +125,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -156,7 +160,7 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         [CLSCompliant(false)]
@@ -176,14 +180,9 @@ namespace System
                 return false;
             }
 
-            return TryParse(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        [CLSCompliant(false)]
-        public static bool TryParse(ReadOnlySpan<char> s, out ushort result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         [CLSCompliant(false)]
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out ushort result)
         {
index 67f6f06..a007dc8 100644 (file)
@@ -96,7 +96,11 @@ namespace System
             return Number.FormatUInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatUInt32(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -105,7 +109,7 @@ namespace System
         public static uint Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
@@ -113,7 +117,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseUInt32(s, style, NumberFormatInfo.CurrentInfo);
         }
 
 
@@ -121,7 +125,7 @@ namespace System
         public static uint Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -129,7 +133,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -148,7 +152,7 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseUInt32(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return Number.TryParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         [CLSCompliant(false)]
@@ -168,14 +172,9 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseUInt32(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return Number.TryParseUInt32(s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        [CLSCompliant(false)]
-        public static bool TryParse(ReadOnlySpan<char> s, out UInt32 result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         [CLSCompliant(false)]
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out uint result)
         {
index 86434d6..87a3c5d 100644 (file)
@@ -94,7 +94,11 @@ namespace System
             return Number.FormatUInt64(m_value, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatUInt64(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -103,7 +107,7 @@ namespace System
         public static ulong Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+            return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
@@ -111,14 +115,14 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseUInt64(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         [CLSCompliant(false)]
         public static ulong Parse(string s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -126,7 +130,7 @@ namespace System
         {
             NumberFormatInfo.ValidateParseStyleInteger(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseUInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         [CLSCompliant(false)]
@@ -145,7 +149,7 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseUInt64(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+            return Number.TryParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
         }
 
         [CLSCompliant(false)]
@@ -165,14 +169,9 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseUInt64(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return Number.TryParseUInt64(s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        [CLSCompliant(false)]
-        public static Boolean TryParse(ReadOnlySpan<char> s, out UInt64 result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         [CLSCompliant(false)]
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out ulong result)
         {
index 8ed36af..df16be2 100644 (file)
@@ -229,7 +229,7 @@ namespace System
             return false;
         }
 
-        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider)
+        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
         {
             // format and provider are ignored.
             return TryFormat(destination, out charsWritten);
index 998a73d..485a89a 100644 (file)
@@ -501,7 +501,11 @@ namespace System
             return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider));
         }
 
-        public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
+        public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
+            TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
         {
             return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
         }
@@ -516,27 +520,27 @@ namespace System
         public static Decimal Parse(String s)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDecimal(s.AsReadOnlySpan(), NumberStyles.Number, NumberFormatInfo.CurrentInfo);
+            return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo);
         }
 
         public static Decimal Parse(String s, NumberStyles style)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDecimal(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
+            return Number.ParseDecimal(s, style, NumberFormatInfo.CurrentInfo);
         }
 
         public static Decimal Parse(String s, IFormatProvider provider)
         {
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDecimal(s.AsReadOnlySpan(), NumberStyles.Number, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider));
         }
 
         public static Decimal Parse(String s, NumberStyles style, IFormatProvider provider)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
-            return Number.ParseDecimal(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider));
+            return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
         }
 
         public static decimal Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
@@ -553,7 +557,7 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseDecimal(s.AsReadOnlySpan(), NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result);
+            return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result);
         }
 
         public static bool TryParse(ReadOnlySpan<char> s, out decimal result)
@@ -571,13 +575,9 @@ namespace System
                 return false;
             }
 
-            return Number.TryParseDecimal(s.AsReadOnlySpan(), style, NumberFormatInfo.GetInstance(provider), out result);
+            return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result);
         }
 
-        // TODO https://github.com/dotnet/corefx/issues/23642: Remove once corefx has been updated with new overloads.
-        public static bool TryParse(ReadOnlySpan<char> s, out decimal result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) =>
-            TryParse(s, style, provider, out result);
-
         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out decimal result)
         {
             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
index ae3fe98..23b0e69 100644 (file)
@@ -450,7 +450,8 @@ namespace System
         input,
         ownedMemory,
         pointer,
-        start
+        start,
+        format
     }
 
     //