git.lukeshu.com/go/lowmemjson@v0.3.9-0.20230723050957-72f6d13f6fb2/borrowed_misc.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  //
     5  // SPDX-License-Identifier: BSD-3-Clause
     6  
     7  package lowmemjson
     8  
     9  import (
    10  	"io"
    11  	"math"
    12  	"reflect"
    13  	"strconv"
    14  
    15  	"git.lukeshu.com/go/lowmemjson/internal/fastio/noescape"
    16  )
    17  
    18  // isEmptyValue is borrowed from encode.go.
    19  func isEmptyValue(v reflect.Value) bool {
    20  	switch v.Kind() {
    21  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
    22  		return v.Len() == 0
    23  	case reflect.Bool:
    24  		return !v.Bool()
    25  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    26  		return v.Int() == 0
    27  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    28  		return v.Uint() == 0
    29  	case reflect.Float32, reflect.Float64:
    30  		return v.Float() == 0
    31  	case reflect.Interface, reflect.Pointer:
    32  		return v.IsNil()
    33  	}
    34  	return false
    35  }
    36  
    37  // encodeFloat is lightly modified from
    38  // encode.go:floatEncoder.encode().
    39  func encodeFloat(w io.Writer, bits int, v reflect.Value) error {
    40  	var scratch [64]byte
    41  
    42  	f := v.Float()
    43  	if math.IsInf(f, 0) || math.IsNaN(f) {
    44  		return &EncodeValueError{Value: v, Str: strconv.FormatFloat(f, 'g', -1, bits)}
    45  	}
    46  
    47  	// Convert as if by ES6 number to string conversion.
    48  	// This matches most other JSON generators.
    49  	// See golang.org/issue/6384 and golang.org/issue/14135.
    50  	// Like fmt %g, but the exponent cutoffs are different
    51  	// and exponents themselves are not padded to two digits.
    52  	b := scratch[:0]
    53  	abs := math.Abs(f)
    54  	fmt := byte('f')
    55  	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
    56  	if abs != 0 {
    57  		if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
    58  			fmt = 'e'
    59  		}
    60  	}
    61  	b = strconv.AppendFloat(b, f, fmt, -1, bits)
    62  	if fmt == 'e' {
    63  		// clean up e-09 to e-9
    64  		n := len(b)
    65  		if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
    66  			b[n-2] = b[n-1]
    67  			b = b[:n-1]
    68  		}
    69  	}
    70  
    71  	if _, err := noescape.Write(w, b); err != nil {
    72  		return err
    73  	}
    74  	return nil
    75  }