1
0
Fork 0
forked from judah/xx
xx/mem/mem.go
2026-02-11 02:51:20 +00:00

154 lines
4.8 KiB
Go

package mem
import (
"unsafe"
)
const (
Kilobyte = 1 << (10 * (iota + 1))
Megabyte
Gigabyte
Terabyte
)
// Sizeof returns the size (in bytes) of the given type.
//
// Not to be confused with [unsafe.Sizeof] which returns the size of a type via an expression.
func Sizeof[T any]() uintptr {
return unsafe.Sizeof(*(*T)(nil))
}
// Alignof returns the alignment (in bytes) of the given type.
//
// Not to be confused with [unsafe.AlignOf] which returns the alignment of a type via an expression.
func Alignof[T any]() uintptr {
return unsafe.Alignof(*(*T)(nil))
}
// ZeroValue returns the zero value of a given type.
func ZeroValue[T any]() (_ T) {
return
}
// BitCast performs a bit conversion between two types of the same size.
//
// BitCast panics if the sizes of the types differ.
func BitCast[TOut any, TIn any](value *TIn) TOut {
if Sizeof[TOut]() != Sizeof[TIn]() {
panic("bitcast: sizes of types must match")
}
return *((*TOut)(unsafe.Pointer(value)))
}
// BitCastValue performs a bit conversion between two types of the same size.
//
// BitCastValue panics if the sizes of the types differ.
func BitCastValue[TOut any, TIn any](value TIn) TOut {
if Sizeof[TOut]() != Sizeof[TIn]() {
panic("bitcast: sizes of types must match")
}
return *((*TOut)(unsafe.Pointer(&value)))
}
// UnsafeCast performs a bit conversion between two types without checking if their sizes match.
func UnsafeCast[TOut any, TIn any](value *TIn) TOut {
return *((*TOut)(unsafe.Pointer(value)))
}
// UnsafeCastValue performs a bit conversion between two types without checking if their sizes match.
func UnsafeCastValue[TOut any, TIn any](value TIn) TOut {
return *((*TOut)(unsafe.Pointer(&value)))
}
// Copy copies size number of bytes from src into dst.
//
// Returns dst.
func Copy(dst, src unsafe.Pointer, size uintptr) unsafe.Pointer {
copy(unsafe.Slice((*byte)(dst), size), unsafe.Slice((*byte)(src), size))
return dst
}
// Clear overwrites 'count' number of bytes in 'dst' with a particular value.
//
// Returns dst.
func Clear(dst unsafe.Pointer, value byte, count uintptr) unsafe.Pointer {
b := (*byte)(dst)
for range count { // @todo: loop unroll/maybe use asm?
*b = value
b = (*byte)(unsafe.Add(b, 1))
}
return dst
}
// Zero overwrites 'count' number of bytes in 'dst' with zeros.
//
// Returns dst.
func Zero(dst unsafe.Pointer, count uintptr) unsafe.Pointer {
return Clear(dst, 0, count)
}
// AlignForward returns an address align to the next power-of-two alignment.
func AlignForward(address uintptr, alignment uintptr) uintptr {
if alignment == 0 || (alignment&(alignment-1)) != 0 {
panic("alignforward: alignment must be a power of two")
}
return (address + alignment - 1) &^ (alignment - 1)
}
// AlignBackward returns an address align to the previous power-of-two alignment.
func AlignBackward(address uintptr, alignment uintptr) uintptr {
if alignment == 0 || (alignment&(alignment-1)) != 0 {
panic("alignbackward: alignment must be a power of two")
}
return address &^ (alignment - 1)
}
// Aligned returns if the address is aligned to the given power-of-two alignment.
func Aligned(address uintptr, alignment uintptr) bool {
if alignment == 0 || (alignment&(alignment-1)) != 0 {
panic("aligned: alignment must be a power of two")
}
return address&(alignment-1) == 0
}
// ExtendSlice returns a copy of the given slice, increasing its length, but leaving the capacity intact.
func ExtendSlice[T any](slice []T, amount uintptr) []T {
if amount+uintptr(len(slice)) > uintptr(cap(slice)) {
panic("extendslice: cannot extend slice past its capacity")
}
return slice[: uintptr(len(slice))+amount : cap(slice)]
}
// Access describes memory access permissions.
type Access int
const (
AccessNone Access = 1 << iota
AccessRead
AccessWrite
AccessExecute
)
// Reserve returns a slice of bytes pointing to uncommitted virtual memory.
// The length and capacity of the slice will be total_address_space bytes.
//
// The underlying memory of the slice must be comitted to phyiscal memory before being accessed (see: Commit).
//
// Use Release to return the virtual address space back to the operating system.
func Reserve(total_address_space uintptr) ([]byte, error) { return reserve(total_address_space) }
// Release returns reserved virtual address space back to the operating system.
//
// Note: Any committed memory within its address space will be freed as well.
func Release(reserved []byte) error { return release(reserved) }
// Commit maps virtual memory to physical memory.
func Commit(reserved []byte, access Access) error { return commit(reserved, access) }
// Decommit unmaps committed memory, leaving the underlying addresss space intact.
//
// Decommitted memory can be re-committed at a later time using Commit.
//
// Note: Accessing the memory after calling Decommit is unsafe and may cause a panic.
func Decommit(committed []byte) (err error) { return decommit(committed) }