Number.NumberBuffer.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. using System.Diagnostics;
  5. using System.Text;
  6. using Internal.Runtime.CompilerServices;
  7. namespace System
  8. {
  9. internal static partial class Number
  10. {
  11. // We need 1 additional byte, per length, for the terminating null
  12. internal const int DecimalNumberBufferLength = 29 + 1 + 1; // 29 for the longest input + 1 for rounding
  13. internal const int DoubleNumberBufferLength = 767 + 1 + 1; // 767 for the longest input + 1 for rounding: 4.9406564584124654E-324
  14. internal const int Int32NumberBufferLength = 10 + 1; // 10 for the longest input: 2,147,483,647
  15. internal const int Int64NumberBufferLength = 19 + 1; // 19 for the longest input: 9,223,372,036,854,775,807
  16. internal const int SingleNumberBufferLength = 112 + 1 + 1; // 112 for the longest input + 1 for rounding: 1.40129846E-45
  17. internal const int UInt32NumberBufferLength = 10 + 1; // 10 for the longest input: 4,294,967,295
  18. internal const int UInt64NumberBufferLength = 20 + 1; // 20 for the longest input: 18,446,744,073,709,551,615
  19. internal unsafe ref struct NumberBuffer
  20. {
  21. public int DigitsCount;
  22. public int Scale;
  23. public bool IsNegative;
  24. public bool HasNonZeroTail;
  25. public NumberBufferKind Kind;
  26. public Span<byte> Digits;
  27. public NumberBuffer(NumberBufferKind kind, byte* digits, int digitsLength)
  28. {
  29. Debug.Assert(digits != null);
  30. Debug.Assert(digitsLength > 0);
  31. DigitsCount = 0;
  32. Scale = 0;
  33. IsNegative = false;
  34. HasNonZeroTail = false;
  35. Kind = kind;
  36. Digits = new Span<byte>(digits, digitsLength);
  37. #if DEBUG
  38. Digits.Fill(0xCC);
  39. #endif
  40. Digits[0] = (byte)('\0');
  41. CheckConsistency();
  42. }
  43. [Conditional("DEBUG")]
  44. public void CheckConsistency()
  45. {
  46. #if DEBUG
  47. Debug.Assert((Kind == NumberBufferKind.Integer) || (Kind == NumberBufferKind.Decimal) || (Kind == NumberBufferKind.FloatingPoint));
  48. Debug.Assert(Digits[0] != '0', "Leading zeros should never be stored in a Number");
  49. int numDigits;
  50. for (numDigits = 0; numDigits < Digits.Length; numDigits++)
  51. {
  52. byte digit = Digits[numDigits];
  53. if (digit == 0)
  54. {
  55. break;
  56. }
  57. Debug.Assert((digit >= '0') && (digit <= '9'), "Unexpected character found in Number");
  58. }
  59. Debug.Assert(numDigits == DigitsCount, "Null terminator found in unexpected location in Number");
  60. Debug.Assert(numDigits < Digits.Length, "Null terminator not found in Number");
  61. #endif // DEBUG
  62. }
  63. public byte* GetDigitsPointer()
  64. {
  65. // This is safe to do since we are a ref struct
  66. return (byte*)(Unsafe.AsPointer(ref Digits[0]));
  67. }
  68. //
  69. // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works.
  70. //
  71. public override string ToString()
  72. {
  73. StringBuilder sb = new StringBuilder();
  74. sb.Append('[');
  75. sb.Append('"');
  76. for (int i = 0; i < Digits.Length; i++)
  77. {
  78. byte digit = Digits[i];
  79. if (digit == 0)
  80. {
  81. break;
  82. }
  83. sb.Append((char)(digit));
  84. }
  85. sb.Append('"');
  86. sb.Append(", Length = " + DigitsCount);
  87. sb.Append(", Scale = " + Scale);
  88. sb.Append(", IsNegative = " + IsNegative);
  89. sb.Append(", HasNonZeroTail = " + HasNonZeroTail);
  90. sb.Append(", Kind = " + Kind);
  91. sb.Append(']');
  92. return sb.ToString();
  93. }
  94. }
  95. internal enum NumberBufferKind : byte
  96. {
  97. Unknown = 0,
  98. Integer = 1,
  99. Decimal = 2,
  100. FloatingPoint = 3,
  101. }
  102. }
  103. }