Comments and style for rope

This commit is contained in:
Zachary Yedidia
2016-03-18 21:25:45 -04:00
parent d55dabaa3b
commit cc098d05ef
2 changed files with 42 additions and 33 deletions

View File

@@ -20,7 +20,7 @@ type Buffer struct {
// This is the text stored everytime the buffer is saved to check if the buffer is modified // This is the text stored everytime the buffer is saved to check if the buffer is modified
savedText string savedText string
// Provide efficient and easy access to text and lines so the rope toString does not // Provide efficient and easy access to text and lines so the rope String does not
// need to be constantly recalculated // need to be constantly recalculated
// These variables are updated in the update() function // These variables are updated in the update() function
text string text string
@@ -30,7 +30,7 @@ type Buffer struct {
// NewBuffer creates a new buffer from `txt` with path and name `path` // NewBuffer creates a new buffer from `txt` with path and name `path`
func NewBuffer(txt, path string) *Buffer { func NewBuffer(txt, path string) *Buffer {
b := new(Buffer) b := new(Buffer)
b.r = newRope(txt) b.r = NewRope(txt)
b.path = path b.path = path
b.name = path b.name = path
b.savedText = txt b.savedText = txt
@@ -42,7 +42,7 @@ func NewBuffer(txt, path string) *Buffer {
// Update fetches the string from the rope and updates the `text` and `lines` in the buffer // Update fetches the string from the rope and updates the `text` and `lines` in the buffer
func (b *Buffer) Update() { func (b *Buffer) Update() {
b.text = b.r.toString() b.text = b.r.String()
b.lines = strings.Split(b.text, "\n") b.lines = strings.Split(b.text, "\n")
} }
@@ -60,13 +60,13 @@ func (b *Buffer) SaveAs(filename string) error {
// Insert a string into the rope // Insert a string into the rope
func (b *Buffer) Insert(idx int, value string) { func (b *Buffer) Insert(idx int, value string) {
b.r.insert(idx, value) b.r.Insert(idx, value)
b.Update() b.Update()
} }
// Remove a slice of the rope from start to end (exclusive) // Remove a slice of the rope from start to end (exclusive)
func (b *Buffer) Remove(start, end int) { func (b *Buffer) Remove(start, end int) {
b.r.remove(start, end) b.r.Remove(start, end)
b.Update() b.Update()
} }

65
rope.go
View File

@@ -1,31 +1,35 @@
package main package main
import ( import (
// "fmt"
"math" "math"
"unicode/utf8" "unicode/utf8"
) )
const ( const (
ropeSplitLength = 1000 // RopeSplitLength defines how large can a string be before it is split into two nodes
ropeJoinLength = 500 RopeSplitLength = 1000
ropeRebalanceRatio = 1.2 // RopeJoinLength defines how short can a string be before it is joined
RopeJoinLength = 500
// RopeRebalanceRatio = 1.2
) )
func min(a, b int) int { // Min takes the min of two ints
func Min(a, b int) int {
if a > b { if a > b {
return b return b
} }
return a return a
} }
func max(a, b int) int { // Max takes the max of two ints
func Max(a, b int) int {
if a > b { if a > b {
return a return a
} }
return b return b
} }
// A Rope is a data structure for efficiently manipulating large strings
type Rope struct { type Rope struct {
left *Rope left *Rope
right *Rope right *Rope
@@ -35,28 +39,30 @@ type Rope struct {
len int len int
} }
func newRope(str string) *Rope { // NewRope returns a new rope from a given string
func NewRope(str string) *Rope {
r := new(Rope) r := new(Rope)
r.value = str r.value = str
r.valueNil = false r.valueNil = false
r.len = utf8.RuneCountInString(r.value) r.len = utf8.RuneCountInString(r.value)
r.adjust() r.Adjust()
return r return r
} }
func (r *Rope) adjust() { // Adjust modifies the rope so it is more balanced
func (r *Rope) Adjust() {
if !r.valueNil { if !r.valueNil {
if r.len > ropeSplitLength { if r.len > RopeSplitLength {
divide := int(math.Floor(float64(r.len) / 2)) divide := int(math.Floor(float64(r.len) / 2))
r.left = newRope(r.value[:divide]) r.left = NewRope(r.value[:divide])
r.right = newRope(r.value[divide:]) r.right = NewRope(r.value[divide:])
r.valueNil = true r.valueNil = true
} }
} else { } else {
if r.len < ropeJoinLength { if r.len < RopeJoinLength {
r.value = r.left.toString() + r.right.toString() r.value = r.left.String() + r.right.String()
r.valueNil = false r.valueNil = false
r.left = nil r.left = nil
r.right = nil r.right = nil
@@ -64,36 +70,39 @@ func (r *Rope) adjust() {
} }
} }
func (r *Rope) toString() string { // String returns the string representation of the rope
func (r *Rope) String() string {
if !r.valueNil { if !r.valueNil {
return r.value return r.value
} }
return r.left.toString() + r.right.toString() return r.left.String() + r.right.String()
} }
func (r *Rope) remove(start, end int) { // Remove deletes a slice of the rope from start the to end (exclusive)
func (r *Rope) Remove(start, end int) {
if !r.valueNil { if !r.valueNil {
r.value = string(append([]rune(r.value)[:start], []rune(r.value)[end:]...)) r.value = string(append([]rune(r.value)[:start], []rune(r.value)[end:]...))
r.valueNil = false r.valueNil = false
r.len = utf8.RuneCountInString(r.value) r.len = utf8.RuneCountInString(r.value)
} else { } else {
leftStart := min(start, r.left.len) leftStart := Min(start, r.left.len)
leftEnd := min(end, r.left.len) leftEnd := Min(end, r.left.len)
rightStart := max(0, min(start-r.left.len, r.right.len)) rightStart := Max(0, Min(start-r.left.len, r.right.len))
rightEnd := max(0, min(end-r.left.len, r.right.len)) rightEnd := Max(0, Min(end-r.left.len, r.right.len))
if leftStart < r.left.len { if leftStart < r.left.len {
r.left.remove(leftStart, leftEnd) r.left.Remove(leftStart, leftEnd)
} }
if rightEnd > 0 { if rightEnd > 0 {
r.right.remove(rightStart, rightEnd) r.right.Remove(rightStart, rightEnd)
} }
r.len = r.left.len + r.right.len r.len = r.left.len + r.right.len
} }
r.adjust() r.Adjust()
} }
func (r *Rope) insert(pos int, value string) { // Insert inserts a string into the rope at a specified position
func (r *Rope) Insert(pos int, value string) {
if !r.valueNil { if !r.valueNil {
first := append([]rune(r.value)[:pos], []rune(value)...) first := append([]rune(r.value)[:pos], []rune(value)...)
r.value = string(append(first, []rune(r.value)[pos:]...)) r.value = string(append(first, []rune(r.value)[pos:]...))
@@ -101,12 +110,12 @@ func (r *Rope) insert(pos int, value string) {
r.len = utf8.RuneCountInString(r.value) r.len = utf8.RuneCountInString(r.value)
} else { } else {
if pos < r.left.len { if pos < r.left.len {
r.left.insert(pos, value) r.left.Insert(pos, value)
r.len = r.left.len + r.right.len r.len = r.left.len + r.right.len
} else { } else {
r.right.insert(pos-r.left.len, value) r.right.Insert(pos-r.left.len, value)
} }
} }
r.adjust() r.Adjust()
} }