aboutsummaryrefslogtreecommitdiff
path: root/gapbuffer
diff options
context:
space:
mode:
authorPetter Rodhelind <petter.rodhelind@gmail.com>2018-02-26 23:51:03 +0100
committerPetter Rodhelind <petter.rodhelind@gmail.com>2018-02-26 23:51:03 +0100
commit2395485d075f80117fe3ce25ef339bb1ffecf160 (patch)
tree87cabebd5ba1c7210adb5dabe253310f17694931 /gapbuffer
parent0023e0929ac7075cd008e0093de58ddc89efd597 (diff)
downloadpoe-2395485d075f80117fe3ce25ef339bb1ffecf160.tar.gz
poe-2395485d075f80117fe3ce25ef339bb1ffecf160.tar.bz2
poe-2395485d075f80117fe3ce25ef339bb1ffecf160.zip
Total redesign. Separating editor parts from UI.
Diffstat (limited to 'gapbuffer')
-rw-r--r--gapbuffer/gap.go81
-rw-r--r--gapbuffer/gap_test.go14
2 files changed, 50 insertions, 45 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
diff --git a/gapbuffer/gap_test.go b/gapbuffer/gap_test.go
index a1eadb0..29a1f72 100644
--- a/gapbuffer/gap_test.go
+++ b/gapbuffer/gap_test.go
@@ -26,7 +26,7 @@ func sliceEqual(a []byte, b []byte) bool {
}
func TestReadAt(t *testing.T) {
- gb := gapbuffer.New()
+ gb := gapbuffer.Buffer{}
gb.Write([]byte(lipsum))
var tt = []struct {
@@ -55,7 +55,7 @@ func TestReadAt(t *testing.T) {
}
func TestSeekAndPos(t *testing.T) {
- gb := gapbuffer.New()
+ gb := gapbuffer.Buffer{}
gb.Write([]byte(lipsum))
var tt = []struct {
@@ -92,7 +92,7 @@ func TestWriteSingle(t *testing.T) {
}
for _, tc := range tt {
- b := gapbuffer.New()
+ b := gapbuffer.Buffer{}
n, err := b.Write(tc.input)
if n != tc.wantret {
t.Errorf("%s: expected %d bytes, got %d", tc.name, tc.wantret, n)
@@ -118,7 +118,7 @@ func TestWriteMulti(t *testing.T) {
}
for _, tc := range tt {
- b := gapbuffer.New()
+ b := gapbuffer.Buffer{}
b.Write(tc.input1)
b.Seek(tc.offset)
b.Write(tc.input2)
@@ -146,7 +146,7 @@ func TestByteAt(t *testing.T) {
}
for _, tc := range tt {
- b := gapbuffer.New()
+ b := gapbuffer.Buffer{}
b.Write(tc.input)
b.Seek(0)
c, err := b.ByteAt(tc.pos)
@@ -156,7 +156,7 @@ func TestByteAt(t *testing.T) {
}
for _, tc := range tt {
- b := gapbuffer.New()
+ b := gapbuffer.Buffer{}
b.Write(tc.input)
b.Seek(2)
c, err := b.ByteAt(tc.pos)
@@ -166,7 +166,7 @@ func TestByteAt(t *testing.T) {
}
for _, tc := range tt {
- b := gapbuffer.New()
+ b := gapbuffer.Buffer{}
b.Write(tc.input)
b.Seek(b.Len())
c, err := b.ByteAt(tc.pos)