add arena.ExtendSlice; add tests
This commit is contained in:
parent
5a76937255
commit
5579115eb4
4 changed files with 88 additions and 4 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package arena
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"git.brut.systems/judah/xx/mem"
|
||||
|
|
@ -36,6 +37,30 @@ func MakeSlice[T any](arena Arena, len, cap int) []T {
|
|||
return unsafe.Slice((*T)(ptr), cap)[:len]
|
||||
}
|
||||
|
||||
// ExtendSlice returns a slice pointing to the same underlying memory
|
||||
// but with an increased capacity.
|
||||
//
|
||||
// Note: If extending the slice results in non-contiguous memory, ExtendSlice will panic.
|
||||
func ExtendSlice[T any](arena Arena, slice []T, newcap int) []T {
|
||||
if cap(slice) >= newcap {
|
||||
return slice
|
||||
}
|
||||
|
||||
count := newcap - cap(slice)
|
||||
ptr, err := arena(ACTION_ALLOC, mem.Sizeof[T]()*uintptr(count), mem.Alignof[T](), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
base := uintptr(unsafe.Pointer(unsafe.SliceData(slice)))
|
||||
expected := base + uintptr(cap(slice)*int(mem.Sizeof[T]()))
|
||||
if uintptr(ptr) != expected {
|
||||
panic(fmt.Sprintf("extendslice: extension of %d was non-contiguous (%d vs %d)", count, uintptr(ptr), expected))
|
||||
}
|
||||
|
||||
return unsafe.Slice((*T)(unsafe.SliceData(slice)), newcap)[:len(slice)]
|
||||
}
|
||||
|
||||
// Reset restores an Arena to its initial state.
|
||||
//
|
||||
// Note: Accessing memory returned by an Arena after calling Reset is unsafe and may result in a fault.
|
||||
|
|
|
|||
|
|
@ -28,3 +28,20 @@ func TestMakeSlice(t *testing.T) {
|
|||
|
||||
testx.Expect(t, p != &s[0], "p = %p, expected %p", p, &s[0])
|
||||
}
|
||||
|
||||
func TestExtendSlice(t *testing.T) {
|
||||
a := arena.Linear(1024 * mem.Kilobyte)
|
||||
defer arena.Reset(a)
|
||||
|
||||
s := arena.MakeSlice[int](a, 0, 5)
|
||||
testx.Expect(t, cap(s) == 5)
|
||||
|
||||
s = arena.ExtendSlice(a, s, cap(s)+2)
|
||||
testx.Expect(t, cap(s) == 7)
|
||||
|
||||
testx.ShouldPanic(t, func() {
|
||||
// cause a non-contiguous slice extension (which will panic)
|
||||
_ = arena.New[int](a)
|
||||
s = arena.ExtendSlice(a, s, cap(s)*2)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,10 +72,8 @@ func Copy(dst, src unsafe.Pointer, size uintptr) unsafe.Pointer {
|
|||
//
|
||||
// Returns dst.
|
||||
func Clear(dst unsafe.Pointer, value byte, count uintptr) unsafe.Pointer {
|
||||
b := (*byte)(dst)
|
||||
for range count {
|
||||
*b = value
|
||||
b = (*byte)(unsafe.Add(unsafe.Pointer(b), 1))
|
||||
for i := range count {
|
||||
*(*byte)(unsafe.Add(unsafe.Pointer(dst), i)) = value
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,50 @@ func TestBitCast(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMemoryPrimitives(t *testing.T) {
|
||||
t.Run("copy", func(t *testing.T) {
|
||||
{ // non-overlapping
|
||||
a := []int{1, 2, 3, 4, 5, 6}
|
||||
b := make([]int, 3)
|
||||
mem.Copy(unsafe.Pointer(&b[0]), unsafe.Pointer(&a[0]), uintptr(len(b))*unsafe.Sizeof(int(0)))
|
||||
|
||||
for i := range len(b) {
|
||||
testx.Expect(t, a[i] == b[i], "%d != %d [%d]", a[i], b[i], i)
|
||||
}
|
||||
}
|
||||
|
||||
{ // overlapping
|
||||
a := []int{1, 2, 3, 4, 5}
|
||||
b := &a[0]
|
||||
mem.Copy(unsafe.Pointer(b), unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(int(0)))
|
||||
|
||||
for i := range len(a) {
|
||||
testx.Expect(t, a[i] == i+1, "[%d] %d != %d", i, a[i], i+1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("clear", func(t *testing.T) {
|
||||
{ // zero
|
||||
v := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
mem.Clear(unsafe.Pointer(&v[0]), 0, uintptr(len(v))*unsafe.Sizeof(int(0)))
|
||||
|
||||
for i := range len(v) {
|
||||
testx.Expect(t, v[i] == 0, "[%d] %d != 0", i, v[i])
|
||||
}
|
||||
}
|
||||
|
||||
{ // fill
|
||||
v := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
mem.Clear(unsafe.Pointer(&v[0]), 0xFF, uintptr(len(v))*unsafe.Sizeof(int(0)))
|
||||
|
||||
for i := range len(v) {
|
||||
testx.Expect(t, v[i] == 0xFF, "[%d] %d != 0xFF", i, v[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAllocationPrimitives(t *testing.T) {
|
||||
t.Run("reserve, unreserve", func(t *testing.T) {
|
||||
data, err := mem.Reserve(1 * mem.Gigabyte)
|
||||
|
|
|
|||
Loading…
Reference in a new issue