};
private int _length;
- private BlocksBuffer _blocks;
+ private fixed uint _blocks[MaxBlockCount];
public BigInteger(uint value)
{
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;
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;
}
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;
}
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;
}
_length += (int)(blocksToShift);
// Zero the remaining low blocks
- Buffer.ZeroMemory((byte*)(_blocks.GetPointer()), (blocksToShift * sizeof(uint)));
+ Buffer.ZeroMemory((byte*)(GetBlocksPointer()), (blocksToShift * sizeof(uint)));
}
else
{
_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)
}
}
- [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]));
}
}
}
}
else
{
- char* pCurrentDigit = (number.digits + digitsNum);
+ char* pCurrentDigit = (number.GetDigitsPointer() + digitsNum);
// Rounding up for 9 is special.
if (currentDigit == 9)
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';
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;
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++;
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';
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';
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);
number.scale = i;
number.kind = NumberBufferKind.Integer;
- char* dst = number.digits;
+ char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
number.precision = UInt64Precision;
number.sign = false;
- char* buffer = number.digits;
+ char* buffer = number.GetDigitsPointer();
char* p = buffer + UInt64Precision;
while (High32(value) != 0)
number.scale = i;
number.kind = NumberBufferKind.Integer;
- char* dst = number.digits;
+ char* dst = number.GetDigitsPointer();
while (--i >= 0)
*dst++ = *p++;
*dst = '\0';
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);
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)
{
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');
}
}
- char* dig = number.digits;
+ char* dig = number.GetDigitsPointer();
if (digPos > 0)
{
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)
// 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)
{
[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,
}
#endif
- char* src = number.digits;
+ char* src = number.GetDigitsPointer();
int total = GetLength(src);
int remaining = total;
{
return false;
}
- char* p = number.digits;
+ char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
int n = 0;
while (--i >= 0)
{
return false;
}
- char* p = number.digits;
+ char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
long n = 0;
while (--i >= 0)
{
return false;
}
- char* p = number.digits;
+ char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
uint n = 0;
while (--i >= 0)
{
return false;
}
- char* p = number.digits;
+ char* p = number.GetDigitsPointer();
Debug.Assert(p != null);
ulong n = 0;
while (--i >= 0)
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;