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 }