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 }