// m_data1 = *pInt++; // lo part
// m_data2 = *pInt++; // mid part
- int[] bits = decimal.GetBits(value);
+ Span<int> bits = stackalloc int[4];
+ decimal.GetBits(value, bits);
uint sgnscl;
unchecked
private static void EmitDecimal(this ILGenerator il, decimal value)
{
- int[] bits = decimal.GetBits(value);
+ Span<int> bits = stackalloc int[4];
+ decimal.GetBits(value, bits);
+
int scale = (bits[3] & int.MaxValue) >> 16;
if (scale == 0)
{
<value>Combination of arguments to the DateTime constructor is out of the legal range.</value>
</data>
<data name="Arg_DecBitCtor" xml:space="preserve">
- <value>Decimal byte array constructor requires an array of length four containing valid decimal bytes.</value>
+ <value>Decimal constructor requires an array or span of four valid decimal bytes.</value>
</data>
<data name="Arg_DirectoryNotFoundException" xml:space="preserve">
<value>Attempted to access a path that is not on the disk.</value>
// The possible binary representations of a particular value are all
// equally valid, and all are numerically equivalent.
//
- public Decimal(int[] bits)
+ public Decimal(int[] bits) :
+ this((ReadOnlySpan<int>)(bits ?? throw new ArgumentNullException(nameof(bits))))
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="decimal"/> to a decimal value represented in binary and contained in the specified span.
+ /// </summary>
+ /// <param name="bits">A span of four <see cref="int"/>s containing a binary representation of a decimal value.</param>
+ /// <exception cref="ArgumentException">The length of <paramref name="bits"/> is not 4, or the representation of the decimal value in <paramref name="bits"/> is not valid.</exception>
+ public Decimal(ReadOnlySpan<int> bits)
{
- if (bits == null)
- throw new ArgumentNullException(nameof(bits));
if (bits.Length == 4)
{
int f = bits[3];
return new int[] { d.lo, d.mid, d.hi, d.flags };
}
+ /// <summary>
+ /// Converts the value of a specified instance of <see cref="decimal"/> to its equivalent binary representation.
+ /// </summary>
+ /// <param name="d">The value to convert.</param>
+ /// <param name="destination">The span into which to store the four-integer binary representation.</param>
+ /// <returns>Four, the number of integers in the binary representation.</returns>
+ /// <exception cref="ArgumentException">The destination span was not long enough to store the binary representation.</exception>
+ public static int GetBits(decimal d, Span<int> destination)
+ {
+ if ((uint)destination.Length <= 3)
+ {
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+
+ destination[0] = d.lo;
+ destination[1] = d.mid;
+ destination[2] = d.hi;
+ destination[3] = d.flags;
+ return 4;
+ }
+
+ /// <summary>
+ /// Tries to convert the value of a specified instance of <see cref="decimal"/> to its equivalent binary representation.
+ /// </summary>
+ /// <param name="d">The value to convert.</param>
+ /// <param name="destination">The span into which to store the binary representation.</param>
+ /// <param name="valuesWritten">The number of integers written to the destination.</param>
+ /// <returns>true if the decimal's binary representation was written to the destination; false if the destination wasn't long enough.</returns>
+ public static bool TryGetBits(decimal d, Span<int> destination, out int valuesWritten)
+ {
+ if ((uint)destination.Length <= 3)
+ {
+ valuesWritten = 0;
+ return false;
+ }
+
+ destination[0] = d.lo;
+ destination[1] = d.mid;
+ destination[2] = d.hi;
+ destination[3] = d.flags;
+ valuesWritten = 4;
+ return true;
+ }
+
internal static void GetBytes(in decimal d, byte[] buffer)
{
Debug.Assert(buffer != null && buffer.Length >= 16, "[GetBytes]buffer != null && buffer.Length >= 16");
{
public static int GetScale(this decimal value)
{
+#if NETCOREAPP
+ Span<int> bits = stackalloc int[4];
+ decimal.GetBits(value, bits);
+ return unchecked((byte)(bits[3] >> 16));
+#else
return unchecked((byte)(decimal.GetBits(value)[3] >> 16));
+#endif
}
public static void GetBits(this decimal value, out bool isNegative, out byte scale, out uint low, out uint mid, out uint high)
{
+#if NETCOREAPP
+ Span<int> bits = stackalloc int[4];
+ decimal.GetBits(value, bits);
+#else
int[] bits = decimal.GetBits(value);
+#endif
// The return value is a four-element array of 32-bit signed integers.
// The first, second, and third elements of the returned array contain the low, middle, and high 32 bits of the 96-bit integer number.
public BigInteger(decimal value)
{
// First truncate to get scale to 0 and extract bits
- int[] bits = decimal.GetBits(decimal.Truncate(value));
+ Span<int> bits = stackalloc int[4];
+ decimal.GetBits(decimal.Truncate(value), bits);
Debug.Assert(bits.Length == 4 && (bits[3] & DecimalScaleFactorMask) == 0);
public Decimal(int value) { throw null; }
public Decimal(int lo, int mid, int hi, bool isNegative, byte scale) { throw null; }
public Decimal(int[] bits) { throw null; }
+ public Decimal(System.ReadOnlySpan<int> bits) { throw null; }
public Decimal(long value) { throw null; }
public Decimal(float value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static System.Decimal Floor(System.Decimal d) { throw null; }
public static System.Decimal FromOACurrency(long cy) { throw null; }
public static int[] GetBits(System.Decimal d) { throw null; }
+ public static int GetBits(System.Decimal d, System.Span<int> destination) { throw null; }
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
public static System.Decimal Multiply(System.Decimal d1, System.Decimal d2) { throw null; }
public static ulong ToUInt64(System.Decimal d) { throw null; }
public static System.Decimal Truncate(System.Decimal d) { 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 TryGetBits(System.Decimal d, System.Span<int> destination, out int valuesWritten) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Decimal result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Decimal result) { throw null; }
public static bool TryParse(string? s, out System.Decimal result) { throw null; }
Assert.Equal(expected, new decimal(value));
}
+ [Theory]
+ [MemberData(nameof(Ctor_IntArray_TestData))]
+ public void Ctor_IntSpan(int[] value, decimal expected)
+ {
+ Assert.Equal(expected, new decimal(value.AsSpan()));
+ }
+
[Fact]
public void Ctor_NullBits_ThrowsArgumentNullException()
{
public void Ctor_InvalidBits_ThrowsArgumentException(int[] bits)
{
AssertExtensions.Throws<ArgumentException>(null, () => new decimal(bits));
+ AssertExtensions.Throws<ArgumentException>(null, () => new decimal(bits.AsSpan()));
}
[Theory]
Assert.Equal(input, newValue);
}
+ [Theory]
+ [MemberData(nameof(GetBits_TestData))]
+ public static void GetBitsSpan(decimal input, int[] expected)
+ {
+ Span<int> bits = new int[4];
+ int bitsWritten = decimal.GetBits(input, bits);
+
+ Assert.Equal(4, bitsWritten);
+ Assert.Equal(expected, bits.ToArray());
+
+ bool sign = (bits[3] & 0x80000000) != 0;
+ byte scale = (byte)((bits[3] >> 16) & 0x7F);
+ decimal newValue = new decimal(bits[0], bits[1], bits[2], sign, scale);
+
+ Assert.Equal(input, newValue);
+ }
+
+ [Fact]
+ public static void GetBitsSpan_TooShort_ThrowsArgumentException()
+ {
+ AssertExtensions.Throws<ArgumentException>("destination", () => decimal.GetBits(123, new int[3]));
+ }
+
+ [Theory]
+ [MemberData(nameof(GetBits_TestData))]
+ public static void TryGetBits(decimal input, int[] expected)
+ {
+ Span<int> bits;
+ int valuesWritten;
+
+ bits = new int[3] { 42, 43, 44 };
+ Assert.False(decimal.TryGetBits(input, bits, out valuesWritten));
+ Assert.Equal(0, valuesWritten);
+ Assert.Equal(new int[3] { 42, 43, 44 }, bits.ToArray());
+
+ bits = new int[4];
+ Assert.True(decimal.TryGetBits(input, bits, out valuesWritten));
+ Assert.Equal(4, valuesWritten);
+ Assert.Equal(expected, bits.ToArray());
+
+ bits = new int[5];
+ bits[4] = 42;
+ Assert.True(decimal.TryGetBits(input, bits, out valuesWritten));
+ Assert.Equal(4, valuesWritten);
+ Assert.Equal(expected, bits.Slice(0, 4).ToArray());
+ Assert.Equal(42, bits[4]);
+ }
+
[Fact]
public void GetTypeCode_Invoke_ReturnsDecimal()
{