Решение на Piece table от Красена Давидова

Обратно към всички решения

Към профила на Красена Давидова

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 4 успешни тест(а)
  • 4 неуспешни тест(а)

Код

package main
import (
"math"
)
type Editor interface {
Insert(position uint, text string) Editor
Delete(offset uint, length int) Editor
Undo() Editor
Redo() Editor
String() string
}
type Buff struct {
origin bool
offset uint
length int
text string
}
var t []*Buff // current version of the editor
var versions [][]*Buff // all version of the editor
var indexVersion int // on what version is the editor
var add Buff // add buffer
var posAdd int // where to add the text in the add buffer
func (b *Buff) Insert(position uint, text string) Editor {
a, pos := findPosition(t, position)
var before, current, newcurrent, after []*Buff
var helpLeft, helpRight *Buff
before = t[:a]
current = append(current, t[a])
after = t[a+1:]
add.text = add.text + text
helper := &Buff{origin: false, offset: uint(posAdd), length: len(text), text: text}
posAdd += len(text)
if pos-len(b.String()) > 1 { // if adding is at end and is far from the original text
helpLeft = &Buff{origin: true, offset: current[0].offset, length: current[0].length, text: current[0].text}
newcurrent = append(newcurrent, helpLeft, helper)
} else {
helpLeft = &Buff{origin: true, offset: current[0].offset, length: len(current[0].text[:pos]), text: current[0].text[:pos]}
helpRight = &Buff{origin: true, offset: helpLeft.offset + uint(helpLeft.length), length: len(current[0].text[pos:]), text: current[0].text[pos:]}
newcurrent = append(newcurrent, helpLeft, helper, helpRight)
}
newAfter := make([]*Buff, len(after))
copy(newAfter, after)
x := append(before, newcurrent...)
x = append(x, newAfter...)
t = make([]*Buff, len(x))
copy(t, x)
versions = append(versions, x)
indexVersion += 1
return b
}
func (b *Buff) Delete(offset uint, length int) Editor {
if len(b.String()) < int(offset) { // if the text to be deleted is at offset more than the length of the editor
a := &Buff{origin: b.origin, offset: b.offset, length: b.length, text: b.text}
t = nil
t = append(t, a)
versions = append(versions, t)
indexVersion += 1
return a
}
var before, current, after []*Buff
i, place := findPosition(t, offset)
before = t[:i]
current = append(current, t[i])
after = t[i+1:]
if t[i].length >= length { // if the text is inside one buffer
helpBefore := &Buff{origin: current[0].origin, offset: current[0].offset, length: len(current[0].text[:place]), text: current[0].text[:place]}
helpAfter := &Buff{origin: current[0].origin, offset: uint(helpBefore.length + length), length: len(current[0].text[helpBefore.length+length:]), text: current[0].text[helpBefore.length+length:]}
var newcurrent []*Buff
newcurrent = append(newcurrent, helpBefore, helpAfter)
newAfter := make([]*Buff, len(after))
copy(newAfter, after)
newBefore := make([]*Buff, len(before))
copy(newBefore, before)
x := append(newBefore, newcurrent...)
x = append(x, newAfter...)
t = make([]*Buff, len(x))
copy(t, x)
} else { // if text to be deleted is in two or more buffers
helper := &Buff{origin: current[0].origin, offset: uint(place), length: len(current[0].text[:place]), text: current[0].text[:place]}
var newLength int
newLength = length - len(current[0].text[i:])
var place int
for _, val := range after {
if newLength < val.length {
break
} else {
newLength -= len(val.text)
place += 1
}
}
if place == len(after) && len(after[len(after)-1].text) < newLength { // if we want to delete out of the string
before = append(before, helper)
t = make([]*Buff, len(before))
copy(t, before)
} else { //if the text is in the correct buffer
newcurrent := &Buff{origin: after[place].origin, offset: after[place].offset + uint(newLength), length: len(after[place].text[newLength:]), text: after[place].text[newLength:]}
newAfter := after[place+1:]
newBefore := make([]*Buff, len(before))
copy(newBefore, before)
x := append(newBefore, newcurrent)
x = append(x, newAfter...)
t = make([]*Buff, len(x))
copy(t, x)
}
}
versions = append(versions, t)
indexVersion += 1
return b
}
func (b *Buff) Undo() Editor {
if indexVersion == 0 {
return b
} else {
var cnt int
for _, value := range versions {
if cnt == indexVersion-1 {
t = value
break
} else {
cnt += 1
}
}
indexVersion -= 1
return b
}
}
func (b *Buff) Redo() Editor {
if indexVersion == len(versions)-1 {
return b
}
var cnt int
for _, value := range versions {
if cnt == indexVersion+1 {
t = value
break
} else {
cnt += 1
}
}
indexVersion += 1
return b
}
func (b *Buff) String() string {
var res string
for _, value := range t {
res = res + value.text
}
return res
}
func findPosition(t []*Buff, position uint) (i, place int) {
var sum int
if position == 0 {
return i, int(position)
}
for _, value := range t {
if sum >= int(position) {
break
} else {
sum += value.length
i += 1
}
}
sum = int(math.Abs(float64(sum - t[i-1].length)))
place = int(math.Abs(float64(sum - int(position))))
return i - 1, place
}
func NewEditor(s string) Editor {
var r = &Buff{origin: true, offset: 0, length: len(s), text: s}
t = nil
t = append(t, r)
indexVersion = 0
versions = nil
versions = append(versions, t)
return r
}

