FastDtoaBuilder.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. namespace Jint.Native.Number.Dtoa
  5. {
  6. public class FastDtoaBuilder
  7. {
  8. // allocate buffer for generated digits + extra notation + padding zeroes
  9. private readonly char[] _chars = new char[FastDtoa.KFastDtoaMaximalLength + 8];
  10. internal int End = 0;
  11. internal int Point;
  12. private bool _formatted;
  13. internal void Append(char c)
  14. {
  15. _chars[End++] = c;
  16. }
  17. internal void DecreaseLast()
  18. {
  19. _chars[End - 1]--;
  20. }
  21. public void Reset()
  22. {
  23. End = 0;
  24. _formatted = false;
  25. }
  26. public override string ToString()
  27. {
  28. return "[chars:" + new System.String(_chars, 0, End) + ", point:" + Point + "]";
  29. }
  30. public System.String Format()
  31. {
  32. if (!_formatted)
  33. {
  34. // check for minus sign
  35. int firstDigit = _chars[0] == '-' ? 1 : 0;
  36. int decPoint = Point - firstDigit;
  37. if (decPoint < -5 || decPoint > 21)
  38. {
  39. ToExponentialFormat(firstDigit, decPoint);
  40. }
  41. else
  42. {
  43. ToFixedFormat(firstDigit, decPoint);
  44. }
  45. _formatted = true;
  46. }
  47. return new System.String(_chars, 0, End);
  48. }
  49. private void ToFixedFormat(int firstDigit, int decPoint)
  50. {
  51. if (Point < End)
  52. {
  53. // insert decimal point
  54. if (decPoint > 0)
  55. {
  56. // >= 1, split decimals and insert point
  57. System.Array.Copy(_chars, Point, _chars, Point + 1, End - Point);
  58. _chars[Point] = '.';
  59. End++;
  60. }
  61. else
  62. {
  63. // < 1,
  64. int target = firstDigit + 2 - decPoint;
  65. System.Array.Copy(_chars, firstDigit, _chars, target, End - firstDigit);
  66. _chars[firstDigit] = '0';
  67. _chars[firstDigit + 1] = '.';
  68. if (decPoint < 0)
  69. {
  70. Fill(_chars, firstDigit + 2, target, '0');
  71. }
  72. End += 2 - decPoint;
  73. }
  74. }
  75. else if (Point > End)
  76. {
  77. // large integer, add trailing zeroes
  78. Fill(_chars, End, Point, '0');
  79. End += Point - End;
  80. }
  81. }
  82. private void ToExponentialFormat(int firstDigit, int decPoint)
  83. {
  84. if (End - firstDigit > 1)
  85. {
  86. // insert decimal point if more than one digit was produced
  87. int dot = firstDigit + 1;
  88. System.Array.Copy(_chars, dot, _chars, dot + 1, End - dot);
  89. _chars[dot] = '.';
  90. End++;
  91. }
  92. _chars[End++] = 'e';
  93. char sign = '+';
  94. int exp = decPoint - 1;
  95. if (exp < 0)
  96. {
  97. sign = '-';
  98. exp = -exp;
  99. }
  100. _chars[End++] = sign;
  101. int charPos = exp > 99 ? End + 2 : exp > 9 ? End + 1 : End;
  102. End = charPos + 1;
  103. // code below is needed because Integer.getChars() is not public
  104. for (;;)
  105. {
  106. int r = exp%10;
  107. _chars[charPos--] = Digits[r];
  108. exp = exp/10;
  109. if (exp == 0) break;
  110. }
  111. }
  112. private static readonly char[] Digits =
  113. {
  114. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
  115. };
  116. private void Fill<T>(T[] array, int fromIndex, int toIndex, T val)
  117. {
  118. for (int i = fromIndex; i < toIndex; i++)
  119. {
  120. array[i] = val;
  121. }
  122. }
  123. }
  124. }