Files
lneto/internal/slices.go
T
Pat Whittingslow 989bb6a0b9 Reduce heap allocs 2 (#46)
* reduce heap allocations in tcp logging; omit use of AppendFloat which allocates a metric sh*tton

* debugheaplog: better heap statistic logging

* heap: use string for pcap.Frame.Protocol

* add potential to eliminate Flags.String heap alloc, remove incorrect HEAP comments

* add StackAsync.DebugErr and httpraw.SetBytes

* many heap alloc reductions and replacement of bytes.Equal with internal.BytesEqual
2026-02-28 15:20:46 -03:00

82 lines
2.1 KiB
Go

package internal
import "unsafe"
// IsZeroed returns true if all arguments are set to their zero value.
func IsZeroed[T comparable](a ...T) bool {
var z T
for i := range a {
if a[i] != z {
return false
}
}
return true
}
// DeleteZeroed deletes zero values in-place contained within the
// slice and returns the modified slice without zero values.
// Does not modify capacity.
func DeleteZeroed[T comparable](a []T) []T {
var z T
off := 0
deleted := false
for i := 0; i < len(a); i++ {
if a[i] != z {
if deleted {
a[off] = a[i]
}
off++
} else if !deleted {
deleted = true
}
}
return a[:off]
}
// SliceReuse prepares a slice for reuse with capacity at least n.
// After calling SliceReuse, the slice will have:
// - length = 0
// - capacity >= n (exactly n if a new allocation was needed)
//
// This function provides specified behavior unlike [slices.Grow] which
// has unspecified capacity growth behavior that differs between Go and TinyGo.
// Use this when the exact capacity matters for subsequent logic.
func SliceReuse[T any](buf *[]T, n int) {
if cap(*buf) < n {
*buf = make([]T, 0, n)
} else {
*buf = (*buf)[:0]
}
}
// SliceReclaim extends the slice length by one and returns a pointer to
// the new last element. The returned element is not zeroed, so callers
// can reuse any existing allocations it may hold from prior use.
//
// Beware: as the name implies SliceReclaim reuses previously held memory
// so it is up to caller to ensure the reclaimed data is coherent by zeroing out
// the needed fields and reusing the previously held slices or pointers responsibly.
func SliceReclaim[T any](ptr *[]T) *T {
b := *ptr
n := len(b)
if n == cap(b) {
var z T
*ptr = append(b, z)
} else {
*ptr = b[:n+1]
}
return &(*ptr)[n]
}
// BytesEqual is heapless replacement of [bytes.Equal] since it allocates in tinygo.
// https://github.com/tinygo-org/tinygo/issues/4045
func BytesEqual(a, b []byte) bool {
if len(a) != len(b) {
return false
}
if len(a) == 0 {
return true
}
return unsafe.String(&a[0], len(a)) == unsafe.String(&b[0], len(b))
}