Лог от изпълнението

--- FAIL: TestExampleFromReadme (0.00s)
panic: runtime error: slice bounds out of range [recovered]
	panic: runtime error: slice bounds out of range

goroutine 6 [running]:
testing.tRunner.func1(0xc0000b2100)
	/usr/local/go/src/testing/testing.go:792 +0x387
panic(0x513fe0, 0x61bff0)
	/usr/local/go/src/runtime/panic.go:513 +0x1b9
_/tmp/d20181107-53-1y0qybs.(*Buff).Delete(0xc00000e360, 0xa, 0x8, 0xc000014300, 0x16)
	/tmp/d20181107-53-1y0qybs/solution.go:72 +0x117f
_/tmp/d20181107-53-1y0qybs.TestExampleFromReadme(0xc0000b2100)
	/tmp/d20181107-53-1y0qybs/solution_test.go:14 +0x2f1
testing.tRunner(0xc0000b2100, 0x541948)
	/usr/local/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x353
exit status 2
FAIL	_/tmp/d20181107-53-1y0qybs	0.004s
--- FAIL: TestOutOfBound (0.00s)
    solution_test.go:75: Expect: "A span of text!"; got "A span of text"
panic: runtime error: index out of range [recovered]
	panic: runtime error: index out of range

goroutine 6 [running]:
testing.tRunner.func1(0xc0000b2100)
	/usr/local/go/src/testing/testing.go:792 +0x387
panic(0x513fe0, 0x61bfe0)
	/usr/local/go/src/runtime/panic.go:513 +0x1b9
_/tmp/d20181107-53-1y0qybs.(*Buff).Delete(0xc00000e360, 0x9, 0xc8, 0x53a37c, 0xe)
	/tmp/d20181107-53-1y0qybs/solution.go:96 +0x1155
_/tmp/d20181107-53-1y0qybs.TestOutOfBound(0xc0000b2100)
	/tmp/d20181107-53-1y0qybs/solution_test.go:23 +0x35d
testing.tRunner(0xc0000b2100, 0x541958)
	/usr/local/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x353
exit status 2
FAIL	_/tmp/d20181107-53-1y0qybs	0.005s
PASS
ok  	_/tmp/d20181107-53-1y0qybs	0.002s
--- FAIL: TestSeveralUndos (0.00s)
panic: runtime error: slice bounds out of range [recovered]
	panic: runtime error: slice bounds out of range

goroutine 6 [running]:
testing.tRunner.func1(0xc0000b0100)
	/usr/local/go/src/testing/testing.go:792 +0x387
panic(0x513fe0, 0x61bff0)
	/usr/local/go/src/runtime/panic.go:513 +0x1b9
