github.com/goplus/igop@v0.25.0/print.go (about)

     1  /*
     2   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package igop
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  	"unsafe"
    24  )
    25  
    26  // writevalue for write argument pass to print
    27  func writevalue(buf *bytes.Buffer, v interface{}, enableAny bool) {
    28  	switch v := v.(type) {
    29  	case float64:
    30  		writefloat(buf, v)
    31  	case float32:
    32  		writefloat(buf, float64(v))
    33  	case complex128:
    34  		writecomplex(buf, v)
    35  	case complex64:
    36  		writecomplex(buf, complex128(v))
    37  	case nil, bool, int, int8, int16, int32, int64,
    38  		uint, uint8, uint16, uint32, uint64, uintptr,
    39  		string:
    40  		fmt.Fprintf(buf, "%v", v)
    41  	default:
    42  		i := reflect.ValueOf(v)
    43  		switch i.Kind() {
    44  		case reflect.Float32, reflect.Float64:
    45  			writefloat(buf, i.Float())
    46  		case reflect.Complex64, reflect.Complex128:
    47  			writecomplex(buf, i.Complex())
    48  		case reflect.Map, reflect.Ptr, reflect.Func, reflect.Chan, reflect.UnsafePointer:
    49  			fmt.Fprintf(buf, "%p", v)
    50  		case reflect.Slice:
    51  			fmt.Fprintf(buf, "[%v/%v]%p", i.Len(), i.Cap(), v)
    52  		case reflect.String:
    53  			fmt.Fprintf(buf, "%v", v)
    54  		case reflect.Interface:
    55  			eface := *(*emptyInterface)(unsafe.Pointer(&i))
    56  			fmt.Fprintf(buf, "(%p,%p)", eface.typ, eface.word)
    57  		case reflect.Struct, reflect.Array:
    58  			if enableAny {
    59  				fmt.Fprintf(buf, "%v", v)
    60  			} else {
    61  				panic(fmt.Sprintf("illegal types for operand: print\n\t%T", v))
    62  			}
    63  		default:
    64  			fmt.Fprintf(buf, "%v", v)
    65  		}
    66  	}
    67  }
    68  
    69  // emptyInterface is the header for an interface{} value.
    70  type emptyInterface struct {
    71  	typ  unsafe.Pointer
    72  	word unsafe.Pointer
    73  }
    74  
    75  func writeinterface(out *bytes.Buffer, i interface{}) {
    76  	eface := *(*emptyInterface)(unsafe.Pointer(&i))
    77  	fmt.Fprintf(out, "(%p,%p)", eface.typ, eface.word)
    78  }
    79  
    80  func writecomplex(out *bytes.Buffer, c complex128) {
    81  	out.WriteByte('(')
    82  	writefloat(out, real(c))
    83  	writefloat(out, imag(c))
    84  	out.WriteString("i)")
    85  }
    86  
    87  func writefloat(out *bytes.Buffer, v float64) {
    88  	switch {
    89  	case v != v:
    90  		out.WriteString("NaN")
    91  		return
    92  	case v+v == v && v > 0:
    93  		out.WriteString("+Inf")
    94  		return
    95  	case v+v == v && v < 0:
    96  		out.WriteString("-Inf")
    97  		return
    98  	}
    99  
   100  	const n = 7 // digits printed
   101  	var buf [n + 7]byte
   102  	buf[0] = '+'
   103  	e := 0 // exp
   104  	if v == 0 {
   105  		if 1/v < 0 {
   106  			buf[0] = '-'
   107  		}
   108  	} else {
   109  		if v < 0 {
   110  			v = -v
   111  			buf[0] = '-'
   112  		}
   113  
   114  		// normalize
   115  		for v >= 10 {
   116  			e++
   117  			v /= 10
   118  		}
   119  		for v < 1 {
   120  			e--
   121  			v *= 10
   122  		}
   123  
   124  		// round
   125  		h := 5.0
   126  		for i := 0; i < n; i++ {
   127  			h /= 10
   128  		}
   129  		v += h
   130  		if v >= 10 {
   131  			e++
   132  			v /= 10
   133  		}
   134  	}
   135  
   136  	// format +d.dddd+edd
   137  	for i := 0; i < n; i++ {
   138  		s := int(v)
   139  		buf[i+2] = byte(s + '0')
   140  		v -= float64(s)
   141  		v *= 10
   142  	}
   143  	buf[1] = buf[2]
   144  	buf[2] = '.'
   145  
   146  	buf[n+2] = 'e'
   147  	buf[n+3] = '+'
   148  	if e < 0 {
   149  		e = -e
   150  		buf[n+3] = '-'
   151  	}
   152  
   153  	buf[n+4] = byte(e/100) + '0'
   154  	buf[n+5] = byte(e/10)%10 + '0'
   155  	buf[n+6] = byte(e%10) + '0'
   156  	out.Write(buf[:])
   157  }
   158  
   159  // writeany for write argument pass to panic
   160  func writeany(buf *bytes.Buffer, v interface{}) {
   161  	switch v := v.(type) {
   162  	case nil, bool, int, int8, int16, int32, int64,
   163  		float32, float64, complex64, complex128,
   164  		uint, uint8, uint16, uint32, uint64, uintptr,
   165  		string:
   166  		writevalue(buf, v, true)
   167  	case error:
   168  		fmt.Fprintf(buf, "%v", v)
   169  	default:
   170  		i := reflect.ValueOf(v)
   171  		typ := i.Type()
   172  		switch i.Kind() {
   173  		case reflect.String:
   174  			fmt.Fprintf(buf, "%v(%q)", typ, i)
   175  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   176  			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   177  			fmt.Fprintf(buf, "%v(%v)", typ, i)
   178  		case reflect.Float32, reflect.Float64:
   179  			buf.WriteString(typ.String())
   180  			buf.WriteByte('(')
   181  			writefloat(buf, i.Float())
   182  			buf.WriteByte(')')
   183  		case reflect.Complex64, reflect.Complex128:
   184  			buf.WriteString(typ.String())
   185  			buf.WriteByte('(')
   186  			writecomplex(buf, i.Complex())
   187  			buf.WriteByte(')')
   188  		default:
   189  			eface := *(*emptyInterface)(unsafe.Pointer(&i))
   190  			fmt.Fprintf(buf, "(%v) %p", typ, eface.word)
   191  		}
   192  	}
   193  }