123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- namespace Jint.Native.Number.Dtoa
- {
- public class FastDtoaBuilder
- {
- // allocate buffer for generated digits + extra notation + padding zeroes
- private readonly char[] _chars = new char[FastDtoa.KFastDtoaMaximalLength + 8];
- internal int End = 0;
- internal int Point;
- private bool _formatted;
- internal void Append(char c)
- {
- _chars[End++] = c;
- }
- internal void DecreaseLast()
- {
- _chars[End - 1]--;
- }
- public void Reset()
- {
- End = 0;
- _formatted = false;
- }
- public override string ToString()
- {
- return "[chars:" + new System.String(_chars, 0, End) + ", point:" + Point + "]";
- }
- public System.String Format()
- {
- if (!_formatted)
- {
- // check for minus sign
- int firstDigit = _chars[0] == '-' ? 1 : 0;
- int decPoint = Point - firstDigit;
- if (decPoint < -5 || decPoint > 21)
- {
- ToExponentialFormat(firstDigit, decPoint);
- }
- else
- {
- ToFixedFormat(firstDigit, decPoint);
- }
- _formatted = true;
- }
- return new System.String(_chars, 0, End);
- }
- private void ToFixedFormat(int firstDigit, int decPoint)
- {
- if (Point < End)
- {
- // insert decimal point
- if (decPoint > 0)
- {
- // >= 1, split decimals and insert point
- System.Array.Copy(_chars, Point, _chars, Point + 1, End - Point);
- _chars[Point] = '.';
- End++;
- }
- else
- {
- // < 1,
- int target = firstDigit + 2 - decPoint;
- System.Array.Copy(_chars, firstDigit, _chars, target, End - firstDigit);
- _chars[firstDigit] = '0';
- _chars[firstDigit + 1] = '.';
- if (decPoint < 0)
- {
- Fill(_chars, firstDigit + 2, target, '0');
- }
- End += 2 - decPoint;
- }
- }
- else if (Point > End)
- {
- // large integer, add trailing zeroes
- Fill(_chars, End, Point, '0');
- End += Point - End;
- }
- }
- private void ToExponentialFormat(int firstDigit, int decPoint)
- {
- if (End - firstDigit > 1)
- {
- // insert decimal point if more than one digit was produced
- int dot = firstDigit + 1;
- System.Array.Copy(_chars, dot, _chars, dot + 1, End - dot);
- _chars[dot] = '.';
- End++;
- }
- _chars[End++] = 'e';
- char sign = '+';
- int exp = decPoint - 1;
- if (exp < 0)
- {
- sign = '-';
- exp = -exp;
- }
- _chars[End++] = sign;
- int charPos = exp > 99 ? End + 2 : exp > 9 ? End + 1 : End;
- End = charPos + 1;
- // code below is needed because Integer.getChars() is not public
- for (;;)
- {
- int r = exp%10;
- _chars[charPos--] = Digits[r];
- exp = exp/10;
- if (exp == 0) break;
- }
- }
- private static readonly char[] Digits =
- {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
- };
- private void Fill<T>(T[] array, int fromIndex, int toIndex, T val)
- {
- for (int i = fromIndex; i < toIndex; i++)
- {
- array[i] = val;
- }
- }
- }
- }
|