github.com/sunvim/utils@v0.1.0/linear_ac/utils.go (about)

     1  // reference to
     2  // https://github.com/crazybie/linear_ac
     3  
     4  package linear_ac
     5  
     6  import (
     7  	"reflect"
     8  	"runtime"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"unsafe"
    13  )
    14  
    15  var (
    16  	ptrSize = int(unsafe.Sizeof(uintptr(0)))
    17  
    18  	boolPtrType = reflect.TypeOf((*bool)(nil))
    19  	intPtrType  = reflect.TypeOf((*int)(nil))
    20  	i32PtrType  = reflect.TypeOf((*int32)(nil))
    21  	u32PtrType  = reflect.TypeOf((*uint32)(nil))
    22  	i64PtrType  = reflect.TypeOf((*int64)(nil))
    23  	u64PtrType  = reflect.TypeOf((*uint64)(nil))
    24  	f32PtrType  = reflect.TypeOf((*float32)(nil))
    25  	f64PtrType  = reflect.TypeOf((*float64)(nil))
    26  	strPtrType  = reflect.TypeOf((*string)(nil))
    27  )
    28  
    29  type sliceHeader struct {
    30  	Data unsafe.Pointer
    31  	Len  int
    32  	Cap  int
    33  }
    34  
    35  type stringHeader struct {
    36  	Data unsafe.Pointer
    37  	Len  int
    38  }
    39  
    40  type emptyInterface struct {
    41  	Type unsafe.Pointer
    42  	Data unsafe.Pointer
    43  }
    44  
    45  //go:linkname reflect_typedmemmove reflect.typedmemmove
    46  func reflect_typedmemmove(typ, dst, src unsafe.Pointer)
    47  
    48  func getg() unsafe.Pointer
    49  
    50  const g_goid_offset = 152
    51  
    52  func goRoutineId() uint64 {
    53  	g := getg()
    54  	p := (*int64)(unsafe.Pointer(uintptr(g) + g_goid_offset))
    55  	return uint64(*p)
    56  }
    57  
    58  func goRoutineIdSlow() uint64 {
    59  	var buf [64]byte
    60  	n := runtime.Stack(buf[:], false)
    61  	stk := strings.TrimPrefix(string(buf[:n]), "goroutine ")
    62  	if id, err := strconv.Atoi(strings.Fields(stk)[0]); err != nil {
    63  		panic(err)
    64  	} else {
    65  		return uint64(id)
    66  	}
    67  }
    68  
    69  // Helpers
    70  
    71  func add(p unsafe.Pointer, offset int) unsafe.Pointer {
    72  	return unsafe.Pointer(uintptr(p) + uintptr(offset))
    73  }
    74  
    75  //go:noinline
    76  func forceStackSplit(i int) int {
    77  	if i > 0 {
    78  		return forceStackSplit(i - 1)
    79  	}
    80  	return i
    81  }
    82  
    83  //go:noinline
    84  //go:nosplit
    85  func noEscape(p interface{}) (ret interface{}) {
    86  	r := *(*[2]uintptr)(unsafe.Pointer(&p))
    87  	//forceStackSplit(1000)
    88  	*(*[2]uintptr)(unsafe.Pointer(&ret)) = r
    89  	return
    90  }
    91  
    92  func data(i interface{}) unsafe.Pointer {
    93  	return (*emptyInterface)(unsafe.Pointer(&i)).Data
    94  }
    95  
    96  func copyBytes(src, dst unsafe.Pointer, len int) {
    97  	alignedEnd := len / ptrSize * ptrSize
    98  	i := 0
    99  	for ; i < alignedEnd; i += ptrSize {
   100  		*(*uintptr)(add(dst, i)) = *(*uintptr)(add(src, i))
   101  	}
   102  	for ; i < len; i++ {
   103  		*(*byte)(add(dst, i)) = *(*byte)(add(src, i))
   104  	}
   105  }
   106  
   107  func clearBytes(dst unsafe.Pointer, len int) {
   108  	alignedEnd := len / ptrSize * ptrSize
   109  	i := 0
   110  	for ; i < alignedEnd; i += ptrSize {
   111  		*(*uintptr)(add(dst, i)) = 0
   112  	}
   113  	for ; i < len; i++ {
   114  		*(*byte)(add(dst, i)) = 0
   115  	}
   116  }
   117  
   118  // syncPool
   119  
   120  type syncPool struct {
   121  	sync.Mutex
   122  	New  func() interface{}
   123  	pool []interface{}
   124  }
   125  
   126  func (p *syncPool) get() interface{} {
   127  	p.Lock()
   128  	defer p.Unlock()
   129  	if len(p.pool) == 0 {
   130  		return p.New()
   131  	}
   132  	r := p.pool[len(p.pool)-1]
   133  	p.pool = p.pool[:len(p.pool)-1]
   134  	return r
   135  }
   136  
   137  func (p *syncPool) put(v interface{}) {
   138  	p.Lock()
   139  	defer p.Unlock()
   140  	p.pool = append(p.pool, v)
   141  }
   142  
   143  func (p *syncPool) putMany(v interface{}) {
   144  	r := reflect.ValueOf(v)
   145  	p.Lock()
   146  	defer p.Unlock()
   147  	for i := 0; i < r.Len(); i++ {
   148  		p.pool = append(p.pool, r.Index(i).Interface())
   149  	}
   150  }
   151  
   152  func (p *syncPool) clear() {
   153  	p.Lock()
   154  	defer p.Unlock()
   155  	p.pool = nil
   156  }
   157  
   158  func (p *syncPool) reserve(cnt int) {
   159  	p.Lock()
   160  	defer p.Unlock()
   161  	for i := 0; i < cnt; i++ {
   162  		p.pool = append(p.pool, p.New())
   163  	}
   164  }