_/tmp/d20181107-53-1y0qybs.(*Buff).Delete(0xc00000e360, 0xa, 0x8, 0x557780, 0xc00000e360)
	/tmp/d20181107-53-1y0qybs/solution.go:72 +0x117f
_/tmp/d20181107-53-1y0qybs.TestSeveralUndos(0xc0000b0100)
	/tmp/d20181107-53-1y0qybs/solution_test.go:37 +0x247
testing.tRunner(0xc0000b0100, 0x541970)
	/usr/local/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x353
exit status 2
FAIL	_/tmp/d20181107-53-1y0qybs	0.004s
PASS
ok  	_/tmp/d20181107-53-1y0qybs	0.002s
--- FAIL: TestSeveralRedos (0.00s)
panic: runtime error: slice bounds out of range [recovered]
	panic: runtime error: slice bounds out of range

goroutine 6 [running]:
testing.tRunner.func1(0xc0000b0100)
	/usr/local/go/src/testing/testing.go:792 +0x387
panic(0x513fe0, 0x61bff0)
	/usr/local/go/src/runtime/panic.go:513 +0x1b9
_/tmp/d20181107-53-1y0qybs.(*Buff).Delete(0xc00000e360, 0xa, 0x8, 0x557780, 0xc00000e360)
	/tmp/d20181107-53-1y0qybs/solution.go:72 +0x117f
_/tmp/d20181107-53-1y0qybs.TestSeveralRedos(0xc0000b0100)
	/tmp/d20181107-53-1y0qybs/solution_test.go:52 +0x247
testing.tRunner(0xc0000b0100, 0x541968)
	/usr/local/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x353
exit status 2
FAIL	_/tmp/d20181107-53-1y0qybs	0.004s
PASS
ok  	_/tmp/d20181107-53-1y0qybs	0.002s
PASS
ok  	_/tmp/d20181107-53-1y0qybs	0.002s

История (1 версия и 0 коментара)

Красена обнови решението на 07.11.2018 15:59 (преди 9 месеца)

