Кристиан обнови решението на 04.11.2018 13:28 (преди 9 месеца)
+package main
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type Editor interface {
+ Insert(position uint, text string) Editor
+
+ Delete(offset, length uint) Editor
+
+ Undo() Editor
+
+ Redo() Editor
+
+ String() string
+}
+
+type PieceTable struct {
+ origin []byte
+ add []byte
+ pStack piecesStack
+ lastAddedOffset int
+}
+
+type piecesStack struct {
+ currentPieces []Piece
+ previousPieces []Piece
+ nextPieces []Piece
+}
+
+type Piece struct {
+ origin bool
+ offset int
+ length int
+}
+
+func (pieceTable *PieceTable) Insert(position uint, text string) Editor {
+ if position > uint(len(pieceTable.origin)+len(pieceTable.add)) {
+ position = uint(len(pieceTable.origin) + len(pieceTable.add))
+ }
+
+ pieceTable.add = append(pieceTable.add, text...)
+
+ newPieces := make([]Piece, 128)
+ counter := 0
+ isAdded := false
+
+ for _, piece := range pieceTable.pStack.currentPieces {
+ if piece.length > 0 {
+ if uint(counter+piece.length) >= position && !isAdded {
+ diff := int(position) - counter
+ firstPiece := Piece{origin: piece.origin, offset: piece.offset, length: diff}
+ secondPiece := Piece{origin: false, offset: pieceTable.lastAddedOffset, length: len(text)}
+ thirdPiece := Piece{origin: piece.origin, offset: piece.offset + diff, length: piece.length - diff}
+
+ newPieces = append(newPieces, firstPiece)
+ newPieces = append(newPieces, secondPiece)
+ newPieces = append(newPieces, thirdPiece)
+
+ pieceTable.lastAddedOffset += len(text)
+ isAdded = true
+ } else {
+ newPieces = append(newPieces, piece)
+ }
+ counter += piece.length
+ }
+ }
+ pieceTable.pStack.previousPieces = pieceTable.pStack.currentPieces
+ pieceTable.pStack.currentPieces = newPieces
+ pieceTable.pStack.nextPieces = nil
+
+ return pieceTable
+}
+
+func (pieceTable *PieceTable) Delete(offset, length uint) Editor {
+ if offset > uint(len(pieceTable.origin)+len(pieceTable.add)) {
+ return pieceTable
+ }
+ if offset+length > uint(len(pieceTable.origin)+len(pieceTable.add)) {
+ length = length + offset - uint(len(pieceTable.origin)+len(pieceTable.add))
+ }
+
+ newPieces := make([]Piece, 128)
+ counter := uint(0)
+ isDeletionStarted := false
+
+ for _, piece := range pieceTable.pStack.currentPieces {
+ if piece.length > 0 {
+ if counter+uint(piece.length) >= offset && length > 0 {
+ diff := int(offset - counter)
+ if !isDeletionStarted {
+ firstPiece := Piece{origin: piece.origin, offset: piece.offset, length: piece.offset + diff}
+ newPieces = append(newPieces, firstPiece)
+ isDeletionStarted = true
+ }
+ if uint(piece.length-diff) > length {
+ secondPiece := Piece{origin: piece.origin, offset: piece.offset + int(length) + 1, length: piece.length - int(length) - 1}
+ newPieces = append(newPieces, secondPiece)
+ length = 0
+ } else {
+ length -= uint(piece.length - diff)
+ }
+
+ } else {
+ newPieces = append(newPieces, piece)
+ }
+ counter += uint(piece.length)
+
+ if length > 0 {
+ offset = counter
+ }
+ }
+ }
+
+ pieceTable.pStack.previousPieces = pieceTable.pStack.currentPieces
+ pieceTable.pStack.currentPieces = newPieces
+ pieceTable.pStack.nextPieces = nil
+ return pieceTable
+}
+
+func (pieceTable *PieceTable) Redo() Editor {
+ if pieceTable.pStack.currentPieces != nil && pieceTable.pStack.nextPieces != nil {
+ pieceTable.pStack.currentPieces = pieceTable.pStack.nextPieces
+ }
+ return pieceTable
+}
+
+func (pieceTable *PieceTable) Undo() Editor {
+ if pieceTable.pStack.currentPieces != nil && pieceTable.pStack.previousPieces != nil {
+ pieceTable.pStack.nextPieces = pieceTable.pStack.currentPieces
+ pieceTable.pStack.currentPieces = pieceTable.pStack.previousPieces
+ }
+ return pieceTable
+}
+
+func (pieceTable *PieceTable) String() string {
+ var buffer bytes.Buffer
+
+ for _, piece := range pieceTable.pStack.currentPieces {
+ if piece.length > 0 {
+ if piece.origin {
+ buffer.WriteString(string(pieceTable.origin[piece.offset : piece.offset+piece.length]))
+ } else {
+ buffer.WriteString(string(pieceTable.add[piece.offset : piece.offset+piece.length]))
+ }
+ }
+ }
+
+ return buffer.String()
+}
+
+func NewEditor(text string) Editor {
+ initPieces := make([]Piece, 34)
+ piece := Piece{origin: true, offset: 0, length: len(text)}
+ initPieces[0] = piece
+ initStack := piecesStack{currentPieces: initPieces, previousPieces: nil, nextPieces: nil}
+ pieceTable := new(PieceTable)
+ pieceTable.origin = []byte(text)
+ pieceTable.pStack = initStack
+ return pieceTable
+}
+
+func main() {
+ var f = NewEditor("A large span of text")
+ f = f.Insert(16, "English ").Delete(2, 6)
+ fmt.Println(f.String())
+}