github.com/rolandhe/saber@v0.0.4/utils/idutils.go (about)

     1  // Package utils, daog包使用的工具,现在只包含读取当前goroutine id的工具,未来可能会扩展
     2  package utils
     3  
     4  import (
     5  	"bytes"
     6  	"errors"
     7  	"fmt"
     8  	"runtime"
     9  	"strconv"
    10  )
    11  
    12  var goroutineSpace = []byte("goroutine ")
    13  
    14  // GetGoRoutineId 获得当前goroutine id函数
    15  func GetGoRoutineId() (uint64, error) {
    16  	b := make([]byte, 64)
    17  	b = b[:runtime.Stack(b, false)]
    18  	// Parse the 4707 out of "goroutine 4707 ["
    19  	b = bytes.TrimPrefix(b, goroutineSpace)
    20  	i := bytes.IndexByte(b, ' ')
    21  	if i < 0 {
    22  		panic(fmt.Sprintf("No space found in %q", b))
    23  	}
    24  	b = b[:i]
    25  	n, err := parseUintBytes(b, 10, 64)
    26  	if err != nil {
    27  		return 0, err
    28  	}
    29  	return n, nil
    30  }
    31  
    32  func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
    33  	var cutoff, maxVal uint64
    34  
    35  	if bitSize == 0 {
    36  		bitSize = strconv.IntSize
    37  	}
    38  
    39  	s0 := s
    40  	switch {
    41  	case len(s) < 1:
    42  		err = strconv.ErrSyntax
    43  		goto Error
    44  
    45  	case 2 <= base && base <= 36:
    46  		// valid base; nothing to do
    47  
    48  	case base == 0:
    49  		// Look for octal, hex prefix.
    50  		switch {
    51  		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
    52  			base = 16
    53  			s = s[2:]
    54  			if len(s) < 1 {
    55  				err = strconv.ErrSyntax
    56  				goto Error
    57  			}
    58  		case s[0] == '0':
    59  			base = 8
    60  		default:
    61  			base = 10
    62  		}
    63  
    64  	default:
    65  		err = errors.New("invalid base " + strconv.Itoa(base))
    66  		goto Error
    67  	}
    68  
    69  	n = 0
    70  	cutoff = cutoff64(base)
    71  	maxVal = 1<<uint(bitSize) - 1
    72  
    73  	for i := 0; i < len(s); i++ {
    74  		var v byte
    75  		d := s[i]
    76  		switch {
    77  		case '0' <= d && d <= '9':
    78  			v = d - '0'
    79  		case 'a' <= d && d <= 'z':
    80  			v = d - 'a' + 10
    81  		case 'A' <= d && d <= 'Z':
    82  			v = d - 'A' + 10
    83  		default:
    84  			n = 0
    85  			err = strconv.ErrSyntax
    86  			goto Error
    87  		}
    88  		if int(v) >= base {
    89  			n = 0
    90  			err = strconv.ErrSyntax
    91  			goto Error
    92  		}
    93  
    94  		if n >= cutoff {
    95  			// n*base overflows
    96  			n = 1<<64 - 1
    97  			err = strconv.ErrRange
    98  			goto Error
    99  		}
   100  		n *= uint64(base)
   101  
   102  		n1 := n + uint64(v)
   103  		if n1 < n || n1 > maxVal {
   104  			// n+v overflows
   105  			n = 1<<64 - 1
   106  			err = strconv.ErrRange
   107  			goto Error
   108  		}
   109  		n = n1
   110  	}
   111  
   112  	return n, nil
   113  
   114  Error:
   115  	return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
   116  }
   117  
   118  // Return the first number n such that n*base >= 1<<64.
   119  func cutoff64(base int) uint64 {
   120  	if base < 2 {
   121  		return 0
   122  	}
   123  	return (1<<64-1)/uint64(base) + 1
   124  }