Skip to content

Instantly share code, notes, and snippets.

@sug0
Last active January 12, 2019 23:57
Show Gist options
  • Select an option

  • Save sug0/128e25b474cae2a61266e4e673de9d7d to your computer and use it in GitHub Desktop.

Select an option

Save sug0/128e25b474cae2a61266e4e673de9d7d to your computer and use it in GitHub Desktop.
Very simple Go allocator
package main
/*
typedef struct {
int x, y;
} Point;
void init_pt(Point *p, int x, int y)
{
p->x = x;
p->y = y;
}
*/
import "C"
import (
"fmt"
"unsafe"
"malloc"
)
func main() {
size := uint64(unsafe.Sizeof(C.Point{}))
blk := malloc.Allocate(size)
defer blk.Free()
p := (*C.Point)(blk.Pointer())
C.init_pt(p, 2, 3)
fmt.Printf("%+v (%d)\n", p, cap(blk))
}
package malloc
import (
"sync"
"unsafe"
)
// Represents an allocated block of memory.
type Block []byte
// Returns an allocated block of memory with a capacity equivalent
// to the ceiling of the closest power of two to n. Ideally you
// should return it to the pool of free blocks with Free().
func Allocate(n uint64) Block {
blk := buckets[ulog2(n)].Get().(Block)
return blk[:n]
}
// Grow a block by delta bytes. This operation may lose the
// reference to the original block, so consider calling
// Pointer() again.
func (b *Block) Grow(delta uint64) {
n := b.Len64() + delta
if n > b.Cap64() {
newblk := Allocate(n)
copy(newblk, *b)
b.Free()
*b = newblk
return
}
*b = (*b)[:n]
}
// Length of a block. Returns a uint64.
func (b Block) Len64() uint64 {
return uint64(len(b))
}
// Capacity of a block. Returns a uint64.
func (b Block) Cap64() uint64 {
return uint64(cap(b))
}
// Returns a block to the pool of free blocks. The capacity
// should be a power of two.
func (b Block) Free() {
buckets[ulog2(b.Cap64())].Put(b)
}
// Returns a pointer to the allocated region.
func (b Block) Pointer() unsafe.Pointer {
return unsafe.Pointer(&b[0])
}
func ulog2(x uint64) uint64 {
var k, y, j uint64
if x & (x - 1) == 0 {
y = 0
} else {
y = 1
}
j = 32
for i := 0; i < 6; i++ {
if x & ceil_t[i] == 0 {
k = 0
} else {
k = j
}
y += k
x >>= k
j >>= 1
}
return y
}
var ceil_t = [...]uint64{
0xFFFFFFFF00000000,
0x00000000FFFF0000,
0x000000000000FF00,
0x00000000000000F0,
0x000000000000000C,
0x0000000000000002,
}
var buckets = [...]sync.Pool{
sync.Pool{},
sync.Pool{New: func() interface{} { return make(Block, 2) }},
sync.Pool{New: func() interface{} { return make(Block, 4) }},
sync.Pool{New: func() interface{} { return make(Block, 8) }},
sync.Pool{New: func() interface{} { return make(Block, 16) }},
sync.Pool{New: func() interface{} { return make(Block, 32) }},
sync.Pool{New: func() interface{} { return make(Block, 64) }},
sync.Pool{New: func() interface{} { return make(Block, 128) }},
sync.Pool{New: func() interface{} { return make(Block, 256) }},
sync.Pool{New: func() interface{} { return make(Block, 512) }},
sync.Pool{New: func() interface{} { return make(Block, 1024) }},
sync.Pool{New: func() interface{} { return make(Block, 2048) }},
sync.Pool{New: func() interface{} { return make(Block, 4096) }},
sync.Pool{New: func() interface{} { return make(Block, 8192) }},
sync.Pool{New: func() interface{} { return make(Block, 16384) }},
sync.Pool{New: func() interface{} { return make(Block, 32768) }},
sync.Pool{New: func() interface{} { return make(Block, 65536) }},
sync.Pool{New: func() interface{} { return make(Block, 131072) }},
sync.Pool{New: func() interface{} { return make(Block, 262144) }},
sync.Pool{New: func() interface{} { return make(Block, 524288) }},
sync.Pool{New: func() interface{} { return make(Block, 1048576) }},
sync.Pool{New: func() interface{} { return make(Block, 2097152) }},
sync.Pool{New: func() interface{} { return make(Block, 4194304) }},
sync.Pool{New: func() interface{} { return make(Block, 8388608) }},
sync.Pool{New: func() interface{} { return make(Block, 16777216) }},
sync.Pool{New: func() interface{} { return make(Block, 33554432) }},
sync.Pool{New: func() interface{} { return make(Block, 67108864) }},
sync.Pool{New: func() interface{} { return make(Block, 134217728) }},
sync.Pool{New: func() interface{} { return make(Block, 268435456) }},
sync.Pool{New: func() interface{} { return make(Block, 536870912) }},
sync.Pool{New: func() interface{} { return make(Block, 1073741824) }},
sync.Pool{New: func() interface{} { return make(Block, 2147483648) }},
sync.Pool{New: func() interface{} { return make(Block, 4294967296) }},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment