...

Source file src/github.com/dop251/goja/ftoa/ftostr.go

Documentation: github.com/dop251/goja/ftoa

     1  package ftoa
     2  
     3  import (
     4  	"math"
     5  	"strconv"
     6  
     7  	"github.com/dop251/goja/ftoa/internal/fast"
     8  )
     9  
    10  type FToStrMode int
    11  
    12  const (
    13  	// Either fixed or exponential format; round-trip
    14  	ModeStandard FToStrMode = iota
    15  	// Always exponential format; round-trip
    16  	ModeStandardExponential
    17  	// Round to <precision> digits after the decimal point; exponential if number is large
    18  	ModeFixed
    19  	// Always exponential format; <precision> significant digits
    20  	ModeExponential
    21  	// Either fixed or exponential format; <precision> significant digits
    22  	ModePrecision
    23  )
    24  
    25  func insert(b []byte, p int, c byte) []byte {
    26  	b = append(b, 0)
    27  	copy(b[p+1:], b[p:])
    28  	b[p] = c
    29  	return b
    30  }
    31  
    32  func expand(b []byte, delta int) []byte {
    33  	newLen := len(b) + delta
    34  	if newLen <= cap(b) {
    35  		return b[:newLen]
    36  	}
    37  	b1 := make([]byte, newLen)
    38  	copy(b1, b)
    39  	return b1
    40  }
    41  
    42  func FToStr(d float64, mode FToStrMode, precision int, buffer []byte) []byte {
    43  	if math.IsNaN(d) {
    44  		buffer = append(buffer, "NaN"...)
    45  		return buffer
    46  	}
    47  	if math.IsInf(d, 0) {
    48  		if math.Signbit(d) {
    49  			buffer = append(buffer, '-')
    50  		}
    51  		buffer = append(buffer, "Infinity"...)
    52  		return buffer
    53  	}
    54  
    55  	if mode == ModeFixed && (d >= 1e21 || d <= -1e21) {
    56  		mode = ModeStandard
    57  	}
    58  
    59  	var decPt int
    60  	var ok bool
    61  	startPos := len(buffer)
    62  
    63  	if d != 0 { // also matches -0
    64  		if d < 0 {
    65  			buffer = append(buffer, '-')
    66  			d = -d
    67  			startPos++
    68  		}
    69  		switch mode {
    70  		case ModeStandard, ModeStandardExponential:
    71  			buffer, decPt, ok = fast.Dtoa(d, fast.ModeShortest, 0, buffer)
    72  		case ModeExponential, ModePrecision:
    73  			buffer, decPt, ok = fast.Dtoa(d, fast.ModePrecision, precision, buffer)
    74  		}
    75  	} else {
    76  		buffer = append(buffer, '0')
    77  		decPt, ok = 1, true
    78  	}
    79  	if !ok {
    80  		buffer, decPt = ftoa(d, dtoaModes[mode], mode >= ModeFixed, precision, buffer)
    81  	}
    82  	exponentialNotation := false
    83  	minNDigits := 0 /* Minimum number of significand digits required by mode and precision */
    84  	nDigits := len(buffer) - startPos
    85  
    86  	switch mode {
    87  	case ModeStandard:
    88  		if decPt < -5 || decPt > 21 {
    89  			exponentialNotation = true
    90  		} else {
    91  			minNDigits = decPt
    92  		}
    93  	case ModeFixed:
    94  		if precision >= 0 {
    95  			minNDigits = decPt + precision
    96  		} else {
    97  			minNDigits = decPt
    98  		}
    99  	case ModeExponential:
   100  		//                    JS_ASSERT(precision > 0);
   101  		minNDigits = precision
   102  		fallthrough
   103  	case ModeStandardExponential:
   104  		exponentialNotation = true
   105  	case ModePrecision:
   106  		//                    JS_ASSERT(precision > 0);
   107  		minNDigits = precision
   108  		if decPt < -5 || decPt > precision {
   109  			exponentialNotation = true
   110  		}
   111  	}
   112  
   113  	for nDigits < minNDigits {
   114  		buffer = append(buffer, '0')
   115  		nDigits++
   116  	}
   117  
   118  	if exponentialNotation {
   119  		/* Insert a decimal point if more than one significand digit */
   120  		if nDigits != 1 {
   121  			buffer = insert(buffer, startPos+1, '.')
   122  		}
   123  		buffer = append(buffer, 'e')
   124  		if decPt-1 >= 0 {
   125  			buffer = append(buffer, '+')
   126  		}
   127  		buffer = strconv.AppendInt(buffer, int64(decPt-1), 10)
   128  	} else if decPt != nDigits {
   129  		/* Some kind of a fraction in fixed notation */
   130  		//                JS_ASSERT(decPt <= nDigits);
   131  		if decPt > 0 {
   132  			/* dd...dd . dd...dd */
   133  			buffer = insert(buffer, startPos+decPt, '.')
   134  		} else {
   135  			/* 0 . 00...00dd...dd */
   136  			buffer = expand(buffer, 2-decPt)
   137  			copy(buffer[startPos+2-decPt:], buffer[startPos:])
   138  			buffer[startPos] = '0'
   139  			buffer[startPos+1] = '.'
   140  			for i := startPos + 2; i < startPos+2-decPt; i++ {
   141  				buffer[i] = '0'
   142  			}
   143  		}
   144  	}
   145  
   146  	return buffer
   147  }
   148  

View as plain text