package arena import ( "unsafe" "git.brut.systems/judah/xx/mem" ) // New returns a pointer to an Arena allocated value of type T. // If allocation fails, New will panic. // // Note: Accessing the returned value after calling Reset is unsafe and may result in a fault. func New[T any](arena Arena) *T { ptr, err := arena(ACTION_ALLOC, mem.Sizeof[T](), mem.Alignof[T](), nil) if err != nil { panic(err) } return (*T)(ptr) } // MakeSlice creates an Arena allocated []T with the given capacity and length. // If allocation fails, MakeSlice will panic. // // Note: Accessing the returned slice after calling Reset is unsafe and may result in a fault. func MakeSlice[T any](arena Arena, len, cap int) []T { ptr, err := arena(ACTION_ALLOC, mem.Sizeof[T]()*uintptr(len), mem.Alignof[T](), nil) if err != nil { panic(err) } return unsafe.Slice((*T)(ptr), cap)[:len] } // Reset restores an Arena to its initial state. // // Note: Accessing memory returned by an Arena after calling Reset is unsafe and may result in a fault. func Reset(arena Arena) { if _, err := arena(ACTION_RESET, 0, 0, nil); err != nil { panic(err) } } // Save returns the restorable state of an Arena. // The returned value is internal to the particular Arena and should not be modified. func Save(arena Arena) (watermark uintptr) { if _, err := arena(ACTION_SAVE, 0, 0, &watermark); err != nil { panic(err) } return } // Restore restores an Arena to a previously saved state. func Restore(arena Arena, watermark uintptr) { if _, err := arena(ACTION_RESTORE, 0, 0, &watermark); err != nil { panic(err) } } // Arena represents a memory allocator. type Arena func(a Action, size, align uintptr, watermark *uintptr) (unsafe.Pointer, error) // Action is a list of distinct events an Arena may respond to. type Action int const ( ACTION_ALLOC Action = iota ACTION_RESET ACTION_SAVE ACTION_RESTORE ) func (a Action) String() string { switch a { case ACTION_ALLOC: return "ALLOC" case ACTION_RESET: return "RESET" case ACTION_SAVE: return "SAVE" case ACTION_RESTORE: return "RESTORE" default: panic("unreachable") } }