Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ private static void FixDefaultShortDatePattern(List<string> shortDatePatterns)
/// </remarks>
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)
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4226,20 +4226,20 @@ 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;

// 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++)
{
Expand Down Expand Up @@ -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<char> format, int pos, StringBuilder result, out int returnValue)
internal static bool TryParseQuoteString(ReadOnlySpan<char> 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)
Expand All @@ -4411,15 +4407,14 @@ internal static bool TryParseQuoteString(ReadOnlySpan<char> 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;
}
}
Expand All @@ -4432,6 +4427,7 @@ internal static bool TryParseQuoteString(ReadOnlySpan<char> format, int pos, Str
if (!foundQuote)
{
// Here we can't find the matching quote.
returnValue = 0;
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -1261,7 +1258,7 @@ private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char

var tokenizer = new TimeSpanTokenizer(input, -1);

while (i < format.Length)
while ((uint)i < (uint)format.Length)
{
char ch = format[i];
int nextFormatChar;
Expand Down Expand Up @@ -1324,18 +1321,18 @@ private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char

case '\'':
case '\"':
StringBuilder enquotedString = StringBuilderCache.Acquire();
if (!DateTimeParse.TryParseQuoteString(format, i, enquotedString, out tokenLen))
var enquotedString = new ValueStringBuilder(64);
if (!DateTimeParse.TryParseQuoteString(format, i, ref enquotedString, out tokenLen))
{
StringBuilderCache.Release(enquotedString);
enquotedString.Dispose();
return result.SetBadQuoteFailure(ch);
}
if (!ParseExactLiteral(ref tokenizer, enquotedString))
if (!ParseExactLiteral(ref tokenizer, ref enquotedString))
{
StringBuilderCache.Release(enquotedString);
enquotedString.Dispose();
return result.SetInvalidStringFailure();
}
StringBuilderCache.Release(enquotedString);
enquotedString.Dispose();
break;

case '%':
Expand Down Expand Up @@ -1363,7 +1360,7 @@ private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char
// For example, "\d" will insert the character 'd' into the string.
//
nextFormatChar = DateTimeFormat.ParseNextChar(format, i);
if (nextFormatChar >= 0 && tokenizer.NextChar == (char)nextFormatChar)
if (nextFormatChar >= 0 && tokenizer.NextChar() == (char)nextFormatChar)
{
tokenLen = 2;
}
Expand Down Expand Up @@ -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();
Expand All @@ -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<char> span = enquotedString.AsSpan();
for (int i = 0; i < span.Length; i++)
{
if (enquotedString[i] != tokenizer.NextChar)
if (span[i] != tokenizer.NextChar())
{
return false;
}
Expand Down
21 changes: 7 additions & 14 deletions src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,23 +509,16 @@ public override void WriteLine(ReadOnlySpan<char> 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<char> 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)
Expand Down