github.com/wfusion/gofusion@v1.1.14/common/utils/clone/allocator.go (about) 1 // Copyright 2023 Huan Du. All rights reserved. 2 // Licensed under the MIT license that can be found in the LICENSE file. 3 4 package clone 5 6 import ( 7 "reflect" 8 "runtime" 9 "sync" 10 "unsafe" 11 ) 12 13 var typeOfAllocator = reflect.TypeOf(Allocator{}) 14 15 // defaultAllocator is the default allocator and allocates memory from heap. 16 var defaultAllocator = &Allocator{ 17 new: heapNew, 18 makeSlice: heapMakeSlice, 19 makeMap: heapMakeMap, 20 makeChan: heapMakeChan, 21 isScalar: IsScalar, 22 } 23 24 // Allocator is a utility type for memory allocation. 25 type Allocator struct { 26 parent *Allocator 27 28 pool unsafe.Pointer 29 new func(pool unsafe.Pointer, t reflect.Type) reflect.Value 30 makeSlice func(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value 31 makeMap func(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value 32 makeChan func(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value 33 isScalar func(t reflect.Kind) bool 34 35 cachedStructTypes sync.Map 36 cachedPointerTypes sync.Map 37 cachedCustomFuncTypes sync.Map 38 } 39 40 // FromHeap creates an allocator which allocate memory from heap. 41 func fromHeap() *Allocator { 42 return newAllocator(nil, nil) 43 } 44 45 // NewAllocator creates an allocator which allocate memory from the pool. 46 // Both pool and methods are optional. 47 // 48 // If methods.New is not nil, the allocator itself is created by calling methods.New. 49 // 50 // The pool is a pointer to the memory pool which is opaque to the allocator. 51 // It's methods' responsibility to allocate memory from the pool properly. 52 func newAllocator(pool unsafe.Pointer, methods *AllocatorMethods) (allocator *Allocator) { 53 parent := methods.parent() 54 new := methods.new(parent, pool) 55 56 // Allocate the allocator from the pool. 57 val := new(pool, typeOfAllocator) 58 allocator = (*Allocator)(unsafe.Pointer(val.Pointer())) 59 runtime.KeepAlive(val) 60 61 allocator.pool = pool 62 allocator.new = new 63 allocator.makeSlice = methods.makeSlice(parent, pool) 64 allocator.makeMap = methods.makeMap(parent, pool) 65 allocator.makeChan = methods.makeChan(parent, pool) 66 allocator.isScalar = methods.isScalar(parent) 67 68 if parent == nil { 69 parent = defaultAllocator 70 } 71 72 allocator.parent = parent 73 return 74 } 75 76 // New returns a new zero value of t. 77 func (a *Allocator) New(t reflect.Type) reflect.Value { 78 return a.new(a.pool, t) 79 } 80 81 // MakeSlice creates a new zero-initialized slice value of t with len and cap. 82 func (a *Allocator) MakeSlice(t reflect.Type, len, cap int) reflect.Value { 83 return a.makeSlice(a.pool, t, len, cap) 84 } 85 86 // MakeMap creates a new map with minimum size n. 87 func (a *Allocator) MakeMap(t reflect.Type, n int) reflect.Value { 88 return a.makeMap(a.pool, t, n) 89 } 90 91 // MakeChan creates a new chan with buffer. 92 func (a *Allocator) MakeChan(t reflect.Type, buffer int) reflect.Value { 93 return a.makeChan(a.pool, t, buffer) 94 } 95 96 // Clone recursively deep clone val to a new value with memory allocated from a. 97 func (a *Allocator) Clone(val reflect.Value) reflect.Value { 98 return a.clone(val, true) 99 } 100 101 func (a *Allocator) clone(val reflect.Value, inCustomFunc bool) reflect.Value { 102 if !val.IsValid() { 103 return val 104 } 105 106 state := &cloneState{ 107 allocator: a, 108 } 109 110 if inCustomFunc { 111 state.skipCustomFuncValue = val 112 } 113 114 return state.clone(val) 115 } 116 117 // CloneSlowly recursively deep clone val to a new value with memory allocated from a. 118 // It marks all cloned values internally, thus it can clone v with cycle pointer. 119 func (a *Allocator) CloneSlowly(val reflect.Value) reflect.Value { 120 return a.cloneSlowly(val, true) 121 } 122 123 func (a *Allocator) cloneSlowly(val reflect.Value, inCustomFunc bool) reflect.Value { 124 if !val.IsValid() { 125 return val 126 } 127 128 state := &cloneState{ 129 allocator: a, 130 visited: visitMap{}, 131 invalid: invalidPointers{}, 132 } 133 134 if inCustomFunc { 135 state.skipCustomFuncValue = val 136 } 137 138 cloned := state.clone(val) 139 state.fix(cloned) 140 return cloned 141 } 142 143 func (a *Allocator) loadStructType(t reflect.Type) (st structType) { 144 st, ok := a.lookupStructType(t) 145 146 if ok { 147 return 148 } 149 150 num := t.NumField() 151 pointerFields := make([]structFieldType, 0, num) 152 153 // Find pointer fields in depth-first order. 154 for i := 0; i < num; i++ { 155 field := t.Field(i) 156 ft := field.Type 157 k := ft.Kind() 158 159 if a.isScalar(k) { 160 continue 161 } 162 163 switch k { 164 case reflect.Array: 165 if ft.Len() == 0 { 166 continue 167 } 168 169 elem := ft.Elem() 170 171 if a.isScalar(elem.Kind()) { 172 continue 173 } 174 175 if elem.Kind() == reflect.Struct { 176 if fst := a.loadStructType(elem); fst.CanShadowCopy() { 177 continue 178 } 179 } 180 case reflect.Struct: 181 if fst := a.loadStructType(ft); fst.CanShadowCopy() { 182 continue 183 } 184 } 185 186 pointerFields = append(pointerFields, structFieldType{ 187 Offset: field.Offset, 188 Index: i, 189 }) 190 } 191 192 if len(pointerFields) == 0 { 193 pointerFields = nil // Release memory ASAP. 194 } 195 196 st = structType{ 197 PointerFields: pointerFields, 198 } 199 200 // Load custom function. 201 current := a 202 203 for current != nil { 204 if fn, ok := current.cachedCustomFuncTypes.Load(t); ok { 205 st.fn = fn.(Func) 206 break 207 } 208 209 current = current.parent 210 } 211 212 a.cachedStructTypes.LoadOrStore(t, st) 213 return 214 } 215 216 func (a *Allocator) lookupStructType(t reflect.Type) (st structType, ok bool) { 217 var v interface{} 218 current := a 219 220 for current != nil { 221 v, ok = current.cachedStructTypes.Load(t) 222 223 if ok { 224 st = v.(structType) 225 return 226 } 227 228 current = current.parent 229 } 230 231 return 232 } 233 234 func (a *Allocator) isOpaquePointer(t reflect.Type) (ok bool) { 235 current := a 236 237 for current != nil { 238 if _, ok = current.cachedPointerTypes.Load(t); ok { 239 return 240 } 241 242 current = current.parent 243 } 244 245 return 246 } 247 248 // MarkAsScalar marks t as a scalar type so that all clone methods will copy t by value. 249 // If t is not struct or pointer to struct, MarkAsScalar ignores t. 250 // 251 // In the most cases, it's not necessary to call it explicitly. 252 // If a struct type contains scalar type fields only, the struct will be marked as scalar automatically. 253 // 254 // Here is a list of types marked as scalar by default: 255 // - time.Time 256 // - reflect.Value 257 func (a *Allocator) MarkAsScalar(t reflect.Type) { 258 t = indirectType(t) 259 if t.Kind() != reflect.Struct { 260 return 261 } 262 263 a.cachedStructTypes.Store(t, zeroStructType) 264 } 265 266 // MarkAsOpaquePointer marks t as an opaque pointer so that all clone methods will copy t by value. 267 // If t is not a pointer, MarkAsOpaquePointer ignores t. 268 // 269 // Here is a list of types marked as opaque pointers by default: 270 // - `elliptic.Curve`, which is `*elliptic.CurveParam` or `elliptic.p256Curve`; 271 // - `reflect.Type`, which is `*reflect.rtype` defined in `runtime`. 272 func (a *Allocator) MarkAsOpaquePointer(t reflect.Type) { 273 if t.Kind() != reflect.Ptr { 274 return 275 } 276 277 a.cachedPointerTypes.Store(t, struct{}{}) 278 } 279 280 // SetCustomFunc sets a custom clone function for type t. 281 // If t is not struct or pointer to struct, SetCustomFunc ignores t. 282 // 283 // If fn is nil, remove the custom clone function for type t. 284 func (a *Allocator) SetCustomFunc(t reflect.Type, fn Func) { 285 if fn == nil { 286 a.cachedCustomFuncTypes.Delete(t) 287 return 288 } 289 290 t = indirectType(t) 291 if t.Kind() != reflect.Struct { 292 return 293 } 294 295 a.cachedCustomFuncTypes.Store(t, fn) 296 } 297 298 func heapNew(pool unsafe.Pointer, t reflect.Type) reflect.Value { 299 return reflect.New(t) 300 } 301 302 func heapMakeSlice(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value { 303 return reflect.MakeSlice(t, len, cap) 304 } 305 306 func heapMakeMap(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value { 307 return reflect.MakeMapWithSize(t, n) 308 } 309 310 func heapMakeChan(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value { 311 return reflect.MakeChan(t, buffer) 312 }