Георги обнови решението на 07.11.2018 09:12 (преди 9 месеца)
+package main
+
+// Editor ...
+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 changes
+        Redo() Editor
+
+        // String returns the complete representation of what a file looks
+        // like after all manipulations
+        String() string
+}
+
+type piece struct {
+        origin bool
+        offset int
+        length int
+}
+
+// PieceTable ...
+type PieceTable struct {
+        Origin  []byte
+        Add     []byte
+        Table   []piece
+        State   [][]piece
+        indexAt uint
+}
+
+// NewEditor ...
+func NewEditor(file string) Editor {
+        initialTable := []piece{piece{origin: true, offset: 0, length: len([]byte(file))}}
+        return PieceTable{
+                Origin: []byte(file),
+                Table:  initialTable,
+                State:  [][]piece{initialTable},
+        }
+}
+
+// Insert ...
+func (p PieceTable) Insert(position uint, text string) Editor {
+        var pieceIndex, leftOffset, rightOffset, previousOffset, lengthUntilNow int
+        var pieceInIndex piece
+        for index, piece := range p.Table {
+                previousOffset = piece.offset
+                lengthUntilNow += piece.length
+                if lengthUntilNow >= int(position) {
+                        rightOffset = lengthUntilNow - int(position)
+                        leftOffset = piece.length - rightOffset
+                        pieceIndex, pieceInIndex = index, piece
+                        break
+                }
+        }
+
+        var newArr []piece
+        if int(position) > lengthUntilNow {
+                newPiece := piece{origin: false, offset: len(p.Add), length: len([]byte(text))}
+                p.Table = append(p.Table, newPiece)
+        } else {
+                newPiece := piece{origin: pieceInIndex.origin, offset: previousOffset, length: leftOffset}
+                newPiece1 := piece{origin: false, offset: len(p.Add), length: len([]byte(text))}
+                newPiece2 := piece{origin: pieceInIndex.origin, offset: previousOffset + leftOffset, length: rightOffset}
+
+                newArr = []piece{newPiece, newPiece1, newPiece2}
+                p.Table = append(p.Table[:pieceIndex], append(newArr, p.Table[pieceIndex+1:]...)...)
+        }
+
+        p.Add = append([]byte(p.Add), append([]byte(text))...)
+
+        p.indexAt = p.indexAt + 1
+        p.State = append(p.State, p.Table)
+
+        return p
+}
+
+// Delete ...
+func (p PieceTable) Delete(offset, length uint) Editor {
+        var pieceIndex, leftOffset, rightOffset, previousOffset, lengthUntilNow int
+        var pieceInIndex piece
+
+        for index, piece := range p.Table {
+                previousOffset = piece.offset
+                lengthUntilNow += piece.length
+                if lengthUntilNow >= int(offset) {
+                        rightOffset = lengthUntilNow - int(offset)
+                        leftOffset = piece.length - rightOffset
+                        pieceIndex, pieceInIndex = index, piece
+                        break
+                }
+        }
+
+        // Do nothing if beyond string
+        if int(offset) > lengthUntilNow {
+                return p
+        }
+
+        if int(length) > lengthUntilNow {
+                length = uint(lengthUntilNow)
+        }
+
+        var newPieces []piece
+        // when we stay in the same piece
+        if int(length) < rightOffset {
+                newPiece1 := piece{origin: pieceInIndex.origin, offset: previousOffset, length: leftOffset}
+                newPiece2 := piece{origin: pieceInIndex.origin, offset: previousOffset + leftOffset + int(length), length: rightOffset - int(length)}
+                newPieces = []piece{newPiece1, newPiece2}
+
+                p.Table = append(p.Table[:pieceIndex], append(newPieces, p.Table[pieceIndex+1:]...)...)
+        } else if int(length) == rightOffset {
+                newPiece := piece{origin: pieceInIndex.origin, offset: previousOffset, length: leftOffset}
+                newPieces = []piece{newPiece}
+                p.Table = append(p.Table[:pieceIndex], append(newPieces, p.Table[pieceIndex+1:]...)...)
+        } else {
+                length = uint(int(length) - int(rightOffset))
+                if length < 0 {
+                        length = 0
+                }
+                nextPiece := p.Table[pieceIndex+1]
+                if int(length) <= nextPiece.length {
+                        leftOffset = nextPiece.length - int(length)
+                        previousOffset = nextPiece.offset
+                        rightOffset = nextPiece.length
+                        leftOffset = rightOffset - int(length)
+                        pieceIndex = pieceIndex + 1
+
+                        newPiece1 := piece{origin: pieceInIndex.origin, offset: previousOffset, length: leftOffset}
+                        newPiece2 := piece{origin: pieceInIndex.origin, offset: previousOffset + leftOffset + int(length), length: rightOffset - int(length)}
+                        newPieces = []piece{newPiece1, newPiece2}
+                        p.Table = append(p.Table[:pieceIndex], append(newPieces, p.Table[pieceIndex+1:]...)...)
+                } else {
+                        for int(length) > rightOffset {
+                                nextPiece := p.Table[pieceIndex+1]
+                                previousOffset = nextPiece.offset
+                                rightOffset = nextPiece.length
+                        }
+                        newPiece1 := piece{origin: pieceInIndex.origin, offset: previousOffset, length: leftOffset}
+                        newPiece2 := piece{origin: pieceInIndex.origin, offset: previousOffset + leftOffset + int(length), length: rightOffset - int(length)}
+                        newPieces = append(newPieces, []piece{newPiece1, newPiece2}...)
+                        p.Table = append(p.Table[:pieceIndex], append(newPieces, p.Table[pieceIndex+1:]...)...)
+                }
+        }
+
+        p.indexAt = p.indexAt + 1
+        p.State = append(p.State, p.Table)
+
+        return p
+}
+
+// Undo ...
+func (p PieceTable) Undo() Editor {
+        if p.indexAt == 0 {
+                return p
+        }
+
+        p.indexAt = p.indexAt - 1
+        state := p.State[p.indexAt : p.indexAt+1]
+        p.Table = state[0]
+
+        return p
+}
+
+// Redo ...
+func (p PieceTable) Redo() Editor {
+        if int(p.indexAt) == len(p.State)-1 {
+                return p
+        }
+
+        p.indexAt = p.indexAt + 1
+        state := p.State[p.indexAt : p.indexAt+1]
+        p.Table = state[0]
+
+        return p
+}
+
+// String ...
+func (p PieceTable) String() string {
+        var s string
+        for _, piece := range p.Table {
+                if piece.origin {
+                        s += string(p.Origin[piece.offset:(piece.offset + piece.length)])
+                } else {
+                        s += string(p.Add[piece.offset:(piece.offset + piece.length)])
+                }
+        }
+
+        return s
+}
