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 }