Траян обнови решението на 07.11.2018 16:13 (преди 9 месеца)
+package main
+
+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 pieceTable struct {
+        origin bool
+        offset int
+        length int
+}
+
+type transition struct {
+        from []pieceTable
+        to   []pieceTable
+}
+
+type editor1 struct {
+        origin              string
+        add                 string
+        pceTbl              []pieceTable
+        textLenght          uint
+        transitionsBackward []transition
+        transitionsForward  []transition
+}
+
+func (editor editor1) Insert(position uint, text string) Editor {
+        if position > editor.textLenght {
+                position = editor.textLenght
+        }
+        editor.transitionsForward = []transition{}
+        editor.textLenght += uint(len(text))
+        i := 0
+        pieceOffset := position
+        for i = 0; i < len(editor.pceTbl) && pieceOffset >= uint(editor.pceTbl[i].length); i++ {
+                pieceOffset -= uint(editor.pceTbl[i].length)
+        }
+        if pieceOffset == 0 {
+                var oldPieces []pieceTable
+                newPiece := pieceTable{false, len(editor.add), len(text)}
+                editor.pceTbl = append(editor.pceTbl, newPiece)
+                copy(editor.pceTbl[i+1:], editor.pceTbl[i:len(editor.pceTbl)])
+                editor.pceTbl[i] = newPiece
+                newPieces := append([]pieceTable{}, newPiece)
+                oldPieces = []pieceTable{pieceTable{false, i, -1}}
+                editor.transitionsBackward = append(editor.transitionsBackward, transition{oldPieces, newPieces})
+        } else {
+                oldPieces := append([]pieceTable{}, editor.pceTbl[i])
+                firstPieceOfDividedElement := pieceTable{editor.pceTbl[i].origin,
+                        editor.pceTbl[i].offset, int(pieceOffset)}
+                newGluePiece := pieceTable{false, len(editor.add), len(text)}
+                secondPieceOfDividedElement := pieceTable{editor.pceTbl[i].origin,
+                        editor.pceTbl[i].offset + int(pieceOffset),
+                        editor.pceTbl[i].length - int(pieceOffset)}
+                newPieces := append([]pieceTable{}, firstPieceOfDividedElement, newGluePiece, secondPieceOfDividedElement)
+                editor.pceTbl = append(editor.pceTbl, firstPieceOfDividedElement, secondPieceOfDividedElement)
+                copy(editor.pceTbl[i+3:], editor.pceTbl[i+1:])
+                editor.pceTbl[i] = firstPieceOfDividedElement
+                editor.pceTbl[i+1] = newGluePiece
+                editor.pceTbl[i+2] = secondPieceOfDividedElement
+                editor.transitionsBackward = append(editor.transitionsBackward, transition{oldPieces, newPieces})
+        }
+        editor.add += text
+        return editor
+}
+
+func (editor editor1) Delete(offset, length uint) Editor {
+        if offset < editor.textLenght && length > 0 {
+                if offset+length > editor.textLenght {
+                        length = editor.textLenght - offset
+                }
+                editor.textLenght -= length
+                idx := 0
+                endIdx := 0
+                for idx = 0; idx < len(editor.pceTbl) && offset >= uint(editor.pceTbl[idx].length); idx++ {
+                        offset -= uint(editor.pceTbl[idx].length)
+                }
+                endIdx = idx
+                if length > uint(editor.pceTbl[idx].length)-offset {
+                        length -= uint(editor.pceTbl[idx].length) - offset
+                        for endIdx = idx + 1; endIdx < len(editor.pceTbl) && length >= uint(editor.pceTbl[endIdx].length); endIdx++ {
+                                length -= uint(editor.pceTbl[endIdx].length)
+                        }
+                }
+                if offset == 0 {
+                        var oldPieces []pieceTable
+                        if idx == 0 && endIdx > 0 {
+                                oldPieces = append(oldPieces, editor.pceTbl[idx:endIdx]...)
+                        } else if idx != 0 && endIdx != 0 {
+                                oldPieces = append([]pieceTable{}, editor.pceTbl[idx-1:endIdx-1]...)
+                        }
+                        var newPieces []pieceTable
+                        editor.pceTbl = append(editor.pceTbl[:idx], editor.pceTbl[endIdx:]...)
+                        if len(editor.pceTbl) > idx {
+                                oldPieces = append(oldPieces, editor.pceTbl[idx])
+                                copy(editor.pceTbl[:], append(editor.pceTbl[:idx], editor.pceTbl[idx+1:]...))
+                                editor.pceTbl = append(editor.pceTbl[:len(editor.pceTbl)-1])
+                                newPieces = append([]pieceTable{}, pieceTable{false, idx, -1})
+                        }
+                        editor.transitionsBackward = append(editor.transitionsBackward, transition{oldPieces, newPieces})
+                } else {
+                        if idx == endIdx {
+                                oldPieces := append([]pieceTable{}, editor.pceTbl[idx])
+                                firstPieceOfDividedElement := pieceTable{editor.pceTbl[idx].origin,
+                                        editor.pceTbl[idx].offset,
+                                        int(offset)}
+                                secondPieceOfDividedElement := pieceTable{editor.pceTbl[idx].origin,
+                                        editor.pceTbl[idx].offset + int(offset) + int(length),
+                                        editor.pceTbl[idx].length - (int(offset) + int(length))}
+                                newPieces := append([]pieceTable{}, firstPieceOfDividedElement, secondPieceOfDividedElement)
+
+                                editor.pceTbl = append(editor.pceTbl, firstPieceOfDividedElement)
+                                copy(editor.pceTbl[idx+2:], editor.pceTbl[idx+1:])
+                                editor.pceTbl[idx] = firstPieceOfDividedElement
+                                editor.pceTbl[idx+1] = secondPieceOfDividedElement
+                                editor.transitionsBackward = append(editor.transitionsBackward, transition{oldPieces, newPieces})
+                        } else {
+                                oldPieces := append([]pieceTable{}, editor.pceTbl[idx:endIdx]...)
+                                editor.pceTbl = append(editor.pceTbl[:idx+1], editor.pceTbl[endIdx:]...)
+                                firstOfTheFirstPiece := pieceTable{editor.pceTbl[idx].origin,
+                                        editor.pceTbl[idx].offset,
+                                        int(offset)}
+                                newPieces := append([]pieceTable{}, firstOfTheFirstPiece)
+                                if length != 0 {
+                                        oldPieces = append(oldPieces, editor.pceTbl[idx+1])
+                                        secondOfTheSecondPiece := pieceTable{editor.pceTbl[idx+1].origin,
+                                                editor.pceTbl[idx+1].offset + int(length),
+                                                editor.pceTbl[idx+1].length - int(length)}
+                                        editor.pceTbl[idx+1] = secondOfTheSecondPiece
+                                        newPieces = append(newPieces, secondOfTheSecondPiece)
+                                }
+                                editor.transitionsBackward = append(editor.transitionsBackward, transition{oldPieces, newPieces})
+                                editor.pceTbl[idx] = firstOfTheFirstPiece
+                        }
+                }
+        }
+        return editor
+}
+
+func (editor editor1) Undo() Editor {
+        if len(editor.transitionsBackward) > 0 {
+                backwTransitionsLastIndex := len(editor.transitionsBackward) - 1
+                undoTransition := editor.transitionsBackward[backwTransitionsLastIndex]
+                startIdx := 0
+                endIdx := 0
+                if undoTransition.from[0].length != -1 {
+                        if undoTransition.to[0].length != -1 {
+                                for i := 0; i < len(editor.pceTbl); i++ {
+                                        if undoTransition.to[0] == editor.pceTbl[i] {
+                                                startIdx = i
+                                                i = len(editor.pceTbl)
+                                        }
+                                }
+                                endIdx = startIdx + len(undoTransition.to)
+                                editor.pceTbl = append(editor.pceTbl[:startIdx], editor.pceTbl[endIdx:]...)
+                                for idx := 0; idx < len(undoTransition.from); idx++ {
+                                        editor.pceTbl = append(editor.pceTbl, pieceTable{})
+                                }
+                                copy(editor.pceTbl[startIdx+len(undoTransition.from):], editor.pceTbl[startIdx:])
+                                copy(editor.pceTbl[startIdx:startIdx+len(undoTransition.from)], undoTransition.from)
+                        } else {
+                                startIdx = undoTransition.to[0].offset
+                                for idx := 0; idx < len(undoTransition.from); idx++ {
+                                        editor.pceTbl = append(editor.pceTbl, pieceTable{})
+                                }
+
+                                copy(editor.pceTbl[startIdx+len(undoTransition.from):], editor.pceTbl[startIdx:])
+                                copy(editor.pceTbl[undoTransition.to[0].offset:undoTransition.to[0].offset+len(undoTransition.from)],
+                                        undoTransition.from[:])
+                        }
+                        editor.transitionsForward = append(editor.transitionsForward, undoTransition)
+                        editor.transitionsBackward = editor.transitionsBackward[:backwTransitionsLastIndex]
+                } else {
+                        editor.pceTbl = append(editor.pceTbl[:undoTransition.from[0].offset], editor.pceTbl[undoTransition.from[0].offset+1:]...)
+                        editor.transitionsForward = append(editor.transitionsForward, undoTransition)
+                        editor.transitionsBackward = editor.transitionsBackward[:backwTransitionsLastIndex]
+                }
+        }
+        return editor
+}
+
+func (editor editor1) Redo() Editor {
+        if len(editor.transitionsForward) > 0 {
+                forwTransitionsLastIndex := len(editor.transitionsForward) - 1
+                redoTransition := editor.transitionsForward[forwTransitionsLastIndex]
+                startIdx := 0
+                endIdx := 0
+                if redoTransition.from[0].length != -1 {
+                        if redoTransition.to[0].length != -1 {
+                                for i := 0; i < len(editor.pceTbl); i++ {
+                                        if redoTransition.from[0] == editor.pceTbl[i] {
+                                                startIdx = i
+                                                i = len(editor.pceTbl)
+                                        }
+                                }
+                                endIdx = startIdx + len(redoTransition.from)
+
+                                editor.pceTbl = append(editor.pceTbl[:startIdx], editor.pceTbl[endIdx:]...)
+
+                                for idx := 0; idx < len(redoTransition.to); idx++ {
+                                        editor.pceTbl = append(editor.pceTbl, pieceTable{})
+                                }
+                                copy(editor.pceTbl[startIdx+len(redoTransition.to):], editor.pceTbl[startIdx:])
+                                copy(editor.pceTbl[startIdx:startIdx+len(redoTransition.to)], redoTransition.to)
+                        } else {
+                                editor.pceTbl = append(editor.pceTbl[:redoTransition.to[0].offset], editor.pceTbl[redoTransition.to[0].offset+1:]...)
+                        }
+                } else {
+                        startIdx = redoTransition.from[0].offset
+                        for idx := 0; idx < len(redoTransition.to); idx++ {
+                                editor.pceTbl = append(editor.pceTbl, pieceTable{})
+                        }
+
+                        copy(editor.pceTbl[startIdx+len(redoTransition.to):], editor.pceTbl[startIdx:])
+                        copy(editor.pceTbl[redoTransition.from[0].offset:redoTransition.from[0].offset+len(redoTransition.to)],
+                                redoTransition.to[:])
+                }
+                editor.transitionsBackward = append(editor.transitionsBackward, redoTransition)
+                editor.transitionsForward = editor.transitionsForward[:forwTransitionsLastIndex]
+        }
+        return editor
+}
+
+func (editor editor1) String() string {
+        resultText := ""
+        for i := 0; i < len(editor.pceTbl); i++ {
+                if editor.pceTbl[i].origin == true {
+                        resultText += editor.origin[editor.pceTbl[i].offset:(editor.pceTbl[i].offset + editor.pceTbl[i].length)]
+                } else {
+                        resultText += editor.add[editor.pceTbl[i].offset:(editor.pceTbl[i].offset + editor.pceTbl[i].length)]
+                }
+        }
+        return resultText
+}
+
+func (editor editor1) GetAdd() string {
+        return editor.add
+}
+
+func (editor editor1) GetOriginLen() int {
+        return len(editor.origin)
+}
+
+func (editor editor1) GetAddLen() int {
+        return len(editor.add)
+}
+
+func NewEditor(editorContent string) Editor {
+        var editor = editor1{origin: editorContent, add: "",
+                pceTbl: []pieceTable{{
+                        true, 0, len(editorContent)}},
+                textLenght: uint(len(editorContent))}
+        return editor
+}
