Last active
January 12, 2019 23:57
-
-
Save sug0/128e25b474cae2a61266e4e673de9d7d to your computer and use it in GitHub Desktop.
Very simple Go allocator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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