Skip to content

Commit

Permalink
Changing Number.BigInteger and Number.NumberBuffer to directly use fi…
Browse files Browse the repository at this point in the history
…xed-sized buffers (dotnet#20371)

* Moving Number.BigInteger to directly use a `fixed-sized buffer`

* Moving Number.NumberBuffer to directly use a `fixed-sized buffer`
  • Loading branch information
tannergooding authored Oct 11, 2018
1 parent 3792728 commit a8e724d
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 68 deletions.
40 changes: 10 additions & 30 deletions src/System.Private.CoreLib/shared/System/Number.BigInteger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ internal unsafe ref struct BigInteger
};

private int _length;
private BlocksBuffer _blocks;
private fixed uint _blocks[MaxBlockCount];

public BigInteger(uint value)
{
Expand Down Expand Up @@ -367,7 +367,7 @@ public static void Multiply(ref BigInteger lhs, ref BigInteger rhs, ref BigInteg
Debug.Assert(unchecked((uint)(maxResultLength)) <= MaxBlockCount);

// Zero out result internal blocks.
Buffer.ZeroMemory((byte*)(result._blocks.GetPointer()), (maxResultLength * sizeof(uint)));
Buffer.ZeroMemory((byte*)(result.GetBlocksPointer()), (maxResultLength * sizeof(uint)));

int smallIndex = 0;
int resultStartIndex = 0;
Expand Down Expand Up @@ -559,7 +559,7 @@ public void ExtendBlocks(uint blockValue, uint blockCount)
return;
}

Buffer.ZeroMemory((byte*)(_blocks.GetPointer() + _length), ((blockCount - 1) * sizeof(uint)));
Buffer.ZeroMemory((byte*)(GetBlocksPointer() + _length), ((blockCount - 1) * sizeof(uint)));
_length += (int)(blockCount);
_blocks[_length - 1] = blockValue;
}
Expand All @@ -585,7 +585,7 @@ public void Multiply(ref BigInteger value)
var result = new BigInteger(0);
Multiply(ref this, ref value, ref result);

Buffer.Memcpy((byte*)(_blocks.GetPointer()), (byte*)(result._blocks.GetPointer()), (result._length) * sizeof(uint));
Buffer.Memcpy((byte*)(GetBlocksPointer()), (byte*)(result.GetBlocksPointer()), (result._length) * sizeof(uint));
_length = result._length;
}

Expand Down Expand Up @@ -638,7 +638,7 @@ public void SetUInt64(ulong value)
public void SetValue(ref BigInteger rhs)
{
int rhsLength = rhs._length;
Buffer.Memcpy((byte*)(_blocks.GetPointer()), (byte*)(rhs._blocks.GetPointer()), (rhsLength * sizeof(uint)));
Buffer.Memcpy((byte*)(GetBlocksPointer()), (byte*)(rhs.GetBlocksPointer()), (rhsLength * sizeof(uint)));
_length = rhsLength;
}

Expand Down Expand Up @@ -678,7 +678,7 @@ public void ShiftLeft(uint shift)
_length += (int)(blocksToShift);

