mirror of
https://github.com/dolthub/dolt.git
synced 2026-01-08 16:16:45 -06:00
149 lines
2.8 KiB
Go
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
|
|
}
|