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  }