diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs index f5d5b0061f06d2..a29b249ea668bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs @@ -258,7 +258,9 @@ private static void FixDefaultShortDatePattern(List shortDatePatterns) /// private static string NormalizeDatePattern(string input) { - StringBuilder destination = StringBuilderCache.Acquire(input.Length); + var destination = input.Length < 128 ? + new ValueStringBuilder(stackalloc char[128]) : + new ValueStringBuilder(input.Length); int index = 0; while (index < input.Length) @@ -287,7 +289,7 @@ private static string NormalizeDatePattern(string input) // maps closest to 3 or 4 'd's in .NET // 'c' in ICU is the stand-alone day of the week, which has no representation in .NET, but // maps closest to 3 or 4 'd's in .NET - NormalizeDayOfWeek(input, destination, ref index); + NormalizeDayOfWeek(input, ref destination, ref index); break; case 'L': case 'M': @@ -332,10 +334,10 @@ private static string NormalizeDatePattern(string input) } } - return StringBuilderCache.GetStringAndRelease(destination); + return destination.ToString(); } - private static void NormalizeDayOfWeek(string input, StringBuilder destination, ref int index) + private static void NormalizeDayOfWeek(string input, ref ValueStringBuilder destination, ref int index) { char dayChar = input[index]; int occurrences = CountOccurrences(input, dayChar, ref index); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs index 6020e84411bf3a..e993a17abba248 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -4226,12 +4226,12 @@ private static bool ParseByFormat( break; case '\"': case '\'': - StringBuilder enquotedString = StringBuilderCache.Acquire(); + var enquotedString = new ValueStringBuilder(stackalloc char[128]); // Use ParseQuoteString so that we can handle escape characters within the quoted string. - if (!TryParseQuoteString(format.Value, format.Index, enquotedString, out tokenLen)) + if (!TryParseQuoteString(format.Value, format.Index, ref enquotedString, out tokenLen)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch); - StringBuilderCache.Release(enquotedString); + enquotedString.Dispose(); return false; } format.Index += tokenLen - 1; @@ -4239,7 +4239,7 @@ private static bool ParseByFormat( // Some cultures uses space in the quoted string. E.g. Spanish has long date format as: // "dddd, dd' de 'MMMM' de 'yyyy". When inner spaces flag is set, we should skip whitespaces if there is space // in the quoted string. - string quotedStr = StringBuilderCache.GetStringAndRelease(enquotedString); + string quotedStr = enquotedString.ToString(); for (int i = 0; i < quotedStr.Length; i++) { @@ -4385,18 +4385,14 @@ private static bool ParseByFormat( // The pos should point to a quote character. This method will // get the string enclosed by the quote character. // - internal static bool TryParseQuoteString(ReadOnlySpan format, int pos, StringBuilder result, out int returnValue) + internal static bool TryParseQuoteString(ReadOnlySpan format, int pos, ref ValueStringBuilder result, out int returnValue) { - // - // NOTE : pos will be the index of the quote character in the 'format' string. - // - returnValue = 0; - int formatLen = format.Length; + // NOTE: pos will be the index of the quote character in the 'format' string. int beginPos = pos; char quoteChar = format[pos++]; // Get the character used to quote the following string. bool foundQuote = false; - while (pos < formatLen) + while ((uint)pos < (uint)format.Length) { char ch = format[pos++]; if (ch == quoteChar) @@ -4411,15 +4407,14 @@ internal static bool TryParseQuoteString(ReadOnlySpan format, int pos, Str // Therefore, someone can use a format like "'minute:' mm\"" to display: // minute: 45" // because the second double quote is escaped. - if (pos < formatLen) + if ((uint)pos < (uint)format.Length) { result.Append(format[pos++]); } else { - // // This means that '\' is at the end of the formatting string. - // + returnValue = 0; return false; } } @@ -4432,6 +4427,7 @@ internal static bool TryParseQuoteString(ReadOnlySpan format, int pos, Str if (!foundQuote) { // Here we can't find the matching quote. + returnValue = 0; return false; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs index 0eb7fd2fc20f3f..ec5e39f76938d3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs @@ -246,15 +246,12 @@ internal void BackOne() if (_pos > 0) --_pos; } - internal char NextChar + internal char NextChar() { - get - { - int pos = ++_pos; - return (uint)pos < (uint)_value.Length ? - _value[pos] : - (char)0; - } + int pos = ++_pos; + return (uint)pos < (uint)_value.Length? + _value[pos] : + (char)0; } } @@ -1261,7 +1258,7 @@ private static bool TryParseByFormat(ReadOnlySpan input, ReadOnlySpan input, ReadOnlySpan input, ReadOnlySpan= 0 && tokenizer.NextChar == (char)nextFormatChar) + if (nextFormatChar >= 0 && tokenizer.NextChar() == (char)nextFormatChar) { tokenLen = 2; } @@ -1423,7 +1420,7 @@ private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDig int tokenLength = 0; while (tokenLength < maxDigitLength) { - char ch = tokenizer.NextChar; + char ch = tokenizer.NextChar(); if (ch < '0' || ch > '9') { tokenizer.BackOne(); @@ -1440,11 +1437,12 @@ private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDig return tokenLength >= minDigitLength; } - private static bool ParseExactLiteral(ref TimeSpanTokenizer tokenizer, StringBuilder enquotedString) + private static bool ParseExactLiteral(ref TimeSpanTokenizer tokenizer, ref ValueStringBuilder enquotedString) { - for (int i = 0; i < enquotedString.Length; i++) + ReadOnlySpan span = enquotedString.AsSpan(); + for (int i = 0; i < span.Length; i++) { - if (enquotedString[i] != tokenizer.NextChar) + if (span[i] != tokenizer.NextChar()) { return false; } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs index c591e51f15e232..656739a7c855e7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs @@ -509,23 +509,16 @@ public override void WriteLine(ReadOnlySpan buffer) private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine) { - StringBuilder sb = - StringBuilderCache.Acquire((format?.Length ?? 0) + args.Length * 8) - .AppendFormatHelper(null, format!, args); // AppendFormatHelper will appropriately throw ArgumentNullException for a null format + int estimatedLength = (format?.Length ?? 0) + args.Length * 8; + var vsb = estimatedLength <= 256 ? + new ValueStringBuilder(stackalloc char[256]) : + new ValueStringBuilder(estimatedLength); - StringBuilder.ChunkEnumerator chunks = sb.GetChunks(); + vsb.AppendFormatHelper(null, format!, args); // AppendFormatHelper will appropriately throw ArgumentNullException for a null format - bool more = chunks.MoveNext(); - while (more) - { - ReadOnlySpan current = chunks.Current.Span; - more = chunks.MoveNext(); - - // If final chunk, include the newline if needed - WriteSpan(current, appendNewLine: more ? false : appendNewLine); - } + WriteSpan(vsb.AsSpan(), appendNewLine); - StringBuilderCache.Release(sb); + vsb.Dispose(); } public override void Write(string format, object? arg0)