Решение на Piece table от Димитър Петров

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

Към профила на Димитър Петров

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 7 успешни тест(а)
  • 1 неуспешни тест(а)

Код

package main
import (
"strings"
)
type Editor interface {
// Insert text starting from given position.
Insert(position uint, text string) Editor
// Delete length items from offset.
Delete(offset, length uint) Editor
// Undo reverts latest change.
Undo() Editor
// Redo re-applies latest undone change.
Redo() Editor
// String returns complete representation of what a file looks
// like after all manipulations.
String() string
}
type Storage struct {
origin []byte
add []byte
}
func (s *Storage) Initialize(text string) {
s.origin = []byte(text)
}
func (s *Storage) Add(text string) (position int, length int) {
position = len(s.add)
textInBytes := []byte(text)
length = len(textInBytes)
s.add = append(s.add, textInBytes...)
return
}
func (s *Storage) GetFromOriginBuffer(offset int, length int) string {
return string(s.origin[offset : offset+length])
}
func (s *Storage) GetFromAddBuffer(offset int, length int) string {
return string(s.add[offset : offset+length])
}
type Span struct {
origin bool
offset int
length int
}
type PieceTable struct {
storage Storage
spans []Span
}
func (pt *PieceTable) Initialize(text string) {
pt.storage.Initialize(text)
pt.spans = append(pt.spans, Span{origin: true, offset: 0, length: len([]byte(text))})
}
func (pt *PieceTable) Insert(position int, text string) {
posInAddBuffer, lengthInBytes := pt.storage.Add(text)
newSpan := Span{origin: false, offset: posInAddBuffer, length: lengthInBytes}
pt.insertSpan(position, newSpan)
}
func (pt *PieceTable) Delete(offset, length int) {
position := 0
start := offset
end := offset + length
flag := false
toBeDeleted := make([]int, 0)
for i, v := range pt.spans {
position += v.length
if position > start && position >= end && !flag {
pt.spans[i].length = offset - (position - v.length)
pt.insertSpansByIndex(i+1, Span{origin: v.origin, offset: pt.spans[i].offset + pt.spans[i].length + length, length: position - end})
break
} else if position > start && position < end && !flag {
flag = true
pt.spans[i].length = offset - (position - v.length)
} else if flag && position < end {
toBeDeleted = append(toBeDeleted, i)
} else if flag && position >= end {
pt.spans[i].offset += end - (position - v.length)
pt.spans[i].length -= end - (position - v.length)
break
}
}
for i := len(toBeDeleted) - 1; i >= 0; i-- {
pt.deleteSpanByIndex(toBeDeleted[i])
}
}
func (pt *PieceTable) String() string {
text := new(strings.Builder)
for _, v := range pt.spans {
if v.origin {
text.WriteString(pt.storage.GetFromOriginBuffer(v.offset, v.length))
} else {
text.WriteString(pt.storage.GetFromAddBuffer(v.offset, v.length))
}
}
return text.String()
}
func (pt *PieceTable) insertSpan(positionInFinalText int, span Span) {
position := 0
for i, v := range pt.spans {
position += v.length
if position > positionInFinalText {
pt.spans[i].length -= position - positionInFinalText
pt.insertSpansByIndex(i+1, span, Span{origin: v.origin, offset: pt.spans[i].length, length: position - positionInFinalText})
position = -1
break
}
}
if position != -1 {
pt.spans = append(pt.spans, span)
}
}
func (pt *PieceTable) insertSpansByIndex(pos int, spans ...Span) {
left := make([]Span, 0)
left = append(left, pt.spans[:pos]...)
left = append(left, spans...)
left = append(left, pt.spans[pos:]...)
pt.spans = left
}
func (pt *PieceTable) deleteSpanByIndex(i int) {
pt.spans = append(pt.spans[:i], pt.spans[i+1:]...)
}
type SimpleEditor struct {
pt PieceTable
undoStack []PieceTable
redoStack []PieceTable
}
func (se *SimpleEditor) Initialize(text string) {
se.pt.Initialize(text)
}
func (se *SimpleEditor) Insert(position uint, text string) Editor {
if len(se.redoStack) > 0 {
se.redoStack = se.redoStack[0:0]
}
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt.Insert(int(position), text)
return se
}
func (se *SimpleEditor) Delete(offset, length uint) Editor {
if len(se.redoStack) > 0 {
se.redoStack = se.redoStack[0:0]
}
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt.Delete(int(offset), int(length))
return se
}
func (se *SimpleEditor) Undo() Editor {
if len(se.undoStack) > 0 {
se.redoStack = append(se.redoStack, CopyPieceTable(se.pt))
se.pt = se.undoStack[len(se.undoStack)-1]
se.undoStack = se.undoStack[:len(se.undoStack)-1]
}
return se
}
func (se *SimpleEditor) Redo() Editor {
if len(se.redoStack) > 0 {
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt = se.redoStack[len(se.redoStack)-1]
se.redoStack = se.redoStack[:len(se.redoStack)-1]
}
return se
}
func (se *SimpleEditor) String() string {
return se.pt.String()
}
func CopyPieceTable(pt PieceTable) PieceTable {
newPt := new(PieceTable)
newPt.storage = pt.storage
newPt.spans = make([]Span, len(pt.spans))
copy(newPt.spans, pt.spans)
return *newPt
}
func NewEditor(text string) Editor {
result := new(SimpleEditor)
result.pt.Initialize(text)
return result
}

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

PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
PASS
ok  	_/tmp/d20181107-53-1uoatt6	0.002s
--- FAIL: TestUnicode (0.00s)
    solution_test.go:75: Expect: "Жълтата дюля беше щастлива, че пухът, който цъфна, замръзна като гьон."; got "Жълтата дюля беше щастлива, че пухът, който цъфна,Жълтата дюля беше щ\xd0"
FAIL
exit status 1
FAIL	_/tmp/d20181107-53-1uoatt6	0.002s

История (2 версии и 3 коментара)

Димитър обнови решението на 03.11.2018 18:32 (преди 9 месеца)

+package main
+
+import (
+ "strings"
+)
+
+type Editor interface {
+ // Insert text starting from given position.
+ Insert(position uint, text string) Editor
+
+ // Delete length items from offset.
+ Delete(offset, length uint) Editor
+
+ // Undo reverts latest change.
+ Undo() Editor
+
+ // Redo re-applies latest undone change.
+ Redo() Editor
+
+ // String returns complete representation of what a file looks
+ // like after all manipulations.
+ String() string
+}
+
+type Storage struct {
+ origin []byte
+ add []byte
+}
+
+func (s *Storage) Initialize(text string) {
+ s.origin = []byte(text)
+}
+
+func (s *Storage) Add(text string) (position int, length int) {
+ position = len(s.add)
+ textInBytes := []byte(text)
+ length = len(textInBytes)
+ s.add = append(s.add, textInBytes...)
+ return
+}
+
+func (s *Storage) GetFromOriginBuffer(offset int, length int) string {
+ return string(s.origin[offset : offset+length])
+}
+
+func (s *Storage) GetFromAddBuffer(offset int, length int) string {
+ return string(s.add[offset : offset+length])
+}
+
+type Span struct {
+ origin bool
+ offset int
+ length int
+}
+
+type PieceTable struct {
+ storage Storage
+ spans []Span
+}
+
+func (pt *PieceTable) Initialize(text string) {
+ pt.storage.Initialize(text)
+ pt.spans = append(pt.spans, Span{origin: true, offset: 0, length: len([]byte(text))})
+}
+
+func (pt *PieceTable) Insert(position int, text string) {
+ posInAddBuffer, lengthInBytes := pt.storage.Add(text)
+ newSpan := Span{origin: false, offset: posInAddBuffer, length: lengthInBytes}
+ pt.insertSpan(position, newSpan)
+}
+
+func (pt *PieceTable) Delete(offset, length int) {
+ position := 0
+ start := offset
+ end := offset + length
+ flag := false
+ for i, v := range pt.spans {
+ position += v.length
+ if position > start && position >= end && !flag {
+ pt.spans[i].length = offset - (position - v.length)
+ pt.insertSpansByIndex(i+1, Span{origin: v.origin, offset: pt.spans[i].offset + pt.spans[i].length + length, length: position - end})
+ break
+ } else if position > start && position < end && !flag {
+ flag = true
+ pt.spans[i].length = offset - (position - v.length)
+ } else if flag && position < end {
+ defer pt.deleteSpanByIndex(i)
+ } else if flag && position >= end {
+ pt.spans[i].offset += end - (position - v.length)
+ pt.spans[i].length -= end - (position - v.length)
+ break
+ }
+ }
+}
+
+func (pt *PieceTable) String() string {
+ text := new(strings.Builder)
+ for _, v := range pt.spans {
+ if v.origin {
+ text.WriteString(pt.storage.GetFromOriginBuffer(v.offset, v.length))
+ } else {
+ text.WriteString(pt.storage.GetFromAddBuffer(v.offset, v.length))
+ }
+ }
+ return text.String()
+}
+
+func (pt *PieceTable) insertSpan(positionInFinalText int, span Span) {
+ position := 0
+ for i, v := range pt.spans {
+ position += v.length
+ if position > positionInFinalText {
+ pt.spans[i].length -= position - positionInFinalText
+ pt.insertSpansByIndex(i+1, span, Span{origin: v.origin, offset: pt.spans[i].length, length: position - positionInFinalText})
+ position = -1
+ break
+ }
+ }
+ if position != -1 {
+ pt.spans = append(pt.spans, span)
+ }
+}
+
+func (pt *PieceTable) insertSpansByIndex(pos int, spans ...Span) {
+ left := make([]Span, 0)
+ left = append(left, pt.spans[:pos]...)
+ left = append(left, spans...)
+ left = append(left, pt.spans[pos:]...)
+ pt.spans = left
+}
+
+func (pt *PieceTable) deleteSpanByIndex(i int) {
+ pt.spans = append(pt.spans[:i], pt.spans[i+1:]...)
+}
+
+type SimpleEditor struct {
+ pt PieceTable
+ undoStack []PieceTable
+ redoStack []PieceTable
+}
+
+func (se *SimpleEditor) Initialize(text string) {
+ se.pt.Initialize(text)
+}
+
+func (se *SimpleEditor) Insert(position uint, text string) Editor {
+ if len(se.redoStack) > 0 {
+ se.redoStack = se.redoStack[0:0]
+ }
+ se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
+ se.pt.Insert(int(position), text)
+ return se
+}
+
+func (se *SimpleEditor) Delete(offset, length uint) Editor {
+ if len(se.redoStack) > 0 {
+ se.redoStack = se.redoStack[0:0]
+ }
+ se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
+ se.pt.Delete(int(offset), int(length))
+ return se
+}
+
+func (se *SimpleEditor) Undo() Editor {
+ if len(se.undoStack) > 0 {
+ se.redoStack = append(se.redoStack, CopyPieceTable(se.pt))
+ se.pt = se.undoStack[len(se.undoStack)-1]
+ se.undoStack = se.undoStack[:len(se.undoStack)-1]
+ }
+ return se
+}
+
+func (se *SimpleEditor) Redo() Editor {
+ if len(se.redoStack) > 0 {
+ se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
+ se.pt = se.redoStack[len(se.redoStack)-1]
+ se.redoStack = se.redoStack[:len(se.redoStack)-1]
+ }
+ return se
+}
+
+func (se *SimpleEditor) String() string {
+ return se.pt.String()
+}
+
+func CopyPieceTable(pt PieceTable) PieceTable {
+ newPt := new(PieceTable)
+ newPt.storage = pt.storage
+ newPt.spans = make([]Span, len(pt.spans))
+ copy(newPt.spans, pt.spans)
+ return *newPt
+}
+
+func NewEditor(text string) Editor {
+ result := new(SimpleEditor)
+ result.pt.Initialize(text)
+ return result
+}

