github.com/urso/go-structform@v0.0.2/gotype/buffer.go (about) 1 package gotype 2 3 import ( 4 "sync" 5 "unsafe" 6 ) 7 8 var alignment = unsafe.Alignof((*uint32)(nil)) 9 10 var stridePool = sync.Pool{} 11 12 type buffer struct { 13 strides []stride 14 strides0 [8]stride 15 i int 16 17 preAlloc uintptr 18 } 19 20 type stride struct { 21 raw []byte 22 pos uintptr 23 } 24 25 func (b *buffer) init(alloc int) { 26 b.strides = b.strides0[:1] 27 b.preAlloc = uintptr(alloc) 28 b.i = 0 29 30 s := &b.strides[0] 31 s.raw = b.allocStride() 32 s.pos = 0 33 } 34 35 func (b *buffer) allocStride() []byte { 36 if bytesIfc := stridePool.Get(); bytesIfc != nil { 37 return bytesIfc.([]byte) 38 } 39 return make([]byte, b.preAlloc) 40 } 41 42 func (b *buffer) alloc(sz int) unsafe.Pointer { 43 // align 'sz' to next for bytes after 'sz' 44 aligned := (((uintptr(sz) + (alignment - 1)) / alignment) * alignment) 45 total := aligned + alignment 46 47 mem := b.doAlloc(total) 48 49 szPtr := (*uint32)(unsafe.Pointer(&mem[aligned])) 50 *szPtr = uint32(total) 51 return unsafe.Pointer(&mem[0]) 52 } 53 54 func (b *buffer) release() { 55 s := &b.strides[b.i] 56 if s.pos == 0 { 57 panic("release of unallocated memory") 58 } 59 60 szPtr := (*uint32)(unsafe.Pointer(&s.raw[s.pos-alignment])) 61 sz := uintptr(*szPtr) 62 63 s.pos -= sz 64 if s.pos == 0 && b.i > 0 { 65 // release (last) stride 66 stridePool.Put(s.raw) 67 s.raw = nil 68 b.strides = b.strides[:b.i] 69 b.i-- 70 } 71 } 72 73 func (b *buffer) doAlloc(sz uintptr) []byte { 74 s := &b.strides[b.i] 75 space := uintptr(len(s.raw)) - s.pos 76 77 if space < sz { 78 var bytes []byte 79 80 if b.preAlloc < sz { 81 bytes = make([]byte, sz) 82 } else { 83 bytes = b.allocStride() 84 } 85 86 b.strides = append(b.strides, stride{ 87 raw: bytes, 88 pos: sz, 89 }) 90 b.i++ 91 92 return b.strides[b.i].raw[0:] 93 } 94 95 start := s.pos 96 s.pos += sz 97 98 mem := s.raw[start:s.pos] 99 for i := range mem { 100 mem[i] = 0 101 } 102 return mem 103 }