Слави обнови решението на 06.11.2018 03:38 (преди 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 table struct {
+ undo *table
+ redo *table
+ pieces []piece
+}
+
+func NewEditor(text string) Editor {
+ editor := new(table)
+ if text != "" {
+ editor.pieces = append(
+ editor.pieces,
+ createPiece(text),
+ )
+ }
+ return editor
+}
+
+func (self *table) String() (result string) {
+ for _, piece := range self.pieces {
+ result += string(piece[:])
+ }
+ return
+}
+
+func (self *table) Insert(
+ position uint,
+ text string,
+) Editor {
+ result := self.setupNext(len(self.pieces) + 2)
+ index, point := shouldSplitAt(self.pieces, position)
+ result.pieces = append(
+ result.pieces,
+ self.pieces[0:index]...,
+ )
+ if index < len(self.pieces) {
+ firstPart, secondPart := splitAt(
+ self.pieces[index],
+ point,
+ )
+ if len(firstPart) > 0 {
+ result.pieces = append(result.pieces, firstPart)
+ }
+ defer func() {
+ result.pieces = append(result.pieces, secondPart)
+ result.pieces = append(
+ result.pieces,
+ self.pieces[index+1:len(self.pieces)]...,
+ )
+ }()
+ }
+ result.pieces = append(result.pieces, createPiece(text))
+ return result
+}
+
+func (self *table) Delete(offset uint, length uint) Editor {
+ result := self.setupNext(len(self.pieces) + 1)
+ secondOffset := offset + length
+ index, point := shouldSplitAt(self.pieces, offset)
+ result.pieces = append(
+ result.pieces,
+ self.pieces[0:index]...,
+ )
+ if index < len(self.pieces) {
+ firstPart, _ := splitAt(
+ self.pieces[index],
+ point,
+ )
+ if len(firstPart) > 0 {
+ result.pieces = append(result.pieces, firstPart)
+ }
+ index, point := shouldSplitAt(
+ self.pieces,
+ secondOffset,
+ )
+ if index < len(self.pieces) {
+ _, secondPart := splitAt(
+ self.pieces[index],
+ point,
+ )
+ result.pieces = append(
+ result.pieces,
+ secondPart,
+ )
+ result.pieces = append(
+ result.pieces,
+ self.pieces[index+1:]...,
+ )
+ }
+ }
+ return result
+}
+
+func (self *table) Undo() Editor {
+ if self.undo == nil {
+ return self
+ }
+ return self.undo
+}
+
+func (self *table) Redo() Editor {
+ if self.redo == nil {
+ return self
+ }
+ return self.redo
+}
+
+func (self *table) setupNext(size int) (result *table) {
+ result = &table{
+ undo: self,
+ redo: nil,
+ pieces: make([]piece, 0, size),
+ }
+ self.redo = result
+ result.undo = self
+ return
+}
+
+func shouldSplitAt(
+ pieces []piece,
+ position uint,
+) (index int, point int) {
+ left := int(position)
+ for i, onePiece := range pieces {
+ if left < len(onePiece) {
+ return i, left
+ }
+ left -= len(onePiece)
+ }
+ return len(pieces), 0
+}
+
+func splitAt(toSplit piece, point int) (piece, piece) {
+ return toSplit[:point], toSplit[point:]
+}
+
+type piece []byte
+
+func createPiece(text string) piece {
+ return piece([]byte(text))
+}