Skip to content

Commit

Permalink
Use ThrowHelper for GetMaxByteCount
Browse files Browse the repository at this point in the history
  • Loading branch information
xtqqczze committed Jan 6, 2025
1 parent b33f755 commit 9df535f
Show file tree
Hide file tree
Showing 18 changed files with 114 additions and 72 deletions.
10 changes: 6 additions & 4 deletions src/libraries/Common/src/System/Text/OSEncoding.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,13 @@ public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

ulong byteCount = (uint)charCount * 14uL; // Max possible value for all encodings

long byteCount = (long)charCount * 14; // Max possible value for all encodings
if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -836,18 +836,20 @@ internal sealed override OperationStatus DecodeFirstRune(ReadOnlySpan<byte> byte

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 1 to 1 for most characters. Only surrogates with fallbacks have less.

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,20 @@ private protected sealed override unsafe int GetByteCountFast(char* pChars, int

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 1 to 1 for most characters. Only surrogates with fallbacks have less.

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ 2 21 00000000 000xxxxx hhhhhhll llllllll
Real Unicode value = (HighSurrogate - 0xD800) * 0x400 + (LowSurrogate - 0xDC00) + 0x10000
*/

private const int MaxUtf32BytesPerChar = 4;

// Used by Encoding.UTF32/BigEndianUTF32 for lazy initialization
// The initialization code will not be run until a static member of the class is referenced
internal static readonly UTF32Encoding s_default = new UTF32Encoding(bigEndian: false, byteOrderMark: true);
Expand Down Expand Up @@ -1067,19 +1069,19 @@ public override Encoder GetEncoder()

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case left over high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 4 bytes per char
byteCount *= 4;
byteCount *= MaxUtf32BytesPerChar;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,8 @@ public override Text.Encoder GetEncoder()

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Suppose that every char can not be direct-encoded, we know that
// a byte can encode 6 bits of the Unicode character. And we will
Expand All @@ -741,11 +742,11 @@ public override int GetMaxByteCount(int charCount)

// Note that UTF7 encoded surrogates individually and isn't worried about mismatches, so all
// code points are encodable int UTF7.
long byteCount = (long)charCount * 3 + 2;
ulong byteCount = (uint)charCount * 3uL + 2;

// check for overflow
if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,7 @@ public override int GetMaxByteCount(int charCount)

if ((uint)charCount > (int.MaxValue / MaxUtf8BytesPerChar) - 1)
{
// Move the throw out of the hot path to allow for inlining.
ThrowArgumentException(charCount);
static void ThrowArgumentException(int charCount)
{
throw new ArgumentOutOfRangeException(
paramName: nameof(charCount),
message: (charCount < 0) ? SR.ArgumentOutOfRange_NeedNonNegNum : SR.ArgumentOutOfRange_GetByteCountOverflow);
}
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);
}

return (charCount * MaxUtf8BytesPerChar) + MaxUtf8BytesPerChar;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,8 @@ internal sealed override OperationStatus DecodeFirstRune(ReadOnlySpan<byte> byte

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// GetMaxByteCount assumes that the caller might have a stateful Encoder instance. If the
// Encoder instance already has a captured high surrogate, then one of two things will
Expand All @@ -808,15 +809,15 @@ public override int GetMaxByteCount(int charCount)
// pessimistic "max byte count" calculation: assume there's a captured surrogate and that
// it must fall back.

long byteCount = (long)charCount + 1; // +1 to account for captured surrogate, per above
ulong byteCount = (uint)charCount + 1; // +1 to account for captured surrogate, per above

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

byteCount *= MaxUtf8BytesPerChar;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1744,19 +1744,20 @@ public override byte[] GetPreamble()

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case left over high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 2 bytes per char
byteCount <<= 1;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
11 changes: 11 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,17 @@ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument
throw GetArgumentOutOfRangeException(argument, paramNumber, resource);
}

[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException_GetMaxByteCount(int charCount)
{
throw new ArgumentOutOfRangeException(
paramName: nameof(charCount),
charCount,
message: (charCount < 0) ?
SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNonNegative, nameof(charCount), charCount) :
SR.ArgumentOutOfRange_GetByteCountOverflow);
}

[DoesNotReturn]
internal static void ThrowEndOfFileException()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ internal sealed class Base64Encoding : Encoding

public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);
if ((charCount % 4) != 0)
throw new FormatException(SR.Format(SR.XmlInvalidBase64Length, charCount.ToString()));
return charCount / 4 * 3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ internal sealed class BinHexEncoding : Encoding
{
public override int GetMaxByteCount(int charCount)
{
ArgumentOutOfRangeException.ThrowIfNegative(charCount);
if (charCount < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);
if ((charCount % 2) != 0)
throw new FormatException(SR.Format(SR.XmlInvalidBinHexLength, charCount.ToString()));
return charCount / 2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ System.Text.CodePagesEncodingProvider</PackageDescription>
<Compile Include="System\Text\ISO2022Encoding.cs" />
<Compile Include="System\Text\ISCIIEncoding.cs" />
<Compile Include="System\Text\SBCSCodePageEncoding.cs" />
<Compile Include="System\Text\ThrowHelper.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows' or '$(TargetFrameworkIdentifier)' == '.NETFramework'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1118,19 +1118,19 @@ public override unsafe int GetChars(byte* bytes, int byteCount,
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_NeedNonNegNum);
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 2 to 1 is worst case. Already considered surrogate fallback
byteCount *= 2;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -742,19 +742,19 @@ public override unsafe int GetChars(byte* bytes, int byteCount,
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_NeedNonNegNum);
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// We could have 4 bytes for each char, no extra for surrogates because 18030 can do whole unicode range.
byteCount *= 4;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,19 @@ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext contex
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_NeedNonNegNum);
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 4 Time input because 1st input could require code page change and also that char could require 2 code points
byteCount *= 4;

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1691,13 +1691,13 @@ private unsafe int GetCharsCP52936(byte* bytes, int byteCount,
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_NeedNonNegNum);
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// Start with just generic DBCS values (sort of).
int perChar = 2;
Expand Down Expand Up @@ -1732,11 +1732,11 @@ public override int GetMaxByteCount(int charCount)
}

// Return our surrogate and End plus perChar for each char.
byteCount *= perChar;
byteCount += extraStart + extraEnd;
byteCount *= (uint)perChar;
byteCount += (uint)(extraStart + extraEnd);

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -903,18 +903,19 @@ public override unsafe int GetChars(byte* bytes, int byteCount,
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_NeedNonNegNum);
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
long byteCount = (long)charCount + 1;
ulong byteCount = (uint)charCount + 1;

if (EncoderFallback.MaxCharCount > 1)
byteCount *= EncoderFallback.MaxCharCount;
byteCount *= (uint)EncoderFallback.MaxCharCount;

// 1 to 1 for most characters. Only surrogates with fallbacks have less.

if (byteCount > 0x7fffffff)
throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
if (byteCount > int.MaxValue)
ThrowHelper.ThrowArgumentOutOfRangeException_GetMaxByteCount(charCount);

return (int)byteCount;
}

Expand Down
Loading

1 comment on commit 9df535f

@xtqqczze
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.