xx/mem/mem.go

112 lines
3.3 KiB
Go

package mem
import (
"unsafe"
)
const (
Kilobyte uintptr = 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(dst, 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
}