Skip to content

Instantly share code, notes, and snippets.

@gebv
Created February 5, 2021 12:41
Show Gist options
  • Save gebv/a14e48d6969dc13beac8f91c97571e16 to your computer and use it in GitHub Desktop.
Save gebv/a14e48d6969dc13beac8f91c97571e16 to your computer and use it in GitHub Desktop.
[draft code] manual buffer implementation io.Writer, io.WriterAt, io.Seeker, io.Reader, io.ReaderAt
package bufx
import (
"errors"
"io"
)
var (
_ io.Writer = (*buf)(nil)
_ io.WriterAt = (*buf)(nil)
_ io.Seeker = (*buf)(nil)
_ io.Reader = (*buf)(nil)
_ io.ReaderAt = (*buf)(nil)
)
type buf struct {
buf []byte
// data has been changed
changed bool
// position
p int64
}
func (b *buf) Сhanged() bool {
return b.changed
}
func (b *buf) Bytes() []byte {
return b.buf[b.p:]
}
func (b *buf) Truncate(n int) {
if n == 0 {
b.Reset()
return
}
if n < 0 || n > b.Len() {
panic("bytes.Buffer: truncation out of range")
}
b.buf = b.buf[:int(b.p)+n]
b.changed = true
}
func (b *buf) Reset() {
b.buf = b.buf[:0]
b.p = 0
b.changed = true
}
func (r *buf) Read(b []byte) (n int, err error) {
if r.p >= int64(len(r.buf)) {
return 0, io.EOF
}
n = copy(b, r.buf[r.p:])
r.p += int64(n)
return
}
func (r *buf) ReadAt(b []byte, off int64) (n int, err error) {
// cannot modify state - see io.ReaderAt
if off < 0 {
return 0, errors.New("strings.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.buf)) {
return 0, io.EOF
}
n = copy(b, r.buf[off:])
if n < len(b) {
err = io.EOF
}
return
}
func (r *buf) Seek(offset int64, whence int) (int64, error) {
var abs int64
switch whence {
case io.SeekStart:
abs = offset
case io.SeekCurrent:
abs = r.p + offset
case io.SeekEnd:
abs = int64(len(r.buf)) + offset
default:
return 0, errors.New("strings.Reader.Seek: invalid whence")
}
if abs < 0 {
return 0, errors.New("strings.Reader.Seek: negative position")
}
r.p = abs
return abs, nil
}
// Copy from bytes.Buffer
// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (r *buf) Len() int {
if r.p >= int64(len(r.buf)) {
return 0
}
return int(int64(len(r.buf)) - r.p)
}
func (b *buf) Cap() int {
return cap(b.buf)
}
func (w *buf) Write(p []byte) (n int, err error) {
// append to end of buffer?
return w.WriteAt(p, int64(len(w.buf)))
}
// coped fragment from aws WrtieAtBuffer
func (w *buf) WriteAt(p []byte, pos int64) (n int, err error) {
pLen := len(p)
expLen := pos + int64(pLen)
if int64(len(w.buf)) < expLen {
if int64(cap(w.buf)) < expLen {
newBuf := make([]byte, expLen, int64(float64(expLen)))
copy(newBuf, w.buf)
w.buf = newBuf
}
w.buf = w.buf[:expLen]
}
copy(w.buf[pos:], p)
w.changed = true
return pLen, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment