diff options
Diffstat (limited to 'gapbuffer/gap.go')
-rw-r--r-- | gapbuffer/gap.go | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/gapbuffer/gap.go b/gapbuffer/gap.go index 5bf9ca6..b714c83 100644 --- a/gapbuffer/gap.go +++ b/gapbuffer/gap.go @@ -5,24 +5,14 @@ import ( "io" ) -// BUFSIZE is the initial size of the Buffer when calling New(). -const BUFSIZE = 64 - // ErrOutOfRange is returned when given position is out of range for the buffer. var ErrOutOfRange = errors.New("index out of range") type Buffer struct { - data []byte - start int // gap start, is considered empty - end int // gap end, holds next byte counting from before the gap -} - -func New() *Buffer { - return &Buffer{ - data: make([]byte, BUFSIZE), - start: 0, - end: BUFSIZE, - } + buf []byte + bootstrap [64]byte + start int // gap start, is considered empty + end int // gap end, holds next byte counting from before the gap } func (b *Buffer) Bytes() []byte { @@ -34,16 +24,16 @@ func (b *Buffer) Bytes() []byte { // Destroy will erase the Buffer by zeroising all fields. func (b *Buffer) Destroy() { b.start = 0 - b.end = len(b.data) + b.end = len(b.buf) } // Byte returns current byte right after the gap. If the gap is at the end, the return will be 0. func (b *Buffer) Byte() byte { - if b.end >= len(b.data) { + if b.end >= len(b.buf) { return 0 // EOF } - return b.data[b.end] + return b.buf[b.end] } // ByteAt returns the byte at the given offset, ignoring and hiding the gap. @@ -55,11 +45,11 @@ func (b *Buffer) ByteAt(offset int) (byte, error) { if offset < 0 { return 0, ErrOutOfRange } - if offset >= len(b.data) { + if offset >= len(b.buf) { return 0, io.EOF } - return b.data[offset], nil + return b.buf[offset], nil } // gapLen returns the length of the gap. @@ -69,12 +59,12 @@ func (b *Buffer) gapLen() int { // Len returns the length of actual data. func (b *Buffer) Len() int { - return len(b.data) - b.gapLen() + return len(b.buf) - b.gapLen() } // Cap returns the capacity of the Buffer, including the gap. func (b *Buffer) Cap() int { - return cap(b.data) + return cap(b.buf) } // Pos returns the current start position of the gap. This is where next write will appear. @@ -86,7 +76,8 @@ func (b *Buffer) Pos() int { func (b *Buffer) Seek(newpos int) { // out of range if newpos < 0 { - b.Seek(0) + //b.Seek(0) + panic("index below zero") return } if newpos > b.Len() { @@ -107,10 +98,10 @@ func (b *Buffer) Seek(newpos int) { // Forward is moving the gap one byte forward. func (b *Buffer) forward() { - if b.end >= len(b.data) { + if b.end >= len(b.buf) { return } - b.data[b.start] = b.data[b.end] + b.buf[b.start] = b.buf[b.end] b.start++ b.end++ } @@ -120,7 +111,7 @@ func (b *Buffer) backward() { if b.start <= 0 { return } - b.data[b.end-1] = b.data[b.start-1] + b.buf[b.end-1] = b.buf[b.start-1] b.start-- b.end-- } @@ -131,7 +122,31 @@ func (b *Buffer) Delete() byte { return 0 } b.start-- - return b.data[b.start] + return b.buf[b.start] +} + +// grow will grow the buffer if necessary. +func (b *Buffer) grow() { + if b.buf == nil { + b.buf = b.bootstrap[:] + fill := make([]byte, cap(b.buf)) + b.buf = append(b.buf, fill...) + + b.start = 0 + b.end = cap(b.buf) + return + } + oldpos := b.start + b.Seek(cap(b.buf)) + + b.buf = append(b.buf, 0) + exp := cap(b.buf) + b.end += exp + 1 + + fill := make([]byte, exp) + b.buf = append(b.buf, fill...) + + b.Seek(oldpos) } // Write writes p into the Buffer at current gap position. The Buffer will expand if needed and this is the only time any new memory allocation is done. The resizing and expanding strategy is handled by the underlying internal byte slice. Cap() will return the size of this slice. @@ -143,19 +158,9 @@ func (b *Buffer) Write(p []byte) (int, error) { } for _, c := range p { if b.gapLen() == 0 { - oldpos := b.start - b.Seek(cap(b.data)) - - b.data = append(b.data, 0) - exp := cap(b.data) - b.end += exp + 1 - - fill := make([]byte, exp) - b.data = append(b.data, fill...) - - b.Seek(oldpos) + b.grow() } - b.data[b.start] = c + b.buf[b.start] = c b.start++ } return len(p), nil |