Imported Upstream version 5.10.0.69

Former-commit-id: fc39669a0b707dd3c063977486506b6793da2890
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-29 19:03:06 +00:00
parent d8f8abd549
commit e2950ec768
6283 changed files with 453847 additions and 91879 deletions

View File

@@ -35,10 +35,10 @@ Global
{28AE24F8-BEF4-4358-B612-ADD9D587C8E1}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{28AE24F8-BEF4-4358-B612-ADD9D587C8E1}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{28AE24F8-BEF4-4358-B612-ADD9D587C8E1}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Release|Any CPU.Build.0 = Release|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{3842BE38-1A99-41B2-81B5-186E64077B95}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{D2C99D27-0BEF-4319-ADB3-05CBEBA8F69B}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{D2C99D27-0BEF-4319-ADB3-05CBEBA8F69B}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{D2C99D27-0BEF-4319-ADB3-05CBEBA8F69B}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU

View File

@@ -5,19 +5,18 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
namespace System.Numerics
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct BigInteger : System.IComparable, System.IComparable<System.Numerics.BigInteger>, System.IEquatable<System.Numerics.BigInteger>, System.IFormattable
public readonly partial struct BigInteger : System.IComparable, System.IComparable<System.Numerics.BigInteger>, System.IEquatable<System.Numerics.BigInteger>, System.IFormattable
{
private readonly object _dummy;
[System.CLSCompliantAttribute(false)]
public BigInteger(byte[] value) { throw null; }
public BigInteger(System.ReadOnlySpan<byte> value) { throw null; }
public BigInteger(decimal value) { throw null; }
public BigInteger(double value) { throw null; }
public BigInteger(int value) { throw null; }
public BigInteger(long value) { throw null; }
public BigInteger(System.ReadOnlySpan<byte> value, bool isUnsigned=false, bool isBigEndian=false) { throw null; }
public BigInteger(float value) { throw null; }
[System.CLSCompliantAttribute(false)]
public BigInteger(uint value) { throw null; }
@@ -35,8 +34,8 @@ namespace System.Numerics
public static System.Numerics.BigInteger Add(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public static int Compare(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public int CompareTo(long other) { throw null; }
public int CompareTo(object obj) { throw null; }
public int CompareTo(System.Numerics.BigInteger other) { throw null; }
public int CompareTo(object obj) { throw null; }
[System.CLSCompliantAttribute(false)]
public int CompareTo(ulong other) { throw null; }
public static System.Numerics.BigInteger Divide(System.Numerics.BigInteger dividend, System.Numerics.BigInteger divisor) { throw null; }
@@ -46,8 +45,8 @@ namespace System.Numerics
public override bool Equals(object obj) { throw null; }
[System.CLSCompliantAttribute(false)]
public bool Equals(ulong other) { throw null; }
public int GetByteCount(bool isUnsigned=false) { throw null; }
public override int GetHashCode() { throw null; }
public int GetByteCount() { throw null; }
public static System.Numerics.BigInteger GreatestCommonDivisor(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public static double Log(System.Numerics.BigInteger value) { throw null; }
public static double Log(System.Numerics.BigInteger value, double baseValue) { throw null; }
@@ -70,8 +69,8 @@ namespace System.Numerics
[System.CLSCompliantAttribute(false)]
public static bool operator ==(ulong left, System.Numerics.BigInteger right) { throw null; }
public static System.Numerics.BigInteger operator ^(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public static explicit operator System.Numerics.BigInteger(decimal value) { throw null; }
public static explicit operator System.Numerics.BigInteger(double value) { throw null; }
public static explicit operator System.Numerics.BigInteger (decimal value) { throw null; }
public static explicit operator System.Numerics.BigInteger (double value) { throw null; }
public static explicit operator byte (System.Numerics.BigInteger value) { throw null; }
public static explicit operator decimal (System.Numerics.BigInteger value) { throw null; }
public static explicit operator double (System.Numerics.BigInteger value) { throw null; }
@@ -87,7 +86,7 @@ namespace System.Numerics
public static explicit operator uint (System.Numerics.BigInteger value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static explicit operator ulong (System.Numerics.BigInteger value) { throw null; }
public static explicit operator System.Numerics.BigInteger(float value) { throw null; }
public static explicit operator System.Numerics.BigInteger (float value) { throw null; }
public static bool operator >(long left, System.Numerics.BigInteger right) { throw null; }
public static bool operator >(System.Numerics.BigInteger left, long right) { throw null; }
public static bool operator >(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
@@ -102,18 +101,18 @@ namespace System.Numerics
public static bool operator >=(System.Numerics.BigInteger left, ulong right) { throw null; }
[System.CLSCompliantAttribute(false)]
public static bool operator >=(ulong left, System.Numerics.BigInteger right) { throw null; }
public static implicit operator System.Numerics.BigInteger(byte value) { throw null; }
public static implicit operator System.Numerics.BigInteger(short value) { throw null; }
public static implicit operator System.Numerics.BigInteger(int value) { throw null; }
public static implicit operator System.Numerics.BigInteger(long value) { throw null; }
public static implicit operator System.Numerics.BigInteger (byte value) { throw null; }
public static implicit operator System.Numerics.BigInteger (short value) { throw null; }
public static implicit operator System.Numerics.BigInteger (int value) { throw null; }
public static implicit operator System.Numerics.BigInteger (long value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.BigInteger(sbyte value) { throw null; }
public static implicit operator System.Numerics.BigInteger (sbyte value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.BigInteger(ushort value) { throw null; }
public static implicit operator System.Numerics.BigInteger (ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.BigInteger(uint value) { throw null; }
public static implicit operator System.Numerics.BigInteger (uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.BigInteger(ulong value) { throw null; }
public static implicit operator System.Numerics.BigInteger (ulong value) { throw null; }
public static System.Numerics.BigInteger operator ++(System.Numerics.BigInteger value) { throw null; }
public static bool operator !=(long left, System.Numerics.BigInteger right) { throw null; }
public static bool operator !=(System.Numerics.BigInteger left, long right) { throw null; }
@@ -144,27 +143,30 @@ namespace System.Numerics
public static System.Numerics.BigInteger operator -(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public static System.Numerics.BigInteger operator -(System.Numerics.BigInteger value) { throw null; }
public static System.Numerics.BigInteger operator +(System.Numerics.BigInteger value) { throw null; }
public static System.Numerics.BigInteger Parse(System.ReadOnlySpan<char> value, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
public static System.Numerics.BigInteger Parse(string value) { throw null; }
public static System.Numerics.BigInteger Parse(string value, System.Globalization.NumberStyles style) { throw null; }
public static System.Numerics.BigInteger Parse(string value, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
public static System.Numerics.BigInteger Parse(string value, System.IFormatProvider provider) { throw null; }
public static System.Numerics.BigInteger Parse(System.ReadOnlySpan<char> value, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, System.IFormatProvider provider = null) { throw null; }
public static System.Numerics.BigInteger Pow(System.Numerics.BigInteger value, int exponent) { throw null; }
public static System.Numerics.BigInteger Remainder(System.Numerics.BigInteger dividend, System.Numerics.BigInteger divisor) { throw null; }
public static System.Numerics.BigInteger Subtract(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; }
public byte[] ToByteArray() { throw null; }
public byte[] ToByteArray(bool isUnsigned=false, bool isBigEndian=false) { throw null; }
public override string ToString() { throw null; }
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> value, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Numerics.BigInteger result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> value, out System.Numerics.BigInteger result) { throw null; }
public static bool TryParse(string value, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Numerics.BigInteger result) { throw null; }
public static bool TryParse(string value, out System.Numerics.BigInteger result) { throw null; }
public static bool TryParse(ReadOnlySpan<char> value, out System.Numerics.BigInteger result, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, System.IFormatProvider provider = null) { throw null; }
public bool TryWriteBytes(System.Span<byte> destination, out int bytesWritten) { throw null; }
public bool TryWriteBytes(System.Span<byte> destination, out int bytesWritten, bool isUnsigned=false, bool isBigEndian=false) { throw null; }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct Complex : System.IEquatable<System.Numerics.Complex>, System.IFormattable
{
private int _dummy;
public static readonly System.Numerics.Complex ImaginaryOne;
public static readonly System.Numerics.Complex One;
public static readonly System.Numerics.Complex Zero;
@@ -195,22 +197,22 @@ namespace System.Numerics
public static System.Numerics.Complex operator +(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }
public static System.Numerics.Complex operator /(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }
public static bool operator ==(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }
public static explicit operator System.Numerics.Complex(decimal value) { throw null; }
public static explicit operator System.Numerics.Complex(System.Numerics.BigInteger value) { throw null; }
public static implicit operator System.Numerics.Complex(byte value) { throw null; }
public static implicit operator System.Numerics.Complex(double value) { throw null; }
public static implicit operator System.Numerics.Complex(short value) { throw null; }
public static implicit operator System.Numerics.Complex(int value) { throw null; }
public static implicit operator System.Numerics.Complex(long value) { throw null; }
public static explicit operator System.Numerics.Complex (decimal value) { throw null; }
public static explicit operator System.Numerics.Complex (System.Numerics.BigInteger value) { throw null; }
public static implicit operator System.Numerics.Complex (byte value) { throw null; }
public static implicit operator System.Numerics.Complex (double value) { throw null; }
public static implicit operator System.Numerics.Complex (short value) { throw null; }
public static implicit operator System.Numerics.Complex (int value) { throw null; }
public static implicit operator System.Numerics.Complex (long value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.Complex(sbyte value) { throw null; }
public static implicit operator System.Numerics.Complex(float value) { throw null; }
public static implicit operator System.Numerics.Complex (sbyte value) { throw null; }
public static implicit operator System.Numerics.Complex (float value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.Complex(ushort value) { throw null; }
public static implicit operator System.Numerics.Complex (ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.Complex(uint value) { throw null; }
public static implicit operator System.Numerics.Complex (uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static implicit operator System.Numerics.Complex(ulong value) { throw null; }
public static implicit operator System.Numerics.Complex (ulong value) { throw null; }
public static bool operator !=(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }
public static System.Numerics.Complex operator *(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }
public static System.Numerics.Complex operator -(System.Numerics.Complex left, System.Numerics.Complex right) { throw null; }

View File

@@ -100,4 +100,7 @@
<data name="Overflow_Decimal" xml:space="preserve">
<value>Value was either too large or too small for a Decimal.</value>
</data>
</root>
<data name="Overflow_Negative_Unsigned" xml:space="preserve">
<value>Negative values do not have an unsigned representation.</value>
</data>
</root>

View File

@@ -8,7 +8,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{D2C99D27-0BEF-4319-ADB3-05CBEBA8F69B}</ProjectGuid>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
@@ -30,11 +29,15 @@
<Compile Include="$(CommonPath)\System\Globalization\FormatProvider.Number.cs">
<Link>System\Globalization\FormatProvider.Number.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Text\ValueStringBuilder.cs">
<Link>System\Text\ValueStringBuilder.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Diagnostics.Contracts" />
<Reference Include="System.Buffers" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />

View File

@@ -9,29 +9,31 @@ namespace System.Globalization
{
internal partial class FormatProvider
{
[SecurityCritical]
internal static string FormatBigInteger(int precision, int scale, bool sign, string format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
internal static void FormatBigInteger(ref ValueStringBuilder sb, int precision, int scale, bool sign, ReadOnlySpan<char> format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
{
unsafe
{
int maxDigits;
char fmt = Number.ParseFormatSpecifier(format, out maxDigits);
fixed (char* overrideDigits = digits)
{
FormatProvider.Number.NumberBuffer numberBuffer = new FormatProvider.Number.NumberBuffer();
var numberBuffer = new Number.NumberBuffer();
numberBuffer.overrideDigits = overrideDigits + startIndex;
numberBuffer.precision = precision;
numberBuffer.scale = scale;
numberBuffer.sign = sign;
char fmt = Number.ParseFormatSpecifier(format, out int maxDigits);
if (fmt != 0)
return Number.NumberToString(numberBuffer, fmt, maxDigits, numberFormatInfo, isDecimal: false);
return Number.NumberToStringFormat(numberBuffer, format, numberFormatInfo);
{
Number.NumberToString(ref sb, ref numberBuffer, fmt, maxDigits, numberFormatInfo, isDecimal: false);
}
else
{
Number.NumberToStringFormat(ref sb, ref numberBuffer, format, numberFormatInfo);
}
}
}
}
[SecurityCritical]
internal static bool TryStringToBigInteger(
ReadOnlySpan<char> s,
NumberStyles styles,

View File

@@ -20,14 +20,12 @@ namespace System.Globalization
public char* digits
{
[SecurityCritical]
get
{
return overrideDigits;
}
}
[SecurityCritical]
public char* overrideDigits; // Used for BigNumber support which can't be limited to 32 characters.
}
}

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
namespace System.Numerics
@@ -12,7 +11,7 @@ namespace System.Numerics
#if !MONO
[System.Runtime.CompilerServices.TypeForwardedFrom("System.Numerics, Version=4.0.0.0, PublicKeyToken=b77a5c561934e089")]
#endif
public struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
public readonly struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
{
private const int knMaskHighBit = int.MinValue;
private const uint kuMaskHighBit = unchecked((uint)int.MinValue);
@@ -146,7 +145,6 @@ namespace System.Numerics
throw new OverflowException(SR.Overflow_NotANumber);
}
}
Contract.EndContractBlock();
_sign = 0;
_bits = null;
@@ -258,21 +256,42 @@ namespace System.Numerics
{
}
public BigInteger(ReadOnlySpan<byte> value)
public BigInteger(ReadOnlySpan<byte> value, bool isUnsigned=false, bool isBigEndian=false)
{
int byteCount = value.Length;
bool isNegative;
if (byteCount > 0)
{
byte lastByte = value[byteCount - 1];
isNegative = (lastByte & 0x80) != 0;
if (lastByte == 0)
byte mostSignificantByte = isBigEndian ? value[0] : value[byteCount - 1];
isNegative = (mostSignificantByte & 0x80) != 0 && !isUnsigned;
if (mostSignificantByte == 0)
{
// Try to conserve space as much as possible by checking for wasted leading byte[] entries
byteCount -= 2;
while (byteCount >= 0 && value[byteCount] == 0) byteCount--;
byteCount++;
if (isBigEndian)
{
int offset = 1;
while (offset < byteCount && value[offset] == 0)
{
offset++;
}
value = value.Slice(offset);
byteCount = value.Length;
}
else
{
byteCount -= 2;
while (byteCount >= 0 && value[byteCount] == 0)
{
byteCount--;
}
byteCount++;
}
}
}
else
@@ -292,9 +311,20 @@ namespace System.Numerics
if (byteCount <= 4)
{
_sign = isNegative ? unchecked((int)0xffffffff) : 0;
for (int i = byteCount - 1; i >= 0; i--)
if (isBigEndian)
{
_sign = (_sign << 8) | value[i];
for (int i = 0; i < byteCount; i++)
{
_sign = (_sign << 8) | value[i];
}
}
else
{
for (int i = byteCount - 1; i >= 0; i--)
{
_sign = (_sign << 8) | value[i];
}
}
_bits = null;
@@ -317,28 +347,65 @@ namespace System.Numerics
int unalignedBytes = byteCount % 4;
int dwordCount = byteCount / 4 + (unalignedBytes == 0 ? 0 : 1);
uint[] val = new uint[dwordCount];
int byteCountMinus1 = byteCount - 1;
// Copy all dwords, except but don't do the last one if it's not a full four bytes
int curDword, curByte = 3;
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
// Copy all dwords, except don't do the last one if it's not a full four bytes
int curDword, curByte;
if (isBigEndian)
{
for (int byteInDword = 0; byteInDword < 4; byteInDword++)
curByte = byteCount - sizeof(int);
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
curByte--;
for (int byteInDword = 0; byteInDword < 4; byteInDword++)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
curByte++;
}
curByte -= 8;
}
}
else
{
curByte = sizeof(int) - 1;
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
{
for (int byteInDword = 0; byteInDword < 4; byteInDword++)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
curByte--;
}
curByte += 8;
}
curByte += 8;
}
// Copy the last dword specially if it's not aligned
if (unalignedBytes != 0)
{
if (isNegative) val[dwordCount - 1] = 0xffffffff;
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
if (isNegative)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
val[dwordCount - 1] = 0xffffffff;
}
if (isBigEndian)
{
for (curByte = 0; curByte < unalignedBytes; curByte++)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
}
}
else
{
for (curByte = byteCountMinus1; curByte >= byteCount - unalignedBytes; curByte--)
{
byte curByteValue = value[curByte];
val[curDword] = (val[curDword] << 8) | curByteValue;
}
}
}
@@ -414,7 +481,6 @@ namespace System.Numerics
{
if (value == null)
throw new ArgumentNullException(nameof(value));
Contract.EndContractBlock();
int len;
@@ -624,7 +690,12 @@ namespace System.Numerics
return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider));
}
public static bool TryParse(ReadOnlySpan<char> value, out BigInteger result, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
public static bool TryParse(ReadOnlySpan<char> value, out BigInteger result)
{
return BigNumber.TryParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
}
public static bool TryParse(ReadOnlySpan<char> value, NumberStyles style, IFormatProvider provider, out BigInteger result)
{
return BigNumber.TryParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider), out result);
}
@@ -832,7 +903,6 @@ namespace System.Numerics
{
if (exponent.Sign < 0)
throw new ArgumentOutOfRangeException(nameof(exponent), SR.ArgumentOutOfRange_MustBeNonNeg);
Contract.EndContractBlock();
value.AssertValid();
exponent.AssertValid();
@@ -866,7 +936,6 @@ namespace System.Numerics
{
if (exponent < 0)
throw new ArgumentOutOfRangeException(nameof(exponent), SR.ArgumentOutOfRange_MustBeNonNeg);
Contract.EndContractBlock();
value.AssertValid();
@@ -1046,10 +1115,48 @@ namespace System.Numerics
/// return an array of one byte whose element is 0x00.
/// </summary>
/// <returns></returns>
public byte[] ToByteArray()
public byte[] ToByteArray() => ToByteArray(isUnsigned: false, isBigEndian: false);
/// <summary>
/// Returns the value of this BigInteger as a byte array using the fewest number of bytes possible.
/// If the value is zero, returns an array of one byte whose element is 0x00.
/// </summary>
/// <param name="isUnsigned">Whether or not an unsigned encoding is to be used</param>
/// <param name="isBigEndian">Whether or not to write the bytes in a big-endian byte order</param>
/// <returns></returns>
/// <exception cref="OverflowException">
/// If <paramref name="isUnsigned"/> is <c>true</c> and <see cref="Sign"/> is negative.
/// </exception>
/// <remarks>
/// The integer value <c>33022</c> can be exported as four different arrays.
///
/// <list type="bullet">
/// <item>
/// <description>
/// <c>(isUnsigned: false, isBigEndian: false)</c> => <c>new byte[] { 0xFE, 0x80, 0x00 }</c>
/// </description>
/// </item>
/// <item>
/// <description>
/// <c>(isUnsigned: false, isBigEndian: true)</c> => <c>new byte[] { 0x00, 0x80, 0xFE }</c>
/// </description>
/// </item>
/// <item>
/// <description>
/// <c>(isUnsigned: true, isBigEndian: false)</c> => <c>new byte[] { 0xFE, 0x80 }</c>
/// </description>
/// </item>
/// <item>
/// <description>
/// <c>(isUnsigned: true, isBigEndian: true)</c> => <c>new byte[] { 0x80, 0xFE }</c>
/// </description>
/// </item>
/// </list>
/// </remarks>
public byte[] ToByteArray(bool isUnsigned=false, bool isBigEndian=false)
{
int ignored = 0;
return TryGetBytes(GetBytesMode.AllocateArray, default(Span<byte>), ref ignored);
return TryGetBytes(GetBytesMode.AllocateArray, default, isUnsigned, isBigEndian, ref ignored);
}
/// <summary>
@@ -1059,42 +1166,61 @@ namespace System.Numerics
/// </summary>
/// <param name="destination">The destination span to which the resulting bytes should be written.</param>
/// <param name="bytesWritten">The number of bytes written to <paramref name="destination"/>.</param>
/// <param name="isUnsigned">Whether or not an unsigned encoding is to be used</param>
/// <param name="isBigEndian">Whether or not to write the bytes in a big-endian byte order</param>
/// <returns>true if the bytes fit in <see cref="destination"/>; false if not all bytes could be written due to lack of space.</returns>
public bool TryWriteBytes(Span<byte> destination, out int bytesWritten)
/// <exception cref="OverflowException">If <paramref name="isUnsigned"/> is <c>true</c> and <see cref="Sign"/> is negative.</exception>
public bool TryWriteBytes(Span<byte> destination, out int bytesWritten, bool isUnsigned=false, bool isBigEndian=false)
{
bytesWritten = 0;
return TryGetBytes(GetBytesMode.Span, destination, ref bytesWritten) != null;
if (TryGetBytes(GetBytesMode.Span, destination, isUnsigned, isBigEndian, ref bytesWritten) == null)
{
bytesWritten = 0;
return false;
}
return true;
}
/// <summary>Gets the number of bytes that will be output by <see cref="ToByteArray"/> and <see cref="TryWriteBytes(Span{byte}, out int)"/>.</summary>
internal bool TryWriteOrCountBytes(Span<byte> destination, out int bytesWritten, bool isUnsigned = false, bool isBigEndian = false)
{
bytesWritten = 0;
return TryGetBytes(GetBytesMode.Span, destination, isUnsigned, isBigEndian, ref bytesWritten) != null;
}
/// <summary>Gets the number of bytes that will be output by <see cref="ToByteArray(bool, bool)"/> and <see cref="TryWriteBytes(Span{byte}, out int, bool, bool)"/>.</summary>
/// <returns>The number of bytes.</returns>
public int GetByteCount()
public int GetByteCount(bool isUnsigned=false)
{
int count = 0;
TryGetBytes(GetBytesMode.Count, default(Span<byte>), ref count);
// Big or Little Endian doesn't matter for the byte count.
const bool IsBigEndian = false;
TryGetBytes(GetBytesMode.Count, default(Span<byte>), isUnsigned, IsBigEndian, ref count);
return count;
}
/// <summary>Mode used to enable sharing <see cref="TryGetBytes(GetBytesMode, Span{byte}, out byte[], out int)"/> for multiple purposes.</summary>
/// <summary>Mode used to enable sharing <see cref="TryGetBytes(GetBytesMode, Span{byte}, bool, bool, ref int)"/> for multiple purposes.</summary>
private enum GetBytesMode { AllocateArray, Count, Span }
/// <summary>Dummy array returned from TryGetBytes to indicate success when in span mode.</summary>
private static readonly byte[] s_success = Array.Empty<byte>();
/// <summary>Shared logic for <see cref="ToByteArray"/>, <see cref="TryWriteBytes(Span{byte}, out int)"/>, and <see cref="GetByteCount"/>.</summary>
/// <summary>Shared logic for <see cref="ToByteArray(bool, bool)"/>, <see cref="TryWriteBytes(Span{byte}, out int, bool, bool)"/>, and <see cref="GetByteCount"/>.</summary>
/// <param name="mode">Which entry point is being used.</param>
/// <param name="destination">The destination span, if mode is <see cref="GetBytesMode.Span"/>.</param>
/// <param name="isUnsigned">True to never write a padding byte, false to write it if the high bit is set.</param>
/// <param name="isBigEndian">True for big endian byte ordering, false for little endian byte ordering.</param>
/// <param name="bytesWritten">
/// If <paramref name="mode"/>==<see cref="GetBytesMode.AllocateArray"/>, ignored.
/// If <paramref name="mode"/>==<see cref="GetBytesMode.Count"/>, the number of bytes that would be written.
/// If <paramref name="mode"/>==<see cref="GetBytesMode.Span"/>, the number of bytes written to the span.
/// If <paramref name="mode"/>==<see cref="GetBytesMode.Span"/>, the number of bytes written to the span or that would be written if it were long enough.
/// </param>
/// <returns>
/// If <paramref name="mode"/>==<see cref="GetBytesMode.AllocateArray"/>, the result array.
/// If <paramref name="mode"/>==<see cref="GetBytesMode.Count"/>, null.
/// If <paramref name="mode"/>==<see cref="GetBytesMode.Span"/>, non-null if the span was long enough, null if there wasn't enough room.
/// </returns>
private byte[] TryGetBytes(GetBytesMode mode, Span<byte> destination, ref int bytesWritten)
/// <exception cref="OverflowException">If <paramref name="isUnsigned"/> is <c>true</c> and <see cref="Sign"/> is negative.</exception>
private byte[] TryGetBytes(GetBytesMode mode, Span<byte> destination, bool isUnsigned, bool isBigEndian, ref int bytesWritten)
{
Debug.Assert(mode == GetBytesMode.AllocateArray || mode == GetBytesMode.Count || mode == GetBytesMode.Span, $"Unexpected mode {mode}.");
Debug.Assert(mode == GetBytesMode.Span || destination.IsEmpty, $"If we're not in span mode, we shouldn't have been passed a destination.");
@@ -1110,16 +1236,21 @@ namespace System.Numerics
bytesWritten = 1;
return null;
default: // case GetBytesMode.Span:
bytesWritten = 1;
if (destination.Length != 0)
{
destination[0] = 0;
bytesWritten = 1;
return s_success;
}
return null;
}
}
if (isUnsigned && sign < 0)
{
throw new OverflowException(SR.Overflow_Negative_Unsigned);
}
byte highByte;
int nonZeroDwordIndex = 0;
uint highDword;
@@ -1185,7 +1316,7 @@ namespace System.Numerics
}
// Ensure high bit is 0 if positive, 1 if negative
bool needExtraByte = (msb & 0x80) != (highByte & 0x80);
bool needExtraByte = (msb & 0x80) != (highByte & 0x80) && !isUnsigned;
int length = msbIndex + 1 + (needExtraByte ? 1 : 0);
if (bits != null)
{
@@ -1202,16 +1333,18 @@ namespace System.Numerics
bytesWritten = length;
return null;
default: // case GetBytesMode.Span:
bytesWritten = length;
if (destination.Length < length)
{
return null;
}
bytesWritten = length;
array = s_success;
break;
}
int curByte = 0;
int curByte = isBigEndian ? length - 1 : 0;
int increment = isBigEndian ? -1 : 1;
if (bits != null)
{
for (int i = 0; i < bits.Length - 1; i++)
@@ -1227,10 +1360,14 @@ namespace System.Numerics
}
}
destination[curByte++] = unchecked((byte)dword);
destination[curByte++] = unchecked((byte)(dword >> 8));
destination[curByte++] = unchecked((byte)(dword >> 16));
destination[curByte++] = unchecked((byte)(dword >> 24));
destination[curByte] = unchecked((byte)dword);
curByte += increment;
destination[curByte] = unchecked((byte)(dword >> 8));
curByte += increment;
destination[curByte] = unchecked((byte)(dword >> 16));
curByte += increment;
destination[curByte] = unchecked((byte)(dword >> 24));
curByte += increment;
}
}
@@ -1238,21 +1375,29 @@ namespace System.Numerics
destination[curByte] = unchecked((byte)highDword);
if (msbIndex != 0)
{
destination[++curByte] = unchecked((byte)(highDword >> 8));
curByte += increment;
destination[curByte] = unchecked((byte)(highDword >> 8));
if (msbIndex != 1)
{
destination[++curByte] = unchecked((byte)(highDword >> 16));
curByte += increment;
destination[curByte] = unchecked((byte)(highDword >> 16));
if (msbIndex != 2)
{
destination[++curByte] = unchecked((byte)(highDword >> 24));
curByte += increment;
destination[curByte] = unchecked((byte)(highDword >> 24));
}
}
}
Debug.Assert((!needExtraByte && curByte == length - 1) || (needExtraByte && curByte == length - 2));
// Assert we're big endian, or little endian consistency holds.
Debug.Assert(isBigEndian || (!needExtraByte && curByte == length - 1) || (needExtraByte && curByte == length - 2));
// Assert we're little endian, or big endian consistency holds.
Debug.Assert(!isBigEndian || (!needExtraByte && curByte == 0) || (needExtraByte && curByte == 1));
if (needExtraByte)
{
destination[length - 1] = highByte;
curByte += increment;
destination[curByte] = highByte;
}
return array;
@@ -1325,6 +1470,11 @@ namespace System.Numerics
return BigNumber.FormatBigInteger(this, format, NumberFormatInfo.GetInstance(provider));
}
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null) // TODO: change format to ReadOnlySpan<char>
{
return BigNumber.TryFormatBigInteger(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
}
private static BigInteger Add(uint[] leftBits, int leftSign, uint[] rightBits, int rightSign)
{
bool trivialLeft = leftBits == null;

View File

@@ -35,7 +35,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
public static unsafe uint[] Add(uint[] left, uint[] right)
{
Debug.Assert(left != null);
@@ -57,7 +56,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
private static unsafe void Add(uint* left, int leftLength,
uint* right, int rightLength,
uint* bits, int bitsLength)
@@ -90,7 +88,6 @@ namespace System.Numerics
bits[i] = (uint)carry;
}
[SecuritySafeCritical]
private static unsafe void AddSelf(uint* left, int leftLength,
uint* right, int rightLength)
{
@@ -147,7 +144,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
public static unsafe uint[] Subtract(uint[] left, uint[] right)
{
Debug.Assert(left != null);
@@ -170,7 +166,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
private static unsafe void Subtract(uint* left, int leftLength,
uint* right, int rightLength,
uint* bits, int bitsLength)
@@ -205,7 +200,6 @@ namespace System.Numerics
Debug.Assert(carry == 0);
}
[SecuritySafeCritical]
private static unsafe void SubtractSelf(uint* left, int leftLength,
uint* right, int rightLength)
{
@@ -258,7 +252,6 @@ namespace System.Numerics
return 0;
}
[SecuritySafeCritical]
private static unsafe int Compare(uint* left, int leftLength,
uint* right, int rightLength)
{

View File

@@ -44,7 +44,6 @@ namespace System.Numerics
Array.Copy(value, 0, _bits, 0, _length);
}
[SecuritySafeCritical]
public unsafe void MultiplySelf(ref BitsBuffer value,
ref BitsBuffer temp)
{
@@ -73,7 +72,6 @@ namespace System.Numerics
Apply(ref temp, _length + value._length);
}
[SecuritySafeCritical]
public unsafe void SquareSelf(ref BitsBuffer temp)
{
Debug.Assert(temp._length == 0);
@@ -99,7 +97,6 @@ namespace System.Numerics
_length = reducer.Reduce(_bits, _length);
}
[SecuritySafeCritical]
public unsafe void Reduce(uint[] modulus)
{
Debug.Assert(modulus != null);
@@ -120,7 +117,6 @@ namespace System.Numerics
}
}
[SecuritySafeCritical]
public unsafe void Reduce(ref BitsBuffer modulus)
{
// Executes a modulo operation using the divide operation.

View File

@@ -72,7 +72,6 @@ namespace System.Numerics
return (uint)carry;
}
[SecuritySafeCritical]
public static unsafe uint[] Divide(uint[] left, uint[] right,
out uint[] remainder)
{
@@ -102,7 +101,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
public static unsafe uint[] Divide(uint[] left, uint[] right)
{
Debug.Assert(left != null);
@@ -128,7 +126,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
public static unsafe uint[] Remainder(uint[] left, uint[] right)
{
Debug.Assert(left != null);
@@ -153,7 +150,6 @@ namespace System.Numerics
return localLeft;
}
[SecuritySafeCritical]
private static unsafe void Divide(uint* left, int leftLength,
uint* right, int rightLength,
uint* bits, int bitsLength)
@@ -240,7 +236,6 @@ namespace System.Numerics
}
}
[SecuritySafeCritical]
private static unsafe uint AddDivisor(uint* left, int leftLength,
uint* right, int rightLength)
{
@@ -262,7 +257,6 @@ namespace System.Numerics
return (uint)carry;
}
[SecuritySafeCritical]
private static unsafe uint SubtractDivisor(uint* left, int leftLength,
uint* right, int rightLength,
ulong q)

View File

@@ -15,7 +15,7 @@ namespace System.Numerics
// see https://en.wikipedia.org/wiki/Barrett_reduction
internal struct FastReducer
internal readonly struct FastReducer
{
private readonly uint[] _modulus;
private readonly uint[] _mu;
@@ -66,7 +66,6 @@ namespace System.Numerics
_modulus, _modulus.Length + 1);
}
[SecuritySafeCritical]
private static unsafe int DivMul(uint[] left, int leftLength,
uint[] right, int rightLength,
uint[] bits, int k)
@@ -111,7 +110,6 @@ namespace System.Numerics
return 0;
}
[SecuritySafeCritical]
private static unsafe int SubMod(uint[] left, int leftLength,
uint[] right, int rightLength,
uint[] modulus, int k)

View File

@@ -9,7 +9,6 @@ namespace System.Numerics
{
internal static partial class BigIntegerCalculator
{
[SecuritySafeCritical]
public static unsafe uint[] Square(uint[] value)
{
Debug.Assert(value != null);
@@ -32,7 +31,6 @@ namespace System.Numerics
private static int SquareThreshold = 32;
private static int AllocationThreshold = 256;
[SecuritySafeCritical]
private static unsafe void Square(uint* value, int valueLength,
uint* bits, int bitsLength)
{
@@ -185,7 +183,6 @@ namespace System.Numerics
return bits;
}
[SecuritySafeCritical]
public static unsafe uint[] Multiply(uint[] left, uint[] right)
{
Debug.Assert(left != null);
@@ -210,7 +207,6 @@ namespace System.Numerics
// Mutable for unit testing...
private static int MultiplyThreshold = 32;
[SecuritySafeCritical]
private static unsafe void Multiply(uint* left, int leftLength,
uint* right, int rightLength,
uint* bits, int bitsLength)
@@ -358,7 +354,6 @@ namespace System.Numerics
}
}
[SecuritySafeCritical]
private static unsafe void SubtractCore(uint* left, int leftLength,
uint* right, int rightLength,
uint* core, int coreLength)

View File

@@ -271,9 +271,9 @@
// NaNs or Infinities.
//
using System.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.Security;
using System.Text;
namespace System.Numerics
@@ -322,7 +322,6 @@ namespace System.Numerics
return true;
}
[SecuritySafeCritical]
internal static bool TryParseBigInteger(string value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
{
if (value == null)
@@ -331,10 +330,9 @@ namespace System.Numerics
return false;
}
return TryParseBigInteger(AsReadOnlySpan(value), style, info, out result);
return TryParseBigInteger(value.AsReadOnlySpan(), style, info, out result);
}
[SecuritySafeCritical]
internal static bool TryParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
{
unsafe
@@ -373,18 +371,7 @@ namespace System.Numerics
throw new ArgumentNullException(nameof(value));
}
return ParseBigInteger(AsReadOnlySpan(value), style, info);
}
// TODO #22688: Remove this and replace it with the real AsReadOnlySpan extension
// method from System.Memory once the System.Memory package is marked stable
// and the package validation system allows us to take a dependency on it.
private static unsafe ReadOnlySpan<char> AsReadOnlySpan(string s)
{
fixed (char* c = s)
{
return new ReadOnlySpan<char>(c, s.Length);
}
return ParseBigInteger(value.AsReadOnlySpan(), style, info);
}
internal static BigInteger ParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info)
@@ -482,10 +469,10 @@ namespace System.Numerics
}
// This function is consistent with VM\COMNumber.cpp!COMNumber::ParseFormatSpecifier
internal static char ParseFormatSpecifier(string format, out int digits)
internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
{
digits = -1;
if (string.IsNullOrEmpty(format))
if (format.Length == 0)
{
return 'R';
}
@@ -516,13 +503,25 @@ namespace System.Numerics
return (char)0; // Custom format
}
private static string FormatBigIntegerToHexString(BigInteger value, char format, int digits, NumberFormatInfo info)
private static string FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span<char> destination, out int charsWritten, out bool spanSuccess)
{
StringBuilder sb = new StringBuilder();
byte[] bits = value.ToByteArray();
string fmt = null;
int cur = bits.Length - 1;
Debug.Assert(format == 'x' || format == 'X');
// Get the bytes that make up the BigInteger.
byte[] arrayToReturnToPool = null;
Span<byte> bits = stackalloc byte[64]; // arbitrary threshold
if (!value.TryWriteOrCountBytes(bits, out int bytesWrittenOrNeeded))
{
bits = arrayToReturnToPool = ArrayPool<byte>.Shared.Rent(bytesWrittenOrNeeded);
bool success = value.TryWriteBytes(bits, out bytesWrittenOrNeeded);
Debug.Assert(success);
}
bits = bits.Slice(0, bytesWrittenOrNeeded);
Span<char> stackSpace = stackalloc char[128]; // each byte is typically two chars
var sb = new ValueStringBuilder(stackSpace);
int cur = bits.Length - 1;
if (cur > -1)
{
// [FF..F8] drop the high F as the two's complement negative number remains clear
@@ -530,58 +529,109 @@ namespace System.Numerics
// [07..00] drop the high 0 as the two's complement positive number remains clear
bool clearHighF = false;
byte head = bits[cur];
if (head > 0xF7)
{
head -= 0xF0;
clearHighF = true;
}
if (head < 0x08 || clearHighF)
{
// {0xF8-0xFF} print as {8-F}
// {0x00-0x07} print as {0-7}
fmt = string.Format(CultureInfo.InvariantCulture, "{0}1", format);
sb.Append(head.ToString(fmt, info));
sb.Append(head < 10 ?
(char)(head + '0') :
format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a'));
cur--;
}
}
if (cur > -1)
{
fmt = string.Format(CultureInfo.InvariantCulture, "{0}2", format);
Span<char> chars = sb.AppendSpan((cur + 1) * 2);
int charsPos = 0;
string hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF";
while (cur > -1)
{
sb.Append(bits[cur--].ToString(fmt, info));
byte b = bits[cur--];
chars[charsPos++] = hexValues[b >> 4];
chars[charsPos++] = hexValues[b & 0xF];
}
}
if (digits > 0 && digits > sb.Length)
if (digits > sb.Length)
{
// Insert leading zeros. User specified "X5" so we create "0ABCD" instead of "ABCD"
sb.Insert(0, (value._sign >= 0 ? ("0") : (format == 'x' ? "f" : "F")), digits - sb.Length);
// Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD"
sb.Insert(
0,
value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F',
digits - sb.Length);
}
if (arrayToReturnToPool != null)
{
ArrayPool<byte>.Shared.Return(arrayToReturnToPool);
}
if (targetSpan)
{
spanSuccess = sb.TryCopyTo(destination, out charsWritten);
return null;
}
else
{
charsWritten = 0;
spanSuccess = false;
return sb.ToString();
}
return sb.ToString();
}
[SecuritySafeCritical]
internal static string FormatBigInteger(BigInteger value, string format, NumberFormatInfo info)
{
int digits = 0;
char fmt = ParseFormatSpecifier(format, out digits);
if (fmt == 'x' || fmt == 'X')
return FormatBigIntegerToHexString(value, fmt, digits, info);
return FormatBigInteger(targetSpan: false, value, format, format, info, default, out _, out _);
}
internal static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
{
FormatBigInteger(targetSpan: true, value, null, format, info, destination, out charsWritten, out bool spanSuccess);
return spanSuccess;
}
private static string FormatBigInteger(
bool targetSpan, BigInteger value,
string formatString, ReadOnlySpan<char> formatSpan,
NumberFormatInfo info, Span<char> destination, out int charsWritten, out bool spanSuccess)
{
Debug.Assert(formatString == null || formatString.Length == formatSpan.Length);
int digits = 0;
char fmt = ParseFormatSpecifier(formatSpan, out digits);
if (fmt == 'x' || fmt == 'X')
{
return FormatBigIntegerToHex(targetSpan, value, fmt, digits, info, destination, out charsWritten, out spanSuccess);
}
bool decimalFmt = (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R');
if (value._bits == null)
{
if (fmt == 'g' || fmt == 'G' || fmt == 'r' || fmt == 'R')
{
if (digits > 0)
format = string.Format(CultureInfo.InvariantCulture, "D{0}", digits.ToString(CultureInfo.InvariantCulture));
else
format = "D";
formatSpan = formatString = digits > 0 ? string.Format("D{0}", digits) : "D";
}
return value._sign.ToString(format, info);
}
if (targetSpan)
{
spanSuccess = value._sign.TryFormat(destination, out charsWritten, formatSpan, info);
return null;
}
else
{
charsWritten = 0;
spanSuccess = false;
return value._sign.ToString(formatString, info);
}
}
// First convert to base 10^9.
const uint kuBase = 1000000000; // 10^9
@@ -624,6 +674,7 @@ namespace System.Numerics
}
catch (OverflowException e) { throw new FormatException(SR.Format_TooLarge, e); }
bool decimalFmt = (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R');
if (decimalFmt)
{
if (digits > 0 && digits > cchMax)
@@ -677,7 +728,21 @@ namespace System.Numerics
int precision = 29;
int scale = cchMax - ichDst;
return FormatProvider.FormatBigInteger(precision, scale, sign, format, info, rgch, ichDst);
Span<char> stackSpace = stackalloc char[128]; // arbitrary stack cut-off
var sb = new ValueStringBuilder(stackSpace);
FormatProvider.FormatBigInteger(ref sb, precision, scale, sign, formatSpan, info, rgch, ichDst);
if (targetSpan)
{
spanSuccess = sb.TryCopyTo(destination, out charsWritten);
return null;
}
else
{
charsWritten = 0;
spanSuccess = false;
return sb.ToString();
}
}
// Format Round-trip decimal
@@ -699,7 +764,26 @@ namespace System.Numerics
for (int i = info.NegativeSign.Length - 1; i > -1; i--)
rgch[--ichDst] = info.NegativeSign[i];
}
return new string(rgch, ichDst, cchMax - ichDst);
int resultLength = cchMax - ichDst;
if (!targetSpan)
{
charsWritten = 0;
spanSuccess = false;
return new string(rgch, ichDst, cchMax - ichDst);
}
else if (new ReadOnlySpan<char>(rgch, ichDst, cchMax - ichDst).TryCopyTo(destination))
{
charsWritten = resultLength;
spanSuccess = true;
return null;
}
else
{
charsWritten = 0;
spanSuccess = false;
return null;
}
}
}
}

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
namespace System.Numerics
@@ -23,8 +22,6 @@ namespace System.Numerics
public static void GetDoubleParts(double dbl, out int sign, out int exp, out ulong man, out bool fFinite)
{
Contract.Ensures(Contract.ValueAtReturn(out sign) == +1 || Contract.ValueAtReturn(out sign) == -1);
DoubleUlong du;
du.uu = 0;
du.dbl = dbl;

View File

@@ -9,7 +9,7 @@ using Xunit;
namespace System.Numerics.Tests
{
public class ToStringTest
public partial class ToStringTest
{
private static bool s_noZeroOut = true;
@@ -100,10 +100,14 @@ namespace System.Numerics.Tests
RunStandardFormatToStringTests(s_random, "D", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 0, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "d0", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 0, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D1", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 1, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D0000001", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 1, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "d2", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 2, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D5", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 5, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "d33", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 33, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D99", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 99, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D\0", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 0, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D4\0", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 4, DecimalFormatter);
RunStandardFormatToStringTests(s_random, "D4\0Z", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 4, DecimalFormatter);
// Exponential (note: negative precision means lower case e)
RunStandardFormatToStringTests(s_random, "E", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 6, ExponentialFormatter);
@@ -180,7 +184,7 @@ namespace System.Numerics.Tests
VerifyToString(test, format, null, true, null);
}
}
[Fact]
public static void RunRegionSpecificStandardFormatToStringTests()
{
@@ -1418,37 +1422,42 @@ namespace System.Numerics.Tests
Assert.False(expectError, "Expected exception not encountered.");
if (expectedResult != result)
{
Assert.Equal(expectedResult.Length, result.Length);
int index = expectedResult.LastIndexOf("E", StringComparison.OrdinalIgnoreCase);
Assert.False(index == 0, "'E' found at beginning of expectedResult");
bool equal = false;
if (index > 0)
{
var dig1 = (byte)expectedResult[index - 1];
var dig2 = (byte)result[index - 1];
equal |= (dig2 == dig1 - 1 || dig2 == dig1 + 1);
equal |= (dig1 == '9' && dig2 == '0' || dig2 == '9' && dig1 == '0');
equal |= (index == 1 && (dig1 == '9' && dig2 == '1' || dig2 == '9' && dig1 == '1'));
}
Assert.True(equal);
}
else
{
Assert.Equal(expectedResult, result);
}
VerifyExpectedStringResult(expectedResult, result);
}
catch (Exception e)
catch (FormatException)
{
Assert.True(expectError && e.GetType() == typeof(FormatException), "Unexpected Exception:" + e);
Assert.True(expectError);
}
VerifyTryFormat(test, format, provider, expectError, expectedResult);
}
private static void VerifyExpectedStringResult(string expectedResult, string result)
{
if (expectedResult != result)
{
Assert.Equal(expectedResult.Length, result.Length);
int index = expectedResult.LastIndexOf("E", StringComparison.OrdinalIgnoreCase);
Assert.False(index == 0, "'E' found at beginning of expectedResult");
bool equal = false;
if (index > 0)
{
var dig1 = (byte)expectedResult[index - 1];
var dig2 = (byte)result[index - 1];
equal |= (dig2 == dig1 - 1 || dig2 == dig1 + 1);
equal |= (dig1 == '9' && dig2 == '0' || dig2 == '9' && dig1 == '0');
equal |= (index == 1 && (dig1 == '9' && dig2 == '1' || dig2 == '9' && dig1 == '1'));
}
Assert.True(equal);
}
}
static partial void VerifyTryFormat(string test, string format, IFormatProvider provider, bool expectError, string expectedResult);
private static String GetDigitSequence(int min, int max, Random random)
{
String result = String.Empty;

View File

@@ -0,0 +1,35 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Xunit;
namespace System.Numerics.Tests
{
public partial class ToStringTest
{
static partial void VerifyTryFormat(string test, string format, IFormatProvider provider, bool expectError, string expectedResult)
{
try
{
BigInteger bi = BigInteger.Parse(test, provider);
char[] destination = expectedResult != null ? new char[expectedResult.Length] : Array.Empty<char>();
Assert.True(bi.TryFormat(destination, out int charsWritten, format, provider));
Assert.False(expectError);
VerifyExpectedStringResult(expectedResult, new string(destination, 0, charsWritten));
if (expectedResult.Length > 0)
{
Assert.False(bi.TryFormat(new char[expectedResult.Length - 1], out charsWritten, format, provider));
Assert.Equal(0, charsWritten);
}
}
catch (FormatException)
{
Assert.True(expectError);
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,120 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Xunit;
namespace System.Numerics.Tests
{
public partial class ExtractBytesMembersTests
{
public static IEnumerable<object[]> FromIntTests_MemberData() =>
MatrixGenerator(FromIntTests_MemberDataSeed(), false);
[Theory]
[MemberData(nameof(FromIntTests_MemberData))]
public void ToByteArray_FromIntTests(int i, bool isUnsigned, bool isBigEndian, byte[] expectedBytes)
{
BigInteger bi = new BigInteger(i);
if (i < 0 && isUnsigned)
{
Assert.Throws<OverflowException>(() => bi.ToByteArray(isUnsigned, isBigEndian));
return;
}
byte[] bytes = bi.ToByteArray(isUnsigned, isBigEndian);
Assert.Equal(expectedBytes, bytes);
BigInteger bi2 = new BigInteger(bytes, isUnsigned, isBigEndian);
Assert.Equal(bi, bi2);
}
public static IEnumerable<object[]> FromLongTests_MemberData() =>
MatrixGenerator(FromLongTests_MemberDataSeed(), false);
[Theory]
[MemberData(nameof(FromLongTests_MemberData))]
public void ToByteArray_FromLongTests(long l, bool isUnsigned, bool isBigEndian, byte[] expectedBytes)
{
BigInteger bi = new BigInteger(l);
if (l < 0 && isUnsigned)
{
Assert.Throws<OverflowException>(() => bi.ToByteArray(isUnsigned, isBigEndian));
return;
}
byte[] bytes = bi.ToByteArray(isUnsigned, isBigEndian);
Assert.Equal(expectedBytes, bytes);
BigInteger bi2 = new BigInteger(bytes, isUnsigned, isBigEndian);
Assert.Equal(bi, bi2);
}
public static IEnumerable<object[]> FromStringTests_MemberData() =>
MatrixGenerator(FromStringTests_MemberDataSeed(), true);
[Theory]
public void ToByteArray_FromStringTests(string str, bool isUnsigned, bool isBigEndian, byte[] expectedBytes)
{
BigInteger bi = BigInteger.Parse(str);
if (str[0] == '-' && isUnsigned)
{
Assert.Throws<OverflowException>(() => bi.ToByteArray(isUnsigned, isBigEndian));
return;
}
byte[] bytes = bi.ToByteArray(isUnsigned, isBigEndian);
Assert.Equal(expectedBytes, bytes);
BigInteger bi2 = new BigInteger(bytes, isUnsigned, isBigEndian);
Assert.Equal(bi, bi2);
}
private static IEnumerable<object[]> MatrixGenerator(IEnumerable<object[]> seedData, bool dataIsBigEndian)
{
foreach (object[] seed in seedData)
{
object value = seed[0];
byte[] leSignedBytes = (byte[])seed[1];
byte[] beSignedBytes = (byte[])leSignedBytes.Clone();
Array.Reverse(beSignedBytes);
if (dataIsBigEndian)
{
var tmp = leSignedBytes;
leSignedBytes = beSignedBytes;
beSignedBytes = tmp;
}
// Signed Little Endian
yield return new object[] { value, false, false, leSignedBytes };
// Signed Big Endian
yield return new object[] { value, false, true, beSignedBytes };
byte[] leUnsignedBytes;
byte[] beUnsignedBytes;
if (beSignedBytes.Length > 1 &&
beSignedBytes[0] == 0)
{
leUnsignedBytes = new Span<byte>(leSignedBytes, 0, leSignedBytes.Length - 1).ToArray();
beUnsignedBytes = new Span<byte>(beSignedBytes, 1, beSignedBytes.Length - 1).ToArray();
}
else
{
// No padding was required, the unsigned data is the same as the signed data.
leUnsignedBytes = leSignedBytes;
beUnsignedBytes = beSignedBytes;
}
// Unsigned Big Endian
yield return new object[] { value, true, true, beUnsignedBytes };
// Unsigned Little Endian
yield return new object[] { value, true, false, leUnsignedBytes };
}
}
}
}

View File

@@ -10,29 +10,32 @@ namespace System.Numerics.Tests
{
[Theory]
[MemberData(nameof(FromIntTests_MemberData))]
public void TryWriteBytes_FromIntTests(int i, byte[] expectedBytes) =>
ValidateGetByteCountAndTryWriteBytes(new BigInteger(i), expectedBytes);
public void TryWriteBytes_FromIntTests(int i, bool isUnsigned, bool isBigEndian, byte[] expectedBytes) =>
ValidateGetByteCountAndTryWriteBytes(new BigInteger(i), isUnsigned, isBigEndian, expectedBytes);
[Theory]
[MemberData(nameof(FromLongTests_MemberData))]
public void TryWriteBytes_FromLongTests(long l, byte[] expectedBytes) =>
ValidateGetByteCountAndTryWriteBytes(new BigInteger(l), expectedBytes);
public void TryWriteBytes_FromLongTests(long l, bool isUnsigned, bool isBigEndian, byte[] expectedBytes) =>
ValidateGetByteCountAndTryWriteBytes(new BigInteger(l), isUnsigned, isBigEndian, expectedBytes);
[Theory]
[MemberData(nameof(FromStringTests_MemberData))]
public void TryWriteBytes_FromStringTests(string str, byte[] expectedBigEndianBytes)
{
byte[] expectedBytes = (byte[])expectedBigEndianBytes.Clone();
Array.Reverse(expectedBytes);
ValidateGetByteCountAndTryWriteBytes(BigInteger.Parse(str), expectedBytes);
}
public void TryWriteBytes_FromStringTests(string str, bool isUnsigned, bool isBigEndian, byte[] expectedBytes) =>
ValidateGetByteCountAndTryWriteBytes(BigInteger.Parse(str), isUnsigned, isBigEndian, expectedBytes);
private void ValidateGetByteCountAndTryWriteBytes(BigInteger bi, byte[] expectedBytes)
private void ValidateGetByteCountAndTryWriteBytes(BigInteger bi, bool isUnsigned, bool isBigEndian, byte[] expectedBytes)
{
byte[] bytes = bi.ToByteArray();
if (bi.Sign < 0 && isUnsigned)
{
Assert.Throws<OverflowException>(() => bi.GetByteCount(isUnsigned));
Assert.Throws<OverflowException>(() => bi.TryWriteBytes(Span<byte>.Empty, out _, isUnsigned, isBigEndian));
return;
}
byte[] bytes = bi.ToByteArray(isUnsigned, isBigEndian);
Assert.Equal(expectedBytes, bytes);
int count = bi.GetByteCount();
int count = bi.GetByteCount(isUnsigned);
Assert.Equal(expectedBytes.Length, count);
Validate(new byte[expectedBytes.Length]); // make sure it works with a span just long enough
@@ -42,11 +45,11 @@ namespace System.Numerics.Tests
{
// Fails if the span is too small
int bytesWritten;
Assert.False(bi.TryWriteBytes(destination.Slice(0, expectedBytes.Length - 1), out bytesWritten));
Assert.False(bi.TryWriteBytes(destination.Slice(0, expectedBytes.Length - 1), out bytesWritten, isUnsigned, isBigEndian));
Assert.Equal(0, bytesWritten);
// Succeeds if the span is sufficiently large
Assert.True(bi.TryWriteBytes(destination, out bytesWritten));
Assert.True(bi.TryWriteBytes(destination, out bytesWritten, isUnsigned, isBigEndian));
Assert.Equal(expectedBytes.Length, bytesWritten);
Assert.Equal<byte>(expectedBytes, destination.Slice(0, bytesWritten).ToArray());
}

View File

@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using Xunit;
namespace System.Numerics.Tests
@@ -16,13 +14,26 @@ namespace System.Numerics.Tests
if (failureNotExpected)
{
Eval(BigInteger.Parse(num1.AsReadOnlySpan(), ns), expected);
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, ns));
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, provider: null, out BigInteger test));
Eval(test, expected);
if (ns == NumberStyles.Integer)
{
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), out test));
Eval(test, expected);
}
}
else
{
Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), ns); });
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, ns), String.Format("Expected TryParse to fail on {0}", num1));
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, provider: null, out BigInteger test));
if (ns == NumberStyles.Integer)
{
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), out test));
}
}
}
@@ -31,13 +42,13 @@ namespace System.Numerics.Tests
if (!failureExpected)
{
Assert.Equal(expected, BigInteger.Parse(num1.AsReadOnlySpan(), provider: nfi));
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, NumberStyles.Any, nfi));
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test));
Assert.Equal(expected, test);
}
else
{
Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), provider: nfi); });
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, NumberStyles.Any, nfi), String.Format("Expected TryParse to fail on {0}", num1));
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
}
}
@@ -46,13 +57,13 @@ namespace System.Numerics.Tests
if (!failureExpected)
{
Assert.Equal(expected, BigInteger.Parse(num1.AsReadOnlySpan(), ns, nfi));
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, NumberStyles.Any, nfi));
Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test));
Assert.Equal(expected, test);
}
else
{
Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), ns, nfi); });
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), out BigInteger test, ns, nfi), String.Format("Expected TryParse to fail on {0}", num1));
Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
}
}
}

Some files were not shown because too many files have changed in this diff Show More