Димитър обнови решението на 04.11.2018 18:08 (преди 9 месеца)

package main
import (
"strings"
)
type Editor interface {
// Insert text starting from given position.
Insert(position uint, text string) Editor
// Delete length items from offset.
Delete(offset, length uint) Editor
// Undo reverts latest change.
Undo() Editor
// Redo re-applies latest undone change.
Redo() Editor
// String returns complete representation of what a file looks
// like after all manipulations.
String() string
}
type Storage struct {
origin []byte
add []byte
}
func (s *Storage) Initialize(text string) {
s.origin = []byte(text)
}
func (s *Storage) Add(text string) (position int, length int) {
position = len(s.add)
textInBytes := []byte(text)
length = len(textInBytes)
s.add = append(s.add, textInBytes...)
return
}
func (s *Storage) GetFromOriginBuffer(offset int, length int) string {
return string(s.origin[offset : offset+length])
}
func (s *Storage) GetFromAddBuffer(offset int, length int) string {
return string(s.add[offset : offset+length])
}
type Span struct {
origin bool
offset int
length int
}
type PieceTable struct {
storage Storage
spans []Span
}
func (pt *PieceTable) Initialize(text string) {
pt.storage.Initialize(text)
pt.spans = append(pt.spans, Span{origin: true, offset: 0, length: len([]byte(text))})
}
func (pt *PieceTable) Insert(position int, text string) {
posInAddBuffer, lengthInBytes := pt.storage.Add(text)
newSpan := Span{origin: false, offset: posInAddBuffer, length: lengthInBytes}
pt.insertSpan(position, newSpan)
}
func (pt *PieceTable) Delete(offset, length int) {
position := 0
start := offset
end := offset + length
flag := false
+ toBeDeleted := make([]int, 0)
for i, v := range pt.spans {
position += v.length
if position > start && position >= end && !flag {
pt.spans[i].length = offset - (position - v.length)
pt.insertSpansByIndex(i+1, Span{origin: v.origin, offset: pt.spans[i].offset + pt.spans[i].length + length, length: position - end})
break
} else if position > start && position < end && !flag {
flag = true
pt.spans[i].length = offset - (position - v.length)
} else if flag && position < end {
- defer pt.deleteSpanByIndex(i)
+ toBeDeleted = append(toBeDeleted, i)
} else if flag && position >= end {
pt.spans[i].offset += end - (position - v.length)
pt.spans[i].length -= end - (position - v.length)
break
}
+ }
+ for i := len(toBeDeleted) - 1; i >= 0; i-- {
+ pt.deleteSpanByIndex(toBeDeleted[i])
}
}
func (pt *PieceTable) String() string {
text := new(strings.Builder)
for _, v := range pt.spans {
if v.origin {
text.WriteString(pt.storage.GetFromOriginBuffer(v.offset, v.length))
} else {
text.WriteString(pt.storage.GetFromAddBuffer(v.offset, v.length))
}
}
return text.String()
}
func (pt *PieceTable) insertSpan(positionInFinalText int, span Span) {
position := 0
for i, v := range pt.spans {
position += v.length
if position > positionInFinalText {
pt.spans[i].length -= position - positionInFinalText
pt.insertSpansByIndex(i+1, span, Span{origin: v.origin, offset: pt.spans[i].length, length: position - positionInFinalText})
position = -1
break
}
}
if position != -1 {
pt.spans = append(pt.spans, span)
}
}
func (pt *PieceTable) insertSpansByIndex(pos int, spans ...Span) {
left := make([]Span, 0)
left = append(left, pt.spans[:pos]...)
left = append(left, spans...)
left = append(left, pt.spans[pos:]...)
pt.spans = left
}
func (pt *PieceTable) deleteSpanByIndex(i int) {
pt.spans = append(pt.spans[:i], pt.spans[i+1:]...)
}
type SimpleEditor struct {
pt PieceTable
undoStack []PieceTable
redoStack []PieceTable
}
func (se *SimpleEditor) Initialize(text string) {
se.pt.Initialize(text)
}
func (se *SimpleEditor) Insert(position uint, text string) Editor {
if len(se.redoStack) > 0 {
se.redoStack = se.redoStack[0:0]
}
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt.Insert(int(position), text)
return se
}
func (se *SimpleEditor) Delete(offset, length uint) Editor {
if len(se.redoStack) > 0 {
se.redoStack = se.redoStack[0:0]
}
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt.Delete(int(offset), int(length))
return se
}
func (se *SimpleEditor) Undo() Editor {
if len(se.undoStack) > 0 {
se.redoStack = append(se.redoStack, CopyPieceTable(se.pt))
se.pt = se.undoStack[len(se.undoStack)-1]
se.undoStack = se.undoStack[:len(se.undoStack)-1]
}
return se
}
func (se *SimpleEditor) Redo() Editor {
if len(se.redoStack) > 0 {
se.undoStack = append(se.undoStack, CopyPieceTable(se.pt))
se.pt = se.redoStack[len(se.redoStack)-1]
se.redoStack = se.redoStack[:len(se.redoStack)-1]
}
return se
}
func (se *SimpleEditor) String() string {
return se.pt.String()
}
func CopyPieceTable(pt PieceTable) PieceTable {
newPt := new(PieceTable)
newPt.storage = pt.storage
newPt.spans = make([]Span, len(pt.spans))
copy(newPt.spans, pt.spans)
return *newPt
}
func NewEditor(text string) Editor {
result := new(SimpleEditor)
result.pt.Initialize(text)
return result
}
  • Правиш методи Initialize на свои типове, което не е добра идея в Go. Защо е нужно те да съществуват извън New... функциите?
  • Логиката в PieceTable.Delete е твърде сложна. Дори не мога да предположа колко добре работи. Опитай се да генерализираш малко.