// Zero the remaining low blocks
Buffer.ZeroMemory((byte*)(_blocks.GetPointer()), (blocksToShift * sizeof(uint)));
Buffer.ZeroMemory((byte*)(GetBlocksPointer()), (blocksToShift * sizeof(uint)));
}
else
{
Expand Down Expand Up @@ -711,7 +711,7 @@ public void ShiftLeft(uint shift)
_blocks[writeIndex - 1] = block << (int)(remainingBitsToShift);

// Zero the remaining low blocks
Buffer.ZeroMemory((byte*)(_blocks.GetPointer()), (blocksToShift * sizeof(uint)));
Buffer.ZeroMemory((byte*)(GetBlocksPointer()), (blocksToShift * sizeof(uint)));

// Check if the terminating block has no set bits
if (_blocks[_length - 1] == 0)
Expand All @@ -721,30 +721,10 @@ public void ShiftLeft(uint shift)
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct BlocksBuffer
private uint* GetBlocksPointer()
{
private fixed uint _blocks[MaxBlockCount];

public ref uint this[int index]
{
get
{
Debug.Assert(unchecked((uint)(index)) <= MaxBlockCount);
return ref Unsafe.Add(ref GetPinnableReference(), index);
}
}

public ref uint GetPinnableReference()
{
var pThis = Unsafe.AsPointer(ref this);
return ref Unsafe.AsRef<uint>(pThis);
}

public uint* GetPointer()
{
return (uint*)(Unsafe.AsPointer(ref this));
}
// This is safe to do since we are a ref struct
return (uint*)(Unsafe.AsPointer(ref _blocks[0]));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Number.Dragon4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ private static unsafe void Dragon4(double value, int precision, ref NumberBuffer
}
else
{
char* pCurrentDigit = (number.digits + digitsNum);
char* pCurrentDigit = (number.GetDigitsPointer() + digitsNum);

// Rounding up for 9 is special.
if (currentDigit == 9)
Expand All @@ -213,7 +213,7 @@ private static unsafe void Dragon4(double value, int precision, ref NumberBuffer
while (true)
{
// If we are at the first digit
if (pCurrentDigit == number.digits)
if (pCurrentDigit == number.GetDigitsPointer())
{
// Output 1 at the next highest exponent
*pCurrentDigit = '1';
Expand Down
30 changes: 15 additions & 15 deletions src/System.Private.CoreLib/shared/System/Number.Formatting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ public static bool TryFormatDecimal(decimal value, ReadOnlySpan<char> format, Nu

private static unsafe void DecimalToNumber(ref decimal d, ref NumberBuffer number)
{
char* buffer = number.digits;
char* buffer = number.GetDigitsPointer();
number.precision = DecimalPrecision;
number.sign = d.IsNegative;
number.kind = NumberBufferKind.Decimal;
Expand All @@ -354,7 +354,7 @@ private static unsafe void DecimalToNumber(ref decimal d, ref NumberBuffer numbe
int i = (int)((byte*)(buffer + DecimalPrecision) - (byte*)p) >> 1;
number.scale = i - d.Scale;

char* dst = number.digits;
char* dst = number.GetDigitsPointer();
while (--i >= 0)
{
*dst++ = *p++;
Expand Down Expand Up @@ -947,14 +947,14 @@ private static unsafe void Int32ToNumber(int value, ref NumberBuffer number)
value = -value;
}

char* buffer = number.digits;
char* buffer = number.GetDigitsPointer();
char* p = UInt32ToDecChars(buffer + Int32Precision, (uint)value, 0);
int i = (int)(buffer + Int32Precision - p);

number.scale = i;
number.kind = NumberBufferKind.Integer;

char* dst = number.digits;
char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
Expand Down Expand Up @@ -1065,13 +1065,13 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number)
number.precision = UInt32Precision;
number.sign = false;

char* buffer = number.digits;
char* buffer = number.GetDigitsPointer();
char* p = UInt32ToDecChars(buffer + UInt32Precision, value, 0);
int i = (int)(buffer + UInt32Precision - p);
number.scale = i;
number.kind = NumberBufferKind.Integer;

char* dst = number.digits;
char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
Expand Down Expand Up @@ -1181,7 +1181,7 @@ private static unsafe void Int64ToNumber(long input, ref NumberBuffer number)
value = (ulong)(-input);
}

char* buffer = number.digits;
char* buffer = number.GetDigitsPointer();
char* p = buffer + Int64Precision;
while (High32(value) != 0)
p = UInt32ToDecChars(p, Int64DivMod1E9(ref value), 9);
Expand All @@ -1191,7 +1191,7 @@ private static unsafe void Int64ToNumber(long input, ref NumberBuffer number)
number.scale = i;
number.kind = NumberBufferKind.Integer;

char* dst = number.digits;
char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
Expand Down Expand Up @@ -1322,7 +1322,7 @@ private static unsafe void UInt64ToNumber(ulong value, ref NumberBuffer number)
number.precision = UInt64Precision;
number.sign = false;

char* buffer = number.digits;
char* buffer = number.GetDigitsPointer();
char* p = buffer + UInt64Precision;

while (High32(value) != 0)
Expand All @@ -1333,7 +1333,7 @@ private static unsafe void UInt64ToNumber(ulong value, ref NumberBuffer number)
number.scale = i;
number.kind = NumberBufferKind.Integer;

char* dst = number.digits;
char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
Expand Down Expand Up @@ -1591,7 +1591,7 @@ internal static unsafe void NumberToStringFormat(ref ValueStringBuilder sb, ref

int section;
int src;
char* dig = number.digits;
char* dig = number.GetDigitsPointer();
char ch;

section = FindSection(format, dig[0] == 0 ? 2 : number.sign ? 1 : 0);
Expand Down Expand Up @@ -1963,7 +1963,7 @@ private static void FormatCurrency(ref ValueStringBuilder sb, ref NumberBuffer n
private static unsafe void FormatFixed(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup)
{
int digPos = number.scale;
char* dig = number.digits;
char* dig = number.GetDigitsPointer();

if (digPos > 0)
{
Expand Down Expand Up @@ -2087,7 +2087,7 @@ private static void FormatNumber(ref ValueStringBuilder sb, ref NumberBuffer num

private static unsafe void FormatScientific(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, char expChar)
{
char* dig = number.digits;
char* dig = number.GetDigitsPointer();

sb.Append((*dig != 0) ? *dig++ : '0');

Expand Down Expand Up @@ -2137,7 +2137,7 @@ private static unsafe void FormatGeneral(ref ValueStringBuilder sb, ref NumberBu
}
}

char* dig = number.digits;
char* dig = number.GetDigitsPointer();

if (digPos > 0)
{
Expand Down Expand Up @@ -2197,7 +2197,7 @@ private static void FormatPercent(ref ValueStringBuilder sb, ref NumberBuffer nu

private static unsafe void RoundNumber(ref NumberBuffer number, int pos)
{
char* dig = number.digits;
char* dig = number.GetDigitsPointer();

int i = 0;
while (i < pos && dig[i] != 0)
Expand Down
2 changes: 1 addition & 1 deletion src/System.Private.CoreLib/shared/System/Number.Grisu3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ public static bool Run(double value, int precision, ref NumberBuffer number)

// Step 4: Generate digits.

bool isSuccess = DigitGen(ref D, precision, number.digits, out int length, out int kappa);
bool isSuccess = DigitGen(ref D, precision, number.GetDigitsPointer(), out int length, out int kappa);

if (isSuccess)
{
Expand Down
26 changes: 12 additions & 14 deletions src/System.Private.CoreLib/shared/System/Number.NumberBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,20 @@ internal static partial class Number
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal unsafe ref struct NumberBuffer
{
public int precision; // 0
public int scale; // 4
private int _sign; // 8
private NumberBufferKind _kind; // 12
private char* _allDigits; // 16
private DigitsAndNullTerminator _digits; // 20 or 24

public bool sign { get => _sign != 0; set => _sign = value ? 1 : 0; }
public char* digits => (char*)Unsafe.AsPointer(ref _digits);
public NumberBufferKind kind { get => _kind; set => _kind = value; }

[StructLayout(LayoutKind.Sequential, Size = (NumberMaxDigits + 1) * sizeof(char))]
private struct DigitsAndNullTerminator { }
public int precision;
public int scale;
public bool sign;
public NumberBufferKind kind;
public fixed char digits[NumberMaxDigits + 1];

public char* GetDigitsPointer()
{
// This is safe to do since we are a ref struct
return (char*)(Unsafe.AsPointer(ref digits[0]));
}
}

internal enum NumberBufferKind
internal enum NumberBufferKind : byte
{
Unknown = 0,
Integer = 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ private static double NumberToDouble(ref NumberBuffer number)
}
#endif

char* src = number.digits;
char* src = number.GetDigitsPointer();
int total = GetLength(src);
int remaining = total;

Expand Down
10 changes: 5 additions & 5 deletions src/System.Private.CoreLib/shared/System/Number.Parsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static unsafe bool NumberToInt32(ref NumberBuffer number, ref int value)
{
return false;
}
char* p = number.digits;
char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
int n = 0;
while (--i >= 0)
Expand Down Expand Up @@ -100,7 +100,7 @@ private static unsafe bool NumberToInt64(ref NumberBuffer number, ref long value
{
return false;
}
char* p = number.digits;
char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
long n = 0;
while (--i >= 0)
Expand Down Expand Up @@ -141,7 +141,7 @@ private static unsafe bool NumberToUInt32(ref NumberBuffer number, ref uint valu
{
return false;
}
char* p = number.digits;
char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
uint n = 0;
while (--i >= 0)
Expand Down Expand Up @@ -173,7 +173,7 @@ private static unsafe bool NumberToUInt64(ref NumberBuffer number, ref ulong val
{
return false;
}
char* p = number.digits;
char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
ulong n = 0;
while (--i >= 0)
Expand Down Expand Up @@ -1468,7 +1468,7 @@ internal static decimal ParseDecimal(ReadOnlySpan<char> value, NumberStyles styl

private static unsafe bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value)
{
char* p = number.digits;
char* p = number.GetDigitsPointer();
int e = number.scale;
bool sign = number.sign;
uint c = *p;
Expand Down

0 comments on commit a8e724d

Please sign in to comment.