Files

101 lines
2.0 KiB
Go

package main
import (
"errors"
"fmt"
"math"
"unsafe"
)
const headerSize = 2
type StackAllocator struct {
data []byte
}
func NewStackAllocator(capacity int) (StackAllocator, error) {
if capacity <= 0 {
return StackAllocator{}, errors.New("incorrect capacity")
}
return StackAllocator{
data: make([]byte, 0, capacity),
}, nil
}
func (a *StackAllocator) Allocate(size int) (unsafe.Pointer, error) {
if size > math.MaxInt16 {
// can increase header size
return nil, errors.New("incorrect size")
}
previousLength := len(a.data)
newLength := previousLength + headerSize + size
if newLength > cap(a.data) {
// can increase capacity
return nil, errors.New("not enough memory")
}
a.data = a.data[:newLength]
header := unsafe.Pointer(&a.data[previousLength])
pointer := unsafe.Pointer(&a.data[previousLength+headerSize])
*(*int16)(header) = int16(size)
return pointer, nil
}
func (a *StackAllocator) Deallocate(pointer unsafe.Pointer) error {
// can deallocate without pointer
if pointer == nil {
return errors.New("incorrect pointer")
}
header := unsafe.Add(pointer, -headerSize)
size := *(*int16)(header)
previousLength := len(a.data)
newLength := previousLength - headerSize - int(size)
a.data = a.data[:newLength]
return nil
}
func (a *StackAllocator) Free() {
a.data = a.data[:0]
}
func store[T any](pointer unsafe.Pointer, value T) {
*(*T)(pointer) = value
}
func load[T any](pointer unsafe.Pointer) T {
return *(*T)(pointer)
}
func main() {
const KB = 1 << 10
allocator, err := NewStackAllocator(KB)
if err != nil {
// handling...
}
defer allocator.Free()
pointer1, _ := allocator.Allocate(2)
defer allocator.Deallocate(pointer1)
pointer2, _ := allocator.Allocate(4)
defer allocator.Deallocate(pointer2)
store[int16](pointer1, 100)
store[int32](pointer2, 200)
value1 := load[int16](pointer1)
value2 := load[int32](pointer2)
fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
fmt.Println("address1:", pointer1)
fmt.Println("address2:", pointer2)
}