github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/utils/buffer/buffer.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package buffer 16 17 import ( 18 "io" 19 20 "github.com/dolthub/dolt/go/libraries/utils/iohelp" 21 ) 22 23 type DynamicBuffer struct { 24 blocks [][]byte 25 blockSize int 26 } 27 28 func New(blockSize int) *DynamicBuffer { 29 return &DynamicBuffer{blockSize: blockSize} 30 } 31 32 func (buf *DynamicBuffer) Append(bytes []byte) { 33 blockIdx := len(buf.blocks) - 1 34 35 var space int 36 var pos int 37 if blockIdx >= 0 { 38 currBlock := buf.blocks[blockIdx] 39 pos = len(currBlock) 40 space = cap(currBlock) - pos 41 } 42 43 for len(bytes) > 0 { 44 if space == 0 { 45 for len(bytes) >= buf.blockSize { 46 buf.blocks = append(buf.blocks, bytes[:buf.blockSize]) 47 bytes = bytes[buf.blockSize:] 48 blockIdx++ 49 } 50 51 if len(bytes) == 0 { 52 return 53 } 54 55 buf.blocks = append(buf.blocks, make([]byte, 0, buf.blockSize)) 56 pos = 0 57 space = buf.blockSize 58 blockIdx++ 59 } 60 61 n := len(bytes) 62 if n > space { 63 n = space 64 } 65 66 buf.blocks[blockIdx] = buf.blocks[blockIdx][:pos+n] 67 copy(buf.blocks[blockIdx][pos:], bytes[:n]) 68 bytes = bytes[n:] 69 space -= n 70 pos += n 71 } 72 } 73 74 func (buf *DynamicBuffer) Close() *BufferIterator { 75 itr := &BufferIterator{blocks: buf.blocks} 76 buf.blocks = nil 77 78 return itr 79 } 80 81 type BufferIterator struct { 82 blocks [][]byte 83 i int 84 } 85 86 func (itr *BufferIterator) Next() ([]byte, error) { 87 if itr.i >= len(itr.blocks) { 88 return nil, io.EOF 89 } 90 next := itr.blocks[itr.i] 91 itr.i++ 92 93 return next, nil 94 } 95 96 func (itr *BufferIterator) NumBlocks() int { 97 return len(itr.blocks) 98 } 99 100 func (itr *BufferIterator) FlushTo(wr io.Writer) error { 101 for { 102 data, err := itr.Next() 103 104 if err == io.EOF { 105 return nil 106 } else if err != nil { 107 return err 108 } 109 110 err = iohelp.WriteAll(wr, data) 111 112 if err != nil { 113 return err 114 } 115 } 116 } 117 118 func (itr *BufferIterator) AsReader() io.Reader { 119 return &bufferIteratorReader{ 120 itr: itr, 121 } 122 } 123 124 type bufferIteratorReader struct { 125 itr *BufferIterator 126 currBuff []byte 127 } 128 129 func (b *bufferIteratorReader) Read(dest []byte) (n int, err error) { 130 if len(b.currBuff) == 0 { 131 b.currBuff, err = b.itr.Next() 132 133 if err != nil { 134 return 0, err 135 } 136 } 137 138 destSize := len(dest) 139 toCopy := b.currBuff 140 if len(b.currBuff) > destSize { 141 toCopy = b.currBuff[:destSize] 142 } 143 144 n = copy(dest, toCopy) 145 b.currBuff = b.currBuff[n:] 146 147 return n, err 148 }