Use a different rope implementation

This commit is contained in:
Zachary Yedidia
2016-03-27 15:22:57 -04:00
parent c997fc362b
commit 927dd9dba9
3 changed files with 18 additions and 157 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"github.com/vinzmay/go-rope"
"io/ioutil"
"strings"
)
@@ -10,7 +11,7 @@ import (
// simple functions for saving and wrapper functions for modifying the rope
type Buffer struct {
// Stores the text of the buffer
r *Rope
r *rope.Rope
// Path to the file on disk
path string
@@ -35,7 +36,11 @@ type Buffer struct {
// NewBuffer creates a new buffer from `txt` with path and name `path`
func NewBuffer(txt, path string) *Buffer {
b := new(Buffer)
b.r = NewRope(txt)
if txt == "" {
b.r = new(rope.Rope)
} else {
b.r = rope.New(txt)
}
b.path = path
b.name = path
b.savedText = txt
@@ -54,7 +59,11 @@ func (b *Buffer) UpdateRules() {
// Update fetches the string from the rope and updates the `text` and `lines` in the buffer
func (b *Buffer) Update() {
b.text = b.r.String()
if b.r.Len() == 0 {
b.text = ""
} else {
b.text = b.r.String()
}
b.lines = strings.Split(b.text, "\n")
}
@@ -79,7 +88,7 @@ func (b *Buffer) IsDirty() bool {
// Insert a string into the rope
func (b *Buffer) Insert(idx int, value string) {
b.r.Insert(idx, value)
b.r = b.r.Insert(idx, value)
b.Update()
}
@@ -93,12 +102,15 @@ func (b *Buffer) Remove(start, end int) string {
end = b.Len()
}
removed := b.text[start:end]
b.r.Remove(start, end)
// The rope implenentation I am using wants indicies starting at 1 instead of 0
start++
end++
b.r = b.r.Delete(start, end-start)
b.Update()
return removed
}
// Len gives the length of the buffer
func (b *Buffer) Len() int {
return b.r.len
return b.r.Len()
}

View File

@@ -1,105 +0,0 @@
package main
import (
"math"
)
const (
// RopeSplitLength is the threshold used to split a leaf node into two child nodes.
RopeSplitLength = 1000000000
// RopeJoinLength is the threshold used to join two child nodes into one leaf node.
RopeJoinLength = 500
// RopeRebalanceRatio = 1.2
)
// A Rope is a data structure for efficiently manipulating large strings
type Rope struct {
left *Rope
right *Rope
value string
valueNil bool
len int
}
// NewRope returns a new rope from a given string
func NewRope(str string) *Rope {
r := new(Rope)
r.value = str
r.valueNil = false
r.len = Count(r.value)
r.Adjust()
return r
}
// Adjust modifies the rope so it is more balanced
func (r *Rope) Adjust() {
if !r.valueNil {
if r.len > RopeSplitLength {
divide := int(math.Floor(float64(r.len) / 2))
runes := []rune(r.value)
r.left = NewRope(string(runes[:divide]))
r.right = NewRope(string(runes[divide:]))
r.valueNil = true
}
} else {
if r.len < RopeJoinLength {
r.value = r.left.String() + r.right.String()
r.valueNil = false
r.left = nil
r.right = nil
}
}
}
// String returns the string representation of the rope
func (r *Rope) String() string {
if !r.valueNil {
return r.value
}
return r.left.String() + r.right.String()
}
// Remove deletes a slice of the rope from start the to end (exclusive)
func (r *Rope) Remove(start, end int) {
if !r.valueNil {
r.value = string(append([]rune(r.value)[:start], []rune(r.value)[end:]...))
r.valueNil = false
r.len = Count(r.value)
} else {
leftStart := Min(start, r.left.len)
leftEnd := Min(end, r.left.len)
rightStart := Max(0, Min(start-r.left.len, r.right.len))
rightEnd := Max(0, Min(end-r.left.len, r.right.len))
if leftStart < r.left.len {
r.left.Remove(leftStart, leftEnd)
}
if rightEnd > 0 {
r.right.Remove(rightStart, rightEnd)
}
r.len = r.left.len + r.right.len
}
r.Adjust()
}
// Insert inserts a string into the rope at a specified position
func (r *Rope) Insert(pos int, value string) {
if !r.valueNil {
first := append([]rune(r.value)[:pos], []rune(value)...)
r.value = string(append(first, []rune(r.value)[pos:]...))
r.valueNil = false
r.len = Count(r.value)
} else {
if pos < r.left.len {
r.left.Insert(pos, value)
r.len = r.left.len + r.right.len
} else {
r.right.Insert(pos-r.left.len, value)
}
}
r.Adjust()
}

View File

@@ -1,46 +0,0 @@
package main
import "testing"
func TestInsert(t *testing.T) {
var tests = []struct {
origStr string
insertStr string
insertPos int
want string
}{
{"foo", " bar", 3, "foo bar"},
{"üñîç", "ø∂é", 4, "üñîçø∂é"},
{"test", "3", 2, "te3st"},
{"", "test", 0, "test"},
}
for _, test := range tests {
r := NewRope(test.origStr)
r.Insert(test.insertPos, test.insertStr)
got := r.String()
if got != test.want {
t.Errorf("Insert(%d, %s) = %s", test.insertPos, test.insertStr, got)
}
}
}
func TestRemove(t *testing.T) {
var tests = []struct {
inputStr string
removeStart int
removeEnd int
want string
}{
{"foo bar", 3, 7, "foo"},
{"üñîçø∂é", 0, 3, "çø∂é"},
{"test", 0, 4, ""},
}
for _, test := range tests {
r := NewRope(test.inputStr)
r.Remove(test.removeStart, test.removeEnd)
got := r.String()
if got != test.want {
t.Errorf("Remove(%d, %d) = %s", test.removeStart, test.removeEnd, got)
}
}
}