xx/pointer/pinned.go

87 lines
1.6 KiB
Go

package pointer
import (
"runtime"
"unsafe"
"git.brut.systems/judah/xx/mem"
)
type Pinned[T any] struct {
base unsafe.Pointer
pinner runtime.Pinner
}
func Pin[T any](ptr *T) (r Pinned[T]) {
r.pinner.Pin(ptr)
r.base = unsafe.Pointer(ptr)
return
}
func Cast[TOut, TIn any](p Pinned[TIn]) Pinned[TOut] {
return Pinned[TOut]{
base: unsafe.Pointer(p.base),
pinner: p.pinner,
}
}
func (p Pinned[T]) Unpin() {
p.pinner.Unpin()
p.base = nil
}
func (p Pinned[T]) Pointer() unsafe.Pointer {
return p.base
}
func (p Pinned[T]) Address() uintptr {
return uintptr(p.base)
}
func (p Pinned[T]) Nil() bool {
return p.base == nil
}
func (p Pinned[T]) Add(amount uintptr) Pinned[T] {
return Pinned[T]{
base: unsafe.Pointer(uintptr(p.base) + amount),
pinner: p.pinner,
}
}
func (p Pinned[T]) Sub(amount uintptr) Pinned[T] {
return Pinned[T]{
base: unsafe.Pointer(uintptr(p.base) - amount),
pinner: p.pinner,
}
}
func (p Pinned[T]) Aligned() bool {
return mem.Aligned(uintptr(p.base), mem.AlignOf[T]())
}
func (p Pinned[T]) AlignForward() Pinned[T] {
return Pinned[T]{
base: unsafe.Pointer(mem.AlignForward(uintptr(p.base), mem.AlignOf[T]())),
pinner: p.pinner,
}
}
func (p Pinned[T]) AlignBackward() Pinned[T] {
return Pinned[T]{
base: unsafe.Pointer(mem.AlignBackward(uintptr(p.base), mem.AlignOf[T]())),
pinner: p.pinner,
}
}
func (p Pinned[T]) Load() T {
return *(*T)(p.base)
}
func (p Pinned[T]) Store(value T) {
*(*T)(p.base) = value
}
func (p Pinned[T]) Nth(index int) T {
return p.Add(uintptr(index) * mem.SizeOf[T]()).Load()
}