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  }