github.com/kortschak/utter@v1.5.0/common.go (about)

     1  /*
     2   * Copyright (c) 2013 Dave Collins <dave@davec.name>
     3   * Copyright (c) 2015 Dan Kortschak <dan.kortschak@adelaide.edu.au>
     4   *
     5   * Permission to use, copy, modify, and distribute this software for any
     6   * purpose with or without fee is hereby granted, provided that the above
     7   * copyright notice and this permission notice appear in all copies.
     8   *
     9   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    10   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    11   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    12   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    13   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    14   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    15   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    16   */
    17  
    18  package utter
    19  
    20  import (
    21  	"bytes"
    22  	"fmt"
    23  	"io"
    24  	"math"
    25  	"reflect"
    26  	"sort"
    27  	"strconv"
    28  	"unsafe"
    29  )
    30  
    31  const (
    32  	// ptrSize is the size of a pointer on the current arch.
    33  	ptrSize = unsafe.Sizeof((*byte)(nil))
    34  )
    35  
    36  var (
    37  	// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
    38  	// internal reflect.Value fields.  These values are valid before golang
    39  	// commit ecccf07e7f9d which changed the format.  The are also valid
    40  	// after commit 82f48826c6c7 which changed the format again to mirror
    41  	// the original format.  Code in the init function updates these offsets
    42  	// as necessary.
    43  	offsetPtr    = uintptr(ptrSize)
    44  	offsetScalar = uintptr(0)
    45  	offsetFlag   = uintptr(ptrSize * 2)
    46  
    47  	// flagKindWidth and flagKindShift indicate various bits that the
    48  	// reflect package uses internally to track kind information.
    49  	//
    50  	// flagRO indicates whether or not the value field of a reflect.Value is
    51  	// read-only.
    52  	//
    53  	// flagIndir indicates whether the value field of a reflect.Value is
    54  	// the actual data or a pointer to the data.
    55  	//
    56  	// These values are valid before golang commit 90a7c3c86944 which
    57  	// changed their positions.  Code in the init function updates these
    58  	// flags as necessary.
    59  	flagKindWidth = uintptr(5)
    60  	flagKindShift = uintptr(flagKindWidth - 1)
    61  	flagRO        = uintptr(1 << 0)
    62  	flagIndir     = uintptr(1 << 1)
    63  )
    64  
    65  func init() {
    66  	// Older versions of reflect.Value stored small integers directly in the
    67  	// ptr field (which is named val in the older versions).  Versions
    68  	// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
    69  	// scalar for this purpose which unfortunately came before the flag
    70  	// field, so the offset of the flag field is different for those
    71  	// versions.
    72  	//
    73  	// This code constructs a new reflect.Value from a known small integer
    74  	// and checks if the size of the reflect.Value struct indicates it has
    75  	// the scalar field. When it does, the offsets are updated accordingly.
    76  	vv := reflect.ValueOf(0xf00)
    77  	if unsafe.Sizeof(vv) == (ptrSize * 4) {
    78  		offsetScalar = ptrSize * 2
    79  		offsetFlag = ptrSize * 3
    80  	}
    81  
    82  	// Commit 90a7c3c86944 changed the flag positions such that the low
    83  	// order bits are the kind.  This code extracts the kind from the flags
    84  	// field and ensures it's the correct type.  When it's not, the flag
    85  	// order has been changed to the newer format, so the flags are updated
    86  	// accordingly.
    87  	upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
    88  	upfv := *(*uintptr)(upf)
    89  	flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
    90  	if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
    91  		flagKindShift = 0
    92  		flagRO = 1 << 5
    93  		flagIndir = 1 << 6
    94  
    95  		// Commit adf9b30e5594 modified the flags to separate the
    96  		// flagRO flag into two bits which specifies whether or not the
    97  		// field is embedded.  This causes flagIndir to move over a bit
    98  		// and means that flagRO is the combination of either of the
    99  		// original flagRO bit and the new bit.
   100  		//
   101  		// This code detects the change by extracting what used to be
   102  		// the indirect bit to ensure it's set.  When it's not, the flag
   103  		// order has been changed to the newer format, so the flags are
   104  		// updated accordingly.
   105  		if upfv&flagIndir == 0 {
   106  			flagRO = 3 << 5
   107  			flagIndir = 1 << 7
   108  		}
   109  	}
   110  }
   111  
   112  // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
   113  // the typical safety restrictions preventing access to unaddressable and
   114  // unexported data.  It works by digging the raw pointer to the underlying
   115  // value out of the protected value and generating a new unprotected (unsafe)
   116  // reflect.Value to it.
   117  //
   118  // This allows us to check for implementations of the Stringer and error
   119  // interfaces to be used for pretty printing ordinarily unaddressable and
   120  // inaccessible values such as unexported struct fields.
   121  func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
   122  	indirects := 1
   123  	vt := v.Type()
   124  	upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
   125  	rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
   126  	if rvf&flagIndir != 0 {
   127  		vt = reflect.PtrTo(v.Type())
   128  		indirects++
   129  	} else if offsetScalar != 0 {
   130  		// The value is in the scalar field when it's not one of the
   131  		// reference types.
   132  		switch vt.Kind() {
   133  		case reflect.Uintptr:
   134  		case reflect.Chan:
   135  		case reflect.Func:
   136  		case reflect.Map:
   137  		case reflect.Ptr:
   138  		case reflect.UnsafePointer:
   139  		default:
   140  			upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
   141  				offsetScalar)
   142  		}
   143  	}
   144  
   145  	pv := reflect.NewAt(vt, upv)
   146  	rv = pv
   147  	for i := 0; i < indirects; i++ {
   148  		rv = rv.Elem()
   149  	}
   150  	return rv
   151  }
   152  
   153  // Some constants in the form of bytes to avoid string overhead.  This mirrors
   154  // the technique used in the fmt package.
   155  var (
   156  	backQuoteBytes        = []byte("`")
   157  	quoteBytes            = []byte(`"`)
   158  	plusBytes             = []byte("+")
   159  	iBytes                = []byte("i")
   160  	trueBytes             = []byte("true")
   161  	falseBytes            = []byte("false")
   162  	interfaceBytes        = []byte("interface{}")
   163  	interfaceTypeBytes    = []byte("interface {}")
   164  	commaSpaceBytes       = []byte(", ")
   165  	commaNewlineBytes     = []byte(",\n")
   166  	newlineBytes          = []byte("\n")
   167  	openBraceBytes        = []byte("{")
   168  	openBraceNewlineBytes = []byte("{\n")
   169  	closeBraceBytes       = []byte("}")
   170  	ampersandBytes        = []byte("&")
   171  	colonSpaceBytes       = []byte(": ")
   172  	spaceBytes            = []byte(" ")
   173  	openParenBytes        = []byte("(")
   174  	closeParenBytes       = []byte(")")
   175  	nilBytes              = []byte("nil")
   176  	hexZeroBytes          = []byte("0x")
   177  	zeroBytes             = []byte("0")
   178  	pointZeroBytes        = []byte(".0")
   179  	openCommentBytes      = []byte(" /*")
   180  	closeCommentBytes     = []byte("*/ ")
   181  	pointerChainBytes     = []byte("->")
   182  	circularBytes         = []byte("(<already shown>)")
   183  	invalidAngleBytes     = []byte("<invalid>")
   184  )
   185  
   186  // hexDigits is used to map a decimal value to a hex digit.
   187  var hexDigits = "0123456789abcdef"
   188  
   189  // printBool outputs a boolean value as true or false to Writer w.
   190  func printBool(w io.Writer, val bool) {
   191  	if val {
   192  		w.Write(trueBytes)
   193  	} else {
   194  		w.Write(falseBytes)
   195  	}
   196  }
   197  
   198  // printInt outputs a signed integer value to Writer w.
   199  func printInt(w io.Writer, val int64, base int) {
   200  	w.Write([]byte(strconv.FormatInt(val, base)))
   201  }
   202  
   203  // printUint outputs an unsigned integer value to Writer w.
   204  func printUint(w io.Writer, val uint64, base int) {
   205  	w.Write([]byte(strconv.FormatUint(val, base)))
   206  }
   207  
   208  // printFloat outputs a floating point value using the specified precision,
   209  // which is expected to be 32 or 64bit, to Writer w.
   210  func printFloat(w io.Writer, val float64, precision int, typeElided bool) {
   211  	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
   212  	if typeElided && !math.IsInf(val, 0) && val == math.Floor(val) {
   213  		w.Write(pointZeroBytes)
   214  	}
   215  }
   216  
   217  // printComplex outputs a complex value using the specified float precision
   218  // for the real and imaginary parts to Writer w.
   219  func printComplex(w io.Writer, c complex128, floatPrecision int) {
   220  	r := real(c)
   221  	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
   222  	i := imag(c)
   223  	if i >= 0 {
   224  		w.Write(plusBytes)
   225  	}
   226  	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
   227  	w.Write(iBytes)
   228  }
   229  
   230  // hexDump is a modified 'hexdump -C'-like that returns a commented Go syntax
   231  // byte slice or array.
   232  func hexDump(w io.Writer, data []byte, indent string, width int, comment bool) {
   233  	var commentBytes []byte
   234  	if comment {
   235  		commentBytes = make([]byte, width)
   236  	}
   237  
   238  	for i, v := range data {
   239  		if i%width == 0 {
   240  			fmt.Fprint(w, indent)
   241  		} else {
   242  			w.Write(spaceBytes)
   243  		}
   244  
   245  		fmt.Fprintf(w, "%#02x,", v)
   246  		if comment {
   247  			if v < 32 || v > 126 {
   248  				v = '.'
   249  			}
   250  			commentBytes[i%width] = v
   251  		}
   252  
   253  		if !comment {
   254  			if i%width == width-1 || i == len(data)-1 {
   255  				fmt.Fprintln(w)
   256  			}
   257  			continue
   258  		}
   259  		if i%width == width-1 {
   260  			fmt.Fprintf(w, " // |%s|\n", commentBytes[:])
   261  		} else if i == len(data)-1 {
   262  			if len(data) > width {
   263  				slots := width - i%width - 1
   264  				switch slots {
   265  				case 0:
   266  					// Do nothing.
   267  				case 1:
   268  					w.Write([]byte(" /* */"))
   269  				default:
   270  					w.Write([]byte(" /*   "))
   271  					w.Write(bytes.Repeat([]byte("      "), slots-2))
   272  					w.Write([]byte("    */"))
   273  				}
   274  			}
   275  			fmt.Fprintf(w, " // |%s|\n", commentBytes[:len(data)%width])
   276  		}
   277  	}
   278  }
   279  
   280  // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
   281  // prefix to Writer w.
   282  func printHexPtr(w io.Writer, p uintptr, isPointer bool) {
   283  	// Null pointer.
   284  	num := uint64(p)
   285  	if num == 0 {
   286  		if isPointer {
   287  			w.Write(nilBytes)
   288  		} else {
   289  			w.Write(zeroBytes)
   290  		}
   291  		return
   292  	}
   293  
   294  	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
   295  	buf := make([]byte, 18)
   296  
   297  	// It's simpler to construct the hex string right to left.
   298  	base := uint64(16)
   299  	i := len(buf) - 1
   300  	for num >= base {
   301  		buf[i] = hexDigits[num%base]
   302  		num /= base
   303  		i--
   304  	}
   305  	buf[i] = hexDigits[num]
   306  
   307  	// Add '0x' prefix.
   308  	i--
   309  	buf[i] = 'x'
   310  	i--
   311  	buf[i] = '0'
   312  
   313  	// Strip unused leading bytes.
   314  	buf = buf[i:]
   315  	w.Write(buf)
   316  }
   317  
   318  // mapSorter implements sort.Interface to allow a slice of reflect.Value
   319  // elements to be sorted.
   320  type mapSorter struct {
   321  	keys []reflect.Value
   322  	vals []reflect.Value
   323  }
   324  
   325  // Len returns the number of values in the slice.  It is part of the
   326  // sort.Interface implementation.
   327  func (s *mapSorter) Len() int {
   328  	return len(s.keys)
   329  }
   330  
   331  // Swap swaps the values at the passed indices.  It is part of the
   332  // sort.Interface implementation.
   333  func (s *mapSorter) Swap(i, j int) {
   334  	s.keys[i], s.keys[j] = s.keys[j], s.keys[i]
   335  	s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
   336  }
   337  
   338  // less returns whether the a key/value should sort before the b key/value.
   339  // It is used by valueSorter.Less as part of the sort.Interface implementation.
   340  func less(kA, kB, vA, vB reflect.Value) bool {
   341  	switch kA.Kind() {
   342  	case reflect.Bool:
   343  		return !kA.Bool() && kB.Bool()
   344  	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
   345  		return kA.Int() < kB.Int()
   346  	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
   347  		return kA.Uint() < kB.Uint()
   348  	case reflect.Float32, reflect.Float64:
   349  		if vA.IsValid() && vB.IsValid() && math.IsNaN(kA.Float()) && math.IsNaN(kB.Float()) {
   350  			return less(vA, vB, reflect.Value{}, reflect.Value{})
   351  		}
   352  		return math.IsNaN(kA.Float()) || kA.Float() < kB.Float()
   353  	case reflect.String:
   354  		return kA.String() < kB.String()
   355  	case reflect.Uintptr:
   356  		return kA.Uint() < kB.Uint()
   357  	case reflect.Array:
   358  		// Compare the contents of both arrays.
   359  		l := kA.Len()
   360  		for i := 0; i < l; i++ {
   361  			av := kA.Index(i)
   362  			bv := kB.Index(i)
   363  			if av.Interface() == bv.Interface() {
   364  				continue
   365  			}
   366  			return less(av, bv, vA, vB)
   367  		}
   368  		return less(vA, vB, reflect.Value{}, reflect.Value{})
   369  	}
   370  	return fmt.Sprint(kA) < fmt.Sprint(kB)
   371  }
   372  
   373  // Less returns whether the value at index i should sort before the
   374  // value at index j.  It is part of the sort.Interface implementation.
   375  func (s *mapSorter) Less(i, j int) bool {
   376  	return less(s.keys[i], s.keys[j], s.vals[i], s.vals[j])
   377  }
   378  
   379  // sortMapByKeyVals is a generic sort function for native types: int, uint, bool,
   380  // float, string and uintptr.  Other inputs are sorted according to their
   381  // Value.String() value to ensure display stability. Floating point values
   382  // sort NaN before non-NaN values and NaN keys are ordered by their corresponding
   383  // values.
   384  func sortMapByKeyVals(keys, vals []reflect.Value) {
   385  	if len(keys) != len(vals) {
   386  		panic("invalid map key val slice pair")
   387  	}
   388  	if len(keys) == 0 {
   389  		return
   390  	}
   391  	sort.Sort(&mapSorter{keys: keys, vals: vals})
   392  }