Иван обнови решението на 07.11.2018 00:53 (преди 9 месеца)
+// Dragons below. Attempt to solve the homework in a small amount of time
+package main
+
+// EditorData is the struct containing all fragments and text buffers
+type EditorData struct {
+ originText string
+ addBuffer string
+ length uint
+ fragments []Fragment
+}
+
+// Fragment points to part of the buffer
+type Fragment struct {
+ origin bool
+ offset uint
+ length uint
+}
+
+// Editor interface
+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
+}
+
+// Insert a new blob of text data in the editor.
+func (e EditorData) Insert(position uint, text string) Editor {
+ if len(text) == 0 {
+ return e
+ }
+
+ var currentAddLength = uint(len(e.addBuffer))
+ e.addBuffer += text
+ e.length += uint(len(text))
+ index, cumulativeOffset := findPosition(&e, position)
+
+ newFragment := Fragment{origin: false, offset: currentAddLength, length: uint(len(text))}
+
+ if position >= cumulativeOffset+e.fragments[index].length {
+ e.fragments = append(e.fragments, newFragment)
+ } else {
+ oldFragment := e.fragments[index]
+ oldOffset := oldFragment.offset
+ inserts := []Fragment{
+ Fragment{origin: oldFragment.origin, offset: oldOffset, length: cumulativeOffset - oldOffset},
+ newFragment,
+ Fragment{origin: oldFragment.origin, offset: cumulativeOffset, length: oldFragment.length - cumulativeOffset + oldOffset},
+ }
+
+ e.fragments = append(e.fragments[:index], append(e.fragments[index+1:], inserts...)...)
+
+ }
+ return e
+}
+
+func findPosition(e *EditorData, position uint) (int, uint) {
+ for i, e := range e.fragments {
+ if position <= e.length {
+ return i, e.offset + position
+ }
+
+ position -= e.length
+ }
+ return 0, 0
+}
+
+// Delete deletes, such wow
+func (e EditorData) Delete(offset, length uint) Editor {
+ if offset >= e.length || length == 0 {
+ return e
+ }
+
+ // Delete could span multiple fragments
+ firstIndex, firstOffset := findPosition(&e, offset)
+ secondIndex, secondOffset := findPosition(&e, offset+length)
+
+ // But it also could not span multiple fragmemnts..
+ if firstIndex == secondIndex && firstOffset == e.fragments[firstIndex].offset {
+ e.fragments[firstIndex].length -= length
+ e.fragments[firstIndex].offset += length
+ return e
+ }
+
+ if firstIndex == secondIndex && e.fragments[firstIndex].offset+e.fragments[firstIndex].length == firstOffset {
+ e.fragments[firstIndex].length -= length
+ return e
+ }
+
+ first := e.fragments[firstIndex]
+ second := e.fragments[secondIndex]
+ inserts := []Fragment{
+ Fragment{origin: first.origin, offset: first.offset, length: firstOffset - first.offset},
+ Fragment{origin: second.origin, offset: secondOffset, length: second.length - secondOffset + second.offset},
+ }
+ e.fragments = append(e.fragments[:firstIndex], append(e.fragments[:secondIndex], inserts...)...)
+ return e
+}
+
+func (f EditorData) Undo() Editor {
+ return f
+}
+
+func (f EditorData) Redo() Editor {
+ return f
+}
+
+func (e EditorData) String() string {
+ var result string
+ for _, elem := range e.fragments {
+ if elem.origin {
+ result += e.originText[elem.offset : elem.offset+elem.length]
+ } else {
+ result += e.addBuffer[elem.offset : elem.offset+elem.length]
+
+ }
+ }
+ return result
+}
+
+// NewEditor creates a new editor
+func NewEditor(content string) Editor {
+ fragments := make([]Fragment, 0, 10)
+ f := Fragment{
+ origin: true,
+ offset: 0,
+ length: uint(len(content)),
+ }
+ fragments = append(fragments, f)
+
+ return EditorData{originText: content, fragments: fragments, length: uint(len(content))}
+}