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 }