github.com/moontrade/nogc@v0.1.7/alloc_std_18.go (about)

     1  //go:build generics
     2  
     3  package nogc
     4  
     5  import (
     6  	"sync/atomic"
     7  	"unsafe"
     8  )
     9  
    10  // RC is a reference count container. It utilizes atomic operations for count incr/decr.
    11  type RC[T any] struct {
    12  	ptr  PointerOf[T]
    13  	refs uintptr
    14  }
    15  
    16  func (rc *RC[T]) Unwrap() *T {
    17  	return rc.ptr.Unwrap()
    18  }
    19  
    20  func (rc *RC[T]) Close() error {
    21  	rc.Free()
    22  	return nil
    23  }
    24  
    25  func (rc *RC[T]) Free() bool {
    26  	if rc.ptr.Ptr == 0 {
    27  		return false
    28  	}
    29  	if atomic.AddUintptr(&rc.refs, ^uintptr(0)) == 0 {
    30  		rc.ptr.Free()
    31  		return true
    32  	}
    33  	return false
    34  }
    35  
    36  func (rc *RC[T]) Clone() *RC[T] {
    37  	atomic.AddUintptr(&rc.refs, 1)
    38  	return rc
    39  }
    40  
    41  func (rc *RC[T]) Scope(fn func(rc *RC[T])) {
    42  	if fn == nil {
    43  		return
    44  	}
    45  	atomic.AddUintptr(&rc.refs, 1)
    46  	defer atomic.AddUintptr(&rc.refs, ^uintptr(0))
    47  	fn(rc)
    48  }
    49  
    50  type RCPointer[T any] struct {
    51  	rc *RC[T]
    52  }
    53  
    54  func (rc *RCPointer[T]) Unwrap() *T {
    55  	return rc.rc.Unwrap()
    56  }
    57  
    58  func (rc RCPointer[T]) Clone() RCPointer[T] {
    59  	rc.rc.Clone()
    60  	return rc
    61  }
    62  
    63  func (rc *RCPointer[T]) Scope(fn func(rc *RC[T])) {
    64  	if fn == nil {
    65  		return
    66  	}
    67  	r := rc.rc
    68  	if r != nil {
    69  		rc.Scope(fn)
    70  	}
    71  }
    72  
    73  func (rc *RCPointer[T]) Close() error {
    74  	rc.Free()
    75  	return nil
    76  }
    77  
    78  func (rc *RCPointer[T]) Free() {
    79  	r := rc.rc
    80  	if r != nil && r.Free() {
    81  		Free(Pointer(unsafe.Pointer(rc.rc)))
    82  		rc.rc = nil
    83  	}
    84  }
    85  
    86  func NewRC[T any](p Pointer) *RC[T] {
    87  	return &RC[T]{ptr: PointerOf[T]{Ptr: p}, refs: 1}
    88  }
    89  
    90  func AllocRC[T any](p Pointer) RCPointer[T] {
    91  	a := Alloc(unsafe.Sizeof(RC[T]{}))
    92  	rc := (*RC[T])(a.Unsafe())
    93  	rc.ptr = PointerOf[T]{Ptr: p}
    94  	return RCPointer[T]{rc: rc}
    95  }
    96  
    97  // Dangling is a pointer that is owned elsewhere. It does not allow freeing. Generally,
    98  // it is advised to not store dangling pointers.
    99  type Dangling[T any] struct {
   100  	ptr Pointer
   101  }
   102  
   103  func (d Dangling[T]) IsNil() bool {
   104  	return d.ptr == 0
   105  }
   106  
   107  func (d *Dangling[T]) Unwrap() *T {
   108  	return (*T)(d.ptr.Unsafe())
   109  }
   110  
   111  func DanglingOf[T any](p Pointer) Dangling[T] {
   112  	return Dangling[T]{ptr: p}
   113  }
   114  
   115  // PointerOf is a typed Pointer.
   116  type PointerOf[T any] struct {
   117  	Ptr Pointer
   118  }
   119  
   120  func AllocZeroOf[T any]() PointerOf[T] {
   121  	var initial T
   122  	return PointerOf[T]{Ptr: AllocZeroed(unsafe.Sizeof(initial))}
   123  }
   124  
   125  // AllocOf is a convenience function to allocate a Go struct outside of Go GC territory.
   126  // Slight performance penalty given it requires a copy of initial struct by value in
   127  // goroutine stack memory. If inside extreme performance sensitive area then manually inline.
   128  func AllocOf[T any](initial T) PointerOf[T] {
   129  	// Alloc non-zeroed memory
   130  	p := PointerOf[T]{Ptr: Alloc(unsafe.Sizeof(initial))}
   131  	// Initialize memory
   132  	*p.Unwrap() = initial
   133  	return p
   134  }
   135  
   136  func PointerToOf[T any](p Pointer) PointerOf[T] {
   137  	return PointerOf[T]{Ptr: p}
   138  }
   139  
   140  func (p PointerOf[T]) Pointer() Pointer {
   141  	return p.Ptr
   142  }
   143  
   144  func (p *PointerOf[T]) Unwrap() *T {
   145  	return (*T)(p.Ptr.Unsafe())
   146  }
   147  
   148  func (p *PointerOf[T]) Free() {
   149  	if p.Ptr == 0 {
   150  		return
   151  	}
   152  	Free(p.Ptr)
   153  	p.Ptr = 0
   154  }
   155  
   156  func (p *PointerOf[T]) Close() error {
   157  	p.Free()
   158  	return nil
   159  }