Summary

Class:System.NumberBuffer
Assembly:System.Memory
File(s):C:\GitHub\corefx\src\System.Memory\src\System\Number\Number.NumberBuffer.cs
Covered lines:15
Uncovered lines:18
Coverable lines:33
Total lines:158
Line coverage:45.4%
Branch coverage:37.5%

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
CheckConsistency()4410080
ToString()3400

File(s)

C:\GitHub\corefx\src\System.Memory\src\System\Number\Number.NumberBuffer.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System.Diagnostics;
 6using System.Text;
 7using System.Runtime.InteropServices;
 8
 9#if !netstandard
 10using Internal.Runtime.CompilerServices;
 11#else
 12using System.Runtime.CompilerServices;
 13#endif
 14
 15namespace System
 16{
 17    //
 18    // This is a port of the Number/NumberBuffer structure from CoreRT (which in turn was a C#-ized port of the NUMBER s
 19    // We use this as the more heavyweight data types such as Decimal and floats. That is, we use Number as a common rep
 20    // and thus share the formatting/parsing routines among them.
 21    //
 22    // This structure can only be stack-allocated as it returns a reference to a fixed-length array inside.
 23    //
 24    [StructLayout(LayoutKind.Sequential)]
 25    internal ref struct NumberBuffer
 26    {
 27        // The Scale is the index of the implied decimal point. Can be negative or beyond the end of the NUL terminator.
 28        //
 29        //    123.45        => "12345", Scale = 3
 30        //    0.005         => "5", Scale = -2
 31        //    1000.00       => "1", Scale = 4 (though it's not guaranteed that it won't be "1000, Scale=0" instead.)
 32        //    0             => "", Scale = 0
 33        //    3m            => "3", Scale = 1
 34        //    3.00m         => "300", Scale = 1 (this is important: trailing zeroes actually matter in Decimal)
 35        //
 36        public int Scale;
 37        public bool IsNegative;
 38
 139        public unsafe Span<byte> Digits => new Span<byte>(Unsafe.AsPointer(ref _b0), BufferSize);
 40
 141        public unsafe byte* UnsafeDigits => (byte*)Unsafe.AsPointer(ref _b0);
 42
 143        public int NumDigits => Digits.IndexOf<byte>(0);
 44
 45        [Conditional("DEBUG")]
 46        public void CheckConsistency()
 147        {
 48#if DEBUG
 149            Span<byte> digits = Digits;
 50
 151            Debug.Assert(digits[0] != '0', "Leading zeros should never be stored in a Number");
 52
 53            int numDigits;
 354            for (numDigits = 0; numDigits < BufferSize; numDigits++)
 155            {
 156                byte digit = digits[numDigits];
 157                if (digit == 0)
 158                    break;
 59
 160                Debug.Assert(digit >= '0' && digit <= '9', "Unexpected character found in Number");
 161            }
 62
 163            Debug.Assert(numDigits < BufferSize, "NUL terminator not found in Number");
 64#endif // DEBUG
 165        }
 66
 67        //
 68        // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it
 69        //
 70        public override string ToString()
 071        {
 072            StringBuilder sb = new StringBuilder();
 073            sb.Append('[');
 074            sb.Append('"');
 075            Span<byte> digits = Digits;
 076            for (int i = 0; i < BufferSize; i++)
 077            {
 078                byte digit = digits[i];
 079                if (digit == 0)
 080                    break;
 081                sb.Append((char)digit);
 082            }
 083            sb.Append('"');
 084            sb.Append(", Scale = " + Scale);
 085            sb.Append(", IsNegative   = " + IsNegative);
 086            sb.Append(']');
 087            return sb.ToString();
 088        }
 89
 90        public const int BufferSize = 50 + 1; // Matches https://github.com/dotnet/coreclr/blob/097e68658c5249eaefff33bd
 91
 92        //
 93        // 50+1 bytes of ASCII digits ('0'..'9'). (Not using "fixed byte[]" as this breaks the VS debugging experience.)
 94        // That's enough room to store the worst case Decimal and double.
 95        //
 96        // A NUL terminator (not to be confused with '0') marks the end of the digits.
 97        //
 98        // Leading zeroes are never stored, even if the entire number is zero.
 99        //
 100        // Trailing zeroes after the decimal point *are* stored. This is important for System.Decimal
 101        // as trailing zeroes are significant in Decimal:
 102        //
 103        //    decimal d1 = 1m;      => d1.ToString("G") emits "1"
 104        //    decimal d2 = 1.00m;   => d1.ToStirng("G") emits "1.00"
 105        //
 106        private byte _b0;
 107        private byte _b1;
 108        private byte _b2;
 109        private byte _b3;
 110        private byte _b4;
 111        private byte _b5;
 112        private byte _b6;
 113        private byte _b7;
 114        private byte _b8;
 115        private byte _b9;
 116        private byte _b10;
 117        private byte _b11;
 118        private byte _b12;
 119        private byte _b13;
 120        private byte _b14;
 121        private byte _b15;
 122        private byte _b16;
 123        private byte _b17;
 124        private byte _b18;
 125        private byte _b19;
 126        private byte _b20;
 127        private byte _b21;
 128        private byte _b22;
 129        private byte _b23;
 130        private byte _b24;
 131        private byte _b25;
 132        private byte _b26;
 133        private byte _b27;
 134        private byte _b28;
 135        private byte _b29;
 136        private byte _b30;
 137        private byte _b31;
 138        private byte _b32;
 139        private byte _b33;
 140        private byte _b34;
 141        private byte _b35;
 142        private byte _b36;
 143        private byte _b37;
 144        private byte _b38;
 145        private byte _b39;
 146        private byte _b40;
 147        private byte _b41;
 148        private byte _b42;
 149        private byte _b43;
 150        private byte _b44;
 151        private byte _b45;
 152        private byte _b46;
 153        private byte _b47;
 154        private byte _b48;
 155        private byte _b49;
 156        private byte _b50;
 157    }
 158}