Files
dolt/go/libraries/utils/buffer/buffer.go
2021-09-08 14:52:42 -07:00

149 lines
2.8 KiB
Go

// Copyright 2021 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package buffer
import (
"io"
"github.com/dolthub/dolt/go/libraries/utils/iohelp"
)
type DynamicBuffer struct {
blocks [][]byte
blockSize int
}
func New(blockSize int) *DynamicBuffer {
return &DynamicBuffer{blockSize: blockSize}
}
func (buf *DynamicBuffer) Append(bytes []byte) {
blockIdx := len(buf.blocks) - 1
var space int
var pos int
if blockIdx >= 0 {
currBlock := buf.blocks[blockIdx]
pos = len(currBlock)
space = cap(currBlock) - pos
}
for len(bytes) > 0 {
if space == 0 {
for len(bytes) >= buf.blockSize {
buf.blocks = append(buf.blocks, bytes[:buf.blockSize])
bytes = bytes[buf.blockSize:]
blockIdx++
}
if len(bytes) == 0 {
return
}
buf.blocks = append(buf.blocks, make([]byte, 0, buf.blockSize))
pos = 0
space = buf.blockSize
blockIdx++
}
n := len(bytes)
if n > space {
n = space
}
buf.blocks[blockIdx] = buf.blocks[blockIdx][:pos+n]
copy(buf.blocks[blockIdx][pos:], bytes[:n])
bytes = bytes[n:]
space -= n
pos += n
}
}
func (buf *DynamicBuffer) Close() *BufferIterator {
itr := &BufferIterator{blocks: buf.blocks}
buf.blocks = nil
return itr
}
type BufferIterator struct {
blocks [][]byte
i int
}
func (itr *BufferIterator) Next() ([]byte, error) {
if itr.i >= len(itr.blocks) {
return nil, io.EOF
}
next := itr.blocks[itr.i]
itr.i++
return next, nil
}
func (itr *BufferIterator) NumBlocks() int {
return len(itr.blocks)
}
func (itr *BufferIterator) FlushTo(wr io.Writer) error {
for {
data, err := itr.Next()
if err == io.EOF {
return nil
} else if err != nil {
return err
}
err = iohelp.WriteAll(wr, data)
if err != nil {
return err
}
}
}
func (itr *BufferIterator) AsReader() io.Reader {
return &bufferIteratorReader{
itr: itr,
}
}
type bufferIteratorReader struct {
itr *BufferIterator
currBuff []byte
}
func (b *bufferIteratorReader) Read(dest []byte) (n int, err error) {
if len(b.currBuff) == 0 {
b.currBuff, err = b.itr.Next()
if err != nil {
return 0, err
}
}
destSize := len(dest)
toCopy := b.currBuff
if len(b.currBuff) > destSize {
toCopy = b.currBuff[:destSize]
}
n = copy(dest, toCopy)
b.currBuff = b.currBuff[n:]
return n, err
}