+package main
+
+import (
+ "math"
+)
+
+type Editor interface {
+ Insert(position uint, text string) Editor
+ Delete(offset uint, length int) Editor
+ Undo() Editor
+ Redo() Editor
+ String() string
+}
+
+type Buff struct {
+ origin bool
+ offset uint
+ length int
+ text string
+}
+
+var t []*Buff // current version of the editor
+var versions [][]*Buff // all version of the editor
+var indexVersion int // on what version is the editor
+var add Buff // add buffer
+var posAdd int // where to add the text in the add buffer
+
+func (b *Buff) Insert(position uint, text string) Editor {
+ a, pos := findPosition(t, position)
+ var before, current, newcurrent, after []*Buff
+ var helpLeft, helpRight *Buff
+ before = t[:a]
+ current = append(current, t[a])
+ after = t[a+1:]
+ add.text = add.text + text
+ helper := &Buff{origin: false, offset: uint(posAdd), length: len(text), text: text}
+ posAdd += len(text)
+ if pos-len(b.String()) > 1 { // if adding is at end and is far from the original text
+ helpLeft = &Buff{origin: true, offset: current[0].offset, length: current[0].length, text: current[0].text}
+ newcurrent = append(newcurrent, helpLeft, helper)
+ } else {
+ helpLeft = &Buff{origin: true, offset: current[0].offset, length: len(current[0].text[:pos]), text: current[0].text[:pos]}
+ helpRight = &Buff{origin: true, offset: helpLeft.offset + uint(helpLeft.length), length: len(current[0].text[pos:]), text: current[0].text[pos:]}
+ newcurrent = append(newcurrent, helpLeft, helper, helpRight)
+ }
+ newAfter := make([]*Buff, len(after))
+ copy(newAfter, after)
+ x := append(before, newcurrent...)
+ x = append(x, newAfter...)
+ t = make([]*Buff, len(x))
+ copy(t, x)
+ versions = append(versions, x)
+ indexVersion += 1
+ return b
+}
+func (b *Buff) Delete(offset uint, length int) Editor {
+ if len(b.String()) < int(offset) { // if the text to be deleted is at offset more than the length of the editor
+ a := &Buff{origin: b.origin, offset: b.offset, length: b.length, text: b.text}
+ t = nil
+ t = append(t, a)
+ versions = append(versions, t)
+ indexVersion += 1
+ return a
+ }
+ var before, current, after []*Buff
+ i, place := findPosition(t, offset)
+ before = t[:i]
+ current = append(current, t[i])
+ after = t[i+1:]
+ if t[i].length >= length { // if the text is inside one buffer
+ helpBefore := &Buff{origin: current[0].origin, offset: current[0].offset, length: len(current[0].text[:place]), text: current[0].text[:place]}
+ helpAfter := &Buff{origin: current[0].origin, offset: uint(helpBefore.length + length), length: len(current[0].text[helpBefore.length+length:]), text: current[0].text[helpBefore.length+length:]}
+ var newcurrent []*Buff
+ newcurrent = append(newcurrent, helpBefore, helpAfter)
+ newAfter := make([]*Buff, len(after))
+ copy(newAfter, after)
+ newBefore := make([]*Buff, len(before))
+ copy(newBefore, before)
+ x := append(newBefore, newcurrent...)
+ x = append(x, newAfter...)
+ t = make([]*Buff, len(x))
+ copy(t, x)
+ } else { // if text to be deleted is in two or more buffers
+ helper := &Buff{origin: current[0].origin, offset: uint(place), length: len(current[0].text[:place]), text: current[0].text[:place]}
+ var newLength int
+ newLength = length - len(current[0].text[i:])
+ var place int
+ for _, val := range after {
+ if newLength < val.length {
+ break
+ } else {
+ newLength -= len(val.text)
+ place += 1
+ }
+ }
+ if place == len(after) && len(after[len(after)-1].text) < newLength { // if we want to delete out of the string
+ before = append(before, helper)
+ t = make([]*Buff, len(before))
+ copy(t, before)
+ } else { //if the text is in the correct buffer
+ newcurrent := &Buff{origin: after[place].origin, offset: after[place].offset + uint(newLength), length: len(after[place].text[newLength:]), text: after[place].text[newLength:]}
+ newAfter := after[place+1:]
+ newBefore := make([]*Buff, len(before))
+ copy(newBefore, before)
+ x := append(newBefore, newcurrent)
+ x = append(x, newAfter...)
+ t = make([]*Buff, len(x))
+ copy(t, x)
+ }
+ }
+ versions = append(versions, t)
+ indexVersion += 1
+ return b
+}
+
+func (b *Buff) Undo() Editor {
+ if indexVersion == 0 {
+ return b
+ } else {
+ var cnt int
+ for _, value := range versions {
+ if cnt == indexVersion-1 {
+ t = value
+ break
+ } else {
+ cnt += 1
+ }
+ }
+ indexVersion -= 1
+ return b
+ }
+}
+
+func (b *Buff) Redo() Editor {
+ if indexVersion == len(versions)-1 {
+ return b
+ }
+ var cnt int
+ for _, value := range versions {
+ if cnt == indexVersion+1 {
+ t = value
+ break
+ } else {
+ cnt += 1
+ }
+ }
+ indexVersion += 1
+ return b
+}
+
+func (b *Buff) String() string {
+ var res string
+ for _, value := range t {
+ res = res + value.text
+ }
+ return res
+}
+
+func findPosition(t []*Buff, position uint) (i, place int) {
+ var sum int
+ if position == 0 {
+ return i, int(position)
+ }
+ for _, value := range t {
+ if sum >= int(position) {
+ break
+ } else {
+ sum += value.length
+ i += 1
+ }
+ }
+ sum = int(math.Abs(float64(sum - t[i-1].length)))
+ place = int(math.Abs(float64(sum - int(position))))
+ return i - 1, place
+}
+
+func NewEditor(s string) Editor {
+ var r = &Buff{origin: true, offset: 0, length: len(s), text: s}
+ t = nil
+ t = append(t, r)
+ indexVersion = 0
+ versions = nil
+ versions = append(versions, t)
+ return r
+}