package array
import (
"sync/atomic"
"unsafe"
"github.com/apache/arrow-go/v18/arrow"
"github.com/apache/arrow-go/v18/arrow/bitutil"
"github.com/apache/arrow-go/v18/arrow/internal/debug"
"github.com/apache/arrow-go/v18/arrow/memory"
)
type bufBuilder interface {
Retain()
Release()
Len() int
Cap() int
Bytes() []byte
resize(int )
Advance(int )
SetLength(int )
Append([]byte )
Reset()
Finish() *memory .Buffer
}
type bufferBuilder struct {
refCount atomic .Int64
mem memory .Allocator
buffer *memory .Buffer
length int
capacity int
bytes []byte
}
func (b *bufferBuilder ) Retain () {
b .refCount .Add (1 )
}
func (b *bufferBuilder ) Release () {
debug .Assert (b .refCount .Load () > 0 , "too many releases" )
if b .refCount .Add (-1 ) == 0 {
if b .buffer != nil {
b .buffer .Release ()
b .buffer , b .bytes = nil , nil
}
}
}
func (b *bufferBuilder ) Len () int { return b .length }
func (b *bufferBuilder ) Cap () int { return b .capacity }
func (b *bufferBuilder ) Bytes () []byte { return b .bytes [:b .length ] }
func (b *bufferBuilder ) resize (elements int ) {
if b .buffer == nil {
b .buffer = memory .NewResizableBuffer (b .mem )
}
b .buffer .ResizeNoShrink (elements )
oldCapacity := b .capacity
b .capacity = b .buffer .Cap ()
b .bytes = b .buffer .Buf ()
if b .capacity > oldCapacity {
memory .Set (b .bytes [oldCapacity :], 0 )
}
}
func (b *bufferBuilder ) SetLength (length int ) {
if length > b .length {
b .Advance (length )
return
}
b .length = length
}
func (b *bufferBuilder ) Advance (length int ) {
if b .capacity < b .length +length {
newCapacity := bitutil .NextPowerOf2 (b .length + length )
b .resize (newCapacity )
}
b .length += length
}
func (b *bufferBuilder ) Append (v []byte ) {
if b .capacity < b .length +len (v ) {
newCapacity := bitutil .NextPowerOf2 (b .length + len (v ))
b .resize (newCapacity )
}
b .unsafeAppend (v )
}
func (b *bufferBuilder ) Reset () {
if b .buffer != nil {
b .buffer .Release ()
}
b .buffer , b .bytes = nil , nil
b .capacity , b .length = 0 , 0
}
func (b *bufferBuilder ) Finish () (buffer *memory .Buffer ) {
if b .length > 0 {
b .buffer .ResizeNoShrink (b .length )
}
buffer = b .buffer
b .buffer = nil
b .Reset ()
if buffer == nil {
buffer = memory .NewBufferBytes (nil )
}
return
}
func (b *bufferBuilder ) unsafeAppend (data []byte ) {
copy (b .bytes [b .length :], data )
b .length += len (data )
}
type multiBufferBuilder struct {
refCount atomic .Int64
blockSize int
mem memory .Allocator
blocks []*memory .Buffer
currentOutBuffer int
}
func (b *multiBufferBuilder ) Retain () {
b .refCount .Add (1 )
}
func (b *multiBufferBuilder ) Release () {
debug .Assert (b .refCount .Load () > 0 , "too many releases" )
if b .refCount .Add (-1 ) == 0 {
b .Reset ()
}
}
func (b *multiBufferBuilder ) Reserve (nbytes int ) {
if len (b .blocks ) == 0 {
out := memory .NewResizableBuffer (b .mem )
if nbytes < b .blockSize {
nbytes = b .blockSize
}
out .Reserve (nbytes )
b .currentOutBuffer = 0
b .blocks = []*memory .Buffer {out }
return
}
curBuf := b .blocks [b .currentOutBuffer ]
remain := curBuf .Cap () - curBuf .Len ()
if nbytes <= remain {
return
}
for i , block := range b .blocks {
remaining := block .Cap () - block .Len ()
if nbytes <= remaining {
b .currentOutBuffer = i
return
}
}
newBuf := memory .NewResizableBuffer (b .mem )
if nbytes < b .blockSize {
nbytes = b .blockSize
}
newBuf .Reserve (nbytes )
b .currentOutBuffer = len (b .blocks )
b .blocks = append (b .blocks , newBuf )
}
func (b *multiBufferBuilder ) RemainingBytes () int {
if len (b .blocks ) == 0 {
return 0
}
buf := b .blocks [b .currentOutBuffer ]
return buf .Cap () - buf .Len ()
}
func (b *multiBufferBuilder ) Reset () {
b .currentOutBuffer = 0
for _ , block := range b .Finish () {
block .Release ()
}
}
func (b *multiBufferBuilder ) UnsafeAppend (hdr *arrow .ViewHeader , val []byte ) {
buf := b .blocks [b .currentOutBuffer ]
idx , offset := b .currentOutBuffer , buf .Len ()
hdr .SetIndexOffset (int32 (idx ), int32 (offset ))
n := copy (buf .Buf ()[offset :], val )
buf .ResizeNoShrink (offset + n )
}
func (b *multiBufferBuilder ) UnsafeAppendString (hdr *arrow .ViewHeader , val string ) {
v := *(*[]byte )(unsafe .Pointer (&struct {
string
int
}{val , len (val )}))
b .UnsafeAppend (hdr , v )
}
func (b *multiBufferBuilder ) Finish () (out []*memory .Buffer ) {
b .currentOutBuffer = 0
out , b .blocks = b .blocks , nil
return
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .