Changing Number.BigInteger and Number.NumberBuffer to directly use fixed-sized buffer...
authorTanner Gooding <tagoo@outlook.com>
Thu, 11 Oct 2018 21:25:40 +0000 (14:25 -0700)
committerGitHub <noreply@github.com>
Thu, 11 Oct 2018 21:25:40 +0000 (14:25 -0700)
* Moving Number.BigInteger to directly use a `fixed-sized buffer`

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

src/System.Private.CoreLib/shared/System/Number.BigInteger.cs
src/System.Private.CoreLib/shared/System/Number.Dragon4.cs
src/System.Private.CoreLib/shared/System/Number.Formatting.cs
src/System.Private.CoreLib/shared/System/Number.Grisu3.cs
src/System.Private.CoreLib/shared/System/Number.NumberBuffer.cs
src/System.Private.CoreLib/shared/System/Number.NumberToDouble.cs
src/System.Private.CoreLib/shared/System/Number.Parsing.cs

index 2629fe2..2599823 100644 (file)
@@ -130,7 +130,7 @@ namespace System
             };
 
             private int _length;
-            private BlocksBuffer _blocks;
+            private fixed uint _blocks[MaxBlockCount];
 
             public BigInteger(uint value)
             {
@@ -367,7 +367,7 @@ namespace System
                 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;
@@ -559,7 +559,7 @@ namespace System
                     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;
             }
@@ -585,7 +585,7 @@ namespace System
                 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;
             }
 
@@ -638,7 +638,7 @@ namespace System
             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;
             }
 
@@ -678,7 +678,7 @@ namespace System
                     _length += (int)(blocksToShift);
 
                     // Zero the remaining low blocks
-                    Buffer.ZeroMemory((byte*)(_blocks.GetPointer()), (blocksToShift * sizeof(uint)));
+                    Buffer.ZeroMemory((byte*)(GetBlocksPointer()), (blocksToShift * sizeof(uint)));
                 }
                 else
                 {
@@ -711,7 +711,7 @@ namespace System
                     _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)
@@ -721,30 +721,10 @@ namespace System
                 }
             }
 
-            [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]));
             }
         }
     }
index ec2ae16..3edefe3 100644 (file)
@@ -204,7 +204,7 @@ namespace System
             }
             else
             {
-                char* pCurrentDigit = (number.digits + digitsNum);
+                char* pCurrentDigit = (number.GetDigitsPointer() + digitsNum);
 
                 // Rounding up for 9 is special.
                 if (currentDigit == 9)
@@ -213,7 +213,7 @@ namespace System
                     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';
index ed0fdb6..51ecee3 100644 (file)
@@ -339,7 +339,7 @@ namespace System
 
         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;
@@ -354,7 +354,7 @@ namespace System
             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++;
@@ -947,14 +947,14 @@ namespace System
                 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';
@@ -1065,13 +1065,13 @@ namespace System
             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';
@@ -1181,7 +1181,7 @@ namespace System
                 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);
@@ -1191,7 +1191,7 @@ namespace System
             number.scale = i;
             number.kind = NumberBufferKind.Integer;
 
-            char* dst = number.digits;
+            char* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
             *dst = '\0';
@@ -1322,7 +1322,7 @@ namespace System
             number.precision = UInt64Precision;
             number.sign = false;
 
-            char* buffer = number.digits;
+            char* buffer = number.GetDigitsPointer();
             char* p = buffer + UInt64Precision;
 
             while (High32(value) != 0)
@@ -1333,7 +1333,7 @@ namespace System
             number.scale = i;
             number.kind = NumberBufferKind.Integer;
 
-            char* dst = number.digits;
+            char* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
             *dst = '\0';
@@ -1591,7 +1591,7 @@ SkipRounding:
 
             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);
@@ -1963,7 +1963,7 @@ SkipRounding:
         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)
             {
@@ -2087,7 +2087,7 @@ SkipRounding:
 
         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');
 
@@ -2137,7 +2137,7 @@ SkipRounding:
                 }
             }
 
-            char* dig = number.digits;
+            char* dig = number.GetDigitsPointer();
 
             if (digPos > 0)
             {
@@ -2197,7 +2197,7 @@ SkipRounding:
 
         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)
index 7d991a6..60d629a 100644 (file)
@@ -366,7 +366,7 @@ namespace System
 
                 // 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)
                 {
index c4d5ba5..b5ed19b 100644 (file)
@@ -19,22 +19,20 @@ namespace System
         [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,
index 4e4c5bc..2df2b2a 100644 (file)
@@ -314,7 +314,7 @@ namespace System
             }
 #endif
 
-            char* src = number.digits;
+            char* src = number.GetDigitsPointer();
             int total = GetLength(src);
             int remaining = total;
 
index 4882f60..2f25e76 100644 (file)
@@ -59,7 +59,7 @@ namespace System
             {
                 return false;
             }
-            char* p = number.digits;
+            char* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             int n = 0;
             while (--i >= 0)
@@ -100,7 +100,7 @@ namespace System
             {
                 return false;
             }
-            char* p = number.digits;
+            char* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             long n = 0;
             while (--i >= 0)
@@ -141,7 +141,7 @@ namespace System
             {
                 return false;
             }
-            char* p = number.digits;
+            char* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             uint n = 0;
             while (--i >= 0)
@@ -173,7 +173,7 @@ namespace System
             {
                 return false;
             }
-            char* p = number.digits;
+            char* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             ulong n = 0;
             while (--i >= 0)
@@ -1468,7 +1468,7 @@ namespace System
 
         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;