Skip to content

Commit

Permalink
[frame] Remove nalloc, nbox
Browse files Browse the repository at this point in the history
There have been several frame bugs related to the fact that Frame.box
is a slice but with manual bounds management via Frame.nalloc and
Frame.nbox. As a result, it was difficult and subtle to use Go
constructs like append on the slice of frbox objects.

Make this code more idiomatic and hopefully less buggy (in pursuit of
great robustness per #30) by making Frame.box a true Go slice.
  • Loading branch information
rjkroege committed Apr 8, 2018
1 parent 7006017 commit cbd759e
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 360 deletions.
109 changes: 53 additions & 56 deletions frame/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,77 @@ import (
"unicode/utf8"
)

const slop = 25
//const slop = 25

// I don't think that this should be necessary.
func (f *Frame) freebox(n0, n1 int) {
if n1 < n0 {
return
}
if n0 >= len(f.box) || n1 >= len(f.box) {
panic("Frame.freebox")
}
n1++
for i := n0; i < n1; i++ {
f.box[i] = nil
}
}

// addbox adds n boxes after bn and shifts the rest up: * box[bn+n]==box[bn]
func (f *Frame) addbox(bn, n int) {
if bn > f.nbox {
panic("Frame.addbox")
if bn > len(f.box) {
panic("Frame.addbox bn too large")
}

if f.nbox+n > f.nalloc {
f.growbox(n + slop)
}

// TODO(rjk): This does some extra work becasue nbox != len(f.box)
// Use a slice and remove nbox and nalloc.
f.box = append(f.box, make([]*frbox, n)...)
copy(f.box[bn+n:], f.box[bn:])
f.nbox += int(n)
}


func (f *Frame) closebox(n0, n1 int) {
if n0 >= f.nbox || n1 >= f.nbox || n1 < n0 {
panic("Frame.closebox")
if n0 >= len(f.box) || n1 >=len(f.box) || n1 < n0 {
panic("Frame.closebox bounds bad")
}
// TODO(rjk): Use copy.
n1++

for i := n1; i < f.nbox; i++ {
f.box[i-(n1-n0)] = f.box[i]
}
f.nbox -= n1 - n0
for i := f.nbox; i < f.nbox+(n1-n0); i++ {
f.box[i] = nil
}
n1++
copy(f.box[n0:], f.box[n1:])
f.box = f.box[0:len(f.box) - (n1 - n0)]
}

func (f *Frame) delbox(n0, n1 int) {
if n0 >= f.nbox || n1 >= f.nbox || n1 < n0 {
panic("Frame.delbox")
}
f.freebox(n0, n1)
// TODO(rjk): One of delbox and closebox don't belong.
f.closebox(n0, n1)
}

func (f *Frame) freebox(n0, n1 int) {
if n1 < n0 {
return
}
if n0 >= f.nbox || n1 >= f.nbox {
panic("Frame.freebox")
}
n1++
for i := n0; i < n1; i++ {
f.box[i] = nil
}
}
func (b *frbox) clone() *frbox {
// Shallow copy.
cp := new(frbox)
*cp = *b

// growbox adds delta new frbox pointers to f.box
func (f *Frame) growbox(delta int) {
f.nalloc += delta
f.box = append(f.box, make([]*frbox, delta)...)
// Now deep copy the byte array
// TODO(rjk): Adjust when we use strings.
cp.Ptr = make([]byte, len(b.Ptr))
copy(cp.Ptr, b.Ptr)
return cp
}

func (f *Frame) dupbox(bn int) {
if f.box[bn].Nrune < 0 {

func (f *Frame) dupbox(i int) {
if i >= len(f.box) {
panic("dupbox i is out of bounds")
}
if f.box[i].Nrune < 0 {
panic("dupbox invalid Nrune")
}

cp := new(frbox)
*cp = *f.box[bn]

f.addbox(bn, 1)
f.box[bn+1] = cp
nb := f.box[i].clone()
f.box = append(f.box, nil)
copy(f.box[i+1:], f.box[i:])
f.box[i] = nb

if f.box[bn].Nrune >= 0 {
p := make([]byte, len(f.box[bn].Ptr))
copy(p, f.box[bn].Ptr)
f.box[bn+1].Ptr = p
}
}

// TODO(rjk): Nicer way when we have a string for box contents.
func runeindex(p []byte, n int) int {
offs := 0
for i := 0; i < n; i++ {
Expand All @@ -97,6 +89,8 @@ func runeindex(p []byte, n int) int {
}

// truncatebox drops the last n characters from box b without allocation.
// TODO(rjk): make a method on a frbox
// TODO(rjk): measure height.
func (f *Frame) truncatebox(b *frbox, n int) {
if b.Nrune < 0 || b.Nrune < int(n) {
panic("truncatebox")
Expand All @@ -107,6 +101,7 @@ func (f *Frame) truncatebox(b *frbox, n int) {
}

// chopbox removes the first n chars from box b without allocation.
// TODO(rjk): measure height
func (f *Frame) chopbox(b *frbox, n int) {
if b.Nrune < 0 || b.Nrune < n {
panic("chopbox")
Expand Down Expand Up @@ -142,11 +137,13 @@ func (f *Frame) mergebox(bn int) {
// findbox finds the box containing q and puts q on a box boundary starting from
// rune p in box bn.
func (f *Frame) findbox(bn, p, q int) int {
for i := bn; bn < f.nbox && p+nrune(f.box[i]) <= q; i++ {
p += nrune(f.box[i])
for _, b := range f.box[bn:] {
if p + nrune(b) > q {
break
}
p += nrune(b)
bn++
}

if p != q {
f.splitbox(bn, q-p)
bn++
Expand Down
Loading

0 comments on commit cbd759e

Please sign in to comment.