Compare commits

...

2 commits

Author SHA1 Message Date
41b74c5b14 todo: fix unions or remove them 2026-01-09 16:54:20 -07:00
4722e6a61f additions 2026-01-09 16:54:10 -07:00
5 changed files with 56 additions and 38 deletions

View file

@ -63,7 +63,6 @@ func (x *Xar[T]) AppendMany(values ...T) *T {
}
first := x.Append(values[0])
if len(values) > 1 {
for _, v := range values[1:] {
x.Append(v)

View file

@ -40,6 +40,13 @@ func BitCast[TOut any, TIn any](value *TIn) TOut {
return *((*TOut)(unsafe.Pointer(value)))
}
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)))
}
// Copy copies size number of bytes from src into dst.
//
// Returns dst.

View file

@ -14,7 +14,9 @@
// }
package osthread
import "runtime"
import (
"runtime"
)
// Start allows arbitrary functions to be run on the main operating system thread.
//
@ -24,14 +26,14 @@ func Start(entrypoint func()) {
done := make(chan any)
// Run entrypoint in a separate goroutine.
go func() {
// Immediately queue entrypoint
Go(func() {
defer func() {
done <- nil
}()
entrypoint()
}()
})
// Call functions in our queue until entrypoint returns.
// These functions are called on the main operating system thread.

View file

@ -36,7 +36,7 @@ type anystruct any
// float32
// })
type Of[T anystruct] struct {
typ reflect.Kind
typ reflect.Type
mem []byte
}
@ -47,39 +47,25 @@ func (u Of[T]) Size() uintptr {
// String returns the string representation of a union.
func (u Of[T]) String() string {
var b strings.Builder
b.WriteString("union[")
if u.typ == reflect.Invalid {
fmt.Fprintf(&b, "union[%s] = ", reflect.TypeFor[T]().String())
if u.typ == nil {
b.WriteString("none")
} else {
b.WriteString(u.typ.String())
}
b.WriteString("] {")
t := reflect.TypeFor[T]()
if t.Kind() == reflect.Struct {
b.WriteByte(' ')
fields := getInternalFields(u)
for i, field := range fields {
b.WriteString(field.Type.String())
if i < len(fields)-1 {
b.WriteString("; ")
}
}
b.WriteByte(' ')
}
b.WriteByte('}')
return b.String()
}
// Is returns true if the given type is currently stored in the union.
func Is[E any, T anystruct](u Of[T]) bool {
// Explicit invalid check to make sure invalid types don't result in false-positives.
if u.typ == reflect.Invalid {
if u.typ == nil {
return false
}
return u.typ == reflect.TypeFor[E]().Kind()
return u.typ == reflect.TypeFor[E]()
}
// Set overwrites the backing memory of a union with the given value; initializing the union if uninitialized.
@ -91,8 +77,8 @@ func Set[V any, T anystruct](u *Of[T], value V) {
u.mem = make([]byte, mem.Sizeof[T]())
}
*(*V)(unsafe.Pointer(&u.mem[0])) = value
u.typ = reflect.TypeFor[V]().Kind()
unsafe.Slice((*V)(unsafe.Pointer(&u.mem[0])), 1)[0] = value
u.typ = reflect.TypeFor[V]()
}
// SetSafe overwrites the backing memory of a union with the given value,
@ -107,8 +93,8 @@ func SetSafe[V any, T anystruct](u *Of[T], value V) error {
vt := reflect.TypeFor[V]()
for _, field := range getInternalFields(*u) {
if field.Type == vt {
*(*V)(unsafe.Pointer(&u.mem[0])) = value
u.typ = reflect.TypeFor[V]().Kind()
unsafe.Slice((*V)(unsafe.Pointer(&u.mem[0])), 1)[0] = value
u.typ = reflect.TypeFor[V]()
return nil
}
}
@ -125,7 +111,7 @@ func Get[V any, T anystruct](u Of[T]) V {
panic(ErrUninitializedAccess)
}
return *(*V)(unsafe.Pointer(&u.mem[0]))
return unsafe.Slice((*V)(unsafe.Pointer(&u.mem[0])), 1)[0]
}
// GetSafe returns the union's backing memory interpreted as a value of type V, returning an error if the type
@ -140,7 +126,7 @@ func GetSafe[V any, T anystruct](u Of[T]) (V, error) {
vt := reflect.TypeFor[V]()
for _, field := range getInternalFields(u) {
if field.Type == vt {
return *(*V)(unsafe.Pointer(&u.mem[0])), nil
return unsafe.Slice((*V)(unsafe.Pointer(&u.mem[0])), 1)[0], nil
}
}

38
xx.go
View file

@ -1,18 +1,13 @@
package xx
import (
"runtime"
"strings"
"unsafe"
"git.brut.systems/judah/xx/mem"
)
// New returns a newly allocated value with an initial value.
func New[T any](expr T) *T {
p := new(T)
*p = expr
return p
}
// Copy copies src number of bytes into dst.
// Returns dst.
//
@ -34,3 +29,32 @@ func Clone[T any](value *T) *T {
func BoolUint(b bool) uint {
return uint(*(*uint8)(unsafe.Pointer(&b)))
}
// CallerLocation returns the source location of the function CallerLocation is called in.
func CallerLocation() (file string, line int) {
_, file, line, _ = runtime.Caller(2)
// @todo: I'm sure there's a better way to do this
// Special-case when CallerLocation is called from main
if strings.Contains(file, "runtime") && strings.Contains(file, "proc.go") {
_, file, line, _ = runtime.Caller(1)
}
return
}
// HashLocation returns a hash of file and line, most likely returned from [CallerLocation].
func HashLocation(file string, line int) uint64 {
const (
FNV64_PRIME uint64 = 0x100000001B3
FNV64_BIAS uint64 = 0xCBF29CE484222325
)
h := FNV64_BIAS
for _, c := range file {
h = (h ^ uint64(c)) * FNV64_PRIME
}
h = (h ^ uint64(line)) * FNV64_PRIME
return h
}