Георги обнови решението на 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
+}