Хакан обнови решението на 06.11.2018 17:56 (преди 9 месеца)
+package main
+
+import (
+        "math"
+)
+
+type Editor interface {
+        Insert(position uint, text string) Editor
+        Delete(offset, length uint) Editor
+        Undo() Editor
+        Redo() Editor
+        String() string
+}
+
+type Piece struct {
+        origin bool
+        offset int
+        length int
+}
+
+type HistoryItem struct {
+        typeOfModif uint
+        offset      int
+        length      int
+}
+type History struct {
+        changes  []HistoryItem
+        position uint
+}
+
+type MyEditor struct {
+        originBuffer string
+        addBuffer    string
+        pTable       []Piece
+        changeLog    History
+}
+
+func NewEditor(str string) MyEditor {
+        var chLog History
+        arrOfP := make([]Piece, 1)
+        arrOfP[0] = Piece{true, 0, len(str)}
+        var val = MyEditor{str, "", arrOfP, chLog}
+        return val
+}
+
+func (m MyEditor) String() string {
+        var res string
+        for i := 0; i < len(m.pTable); i++ {
+                if m.pTable[i].origin == true {
+                        res += m.originBuffer[m.pTable[i].offset : m.pTable[i].offset+m.pTable[i].length]
+                } else {
+                        res += m.addBuffer[m.pTable[i].offset : m.pTable[i].offset+m.pTable[i].length]
+                }
+        }
+        return res
+}
+
+func (i MyEditor) Insert(position uint, text string) MyEditor {
+        addPiece := make([]Piece, 1)
+        addPiece[0] = Piece{false, len(i.addBuffer), len(text)}
+        indexSaver := len(i.addBuffer)
+        if position == 0 {
+                i.pTable = append(addPiece, i.pTable...)
+        } else if position > 0 && (int(position) < len(i.originBuffer)) { //mid insert
+                for key, val := range i.pTable {
+                        if int(position) >= val.offset && int(position) <= val.offset+val.length {
+                                newPieces := make([]Piece, 0)
+                                newPieceTable1 := Piece{origin: true, offset: val.offset, length: int(position) - val.offset}
+                                newPieceTable2 := Piece{origin: true, offset: newPieceTable1.offset + newPieceTable1.length,
+                                        length: val.length - newPieceTable1.length}
+                                newPieces = append(newPieces, newPieceTable1, addPiece[0], newPieceTable2)
+                                if len(i.pTable) == 1 {
+                                        i.pTable = newPieces
+                                } else {
+                                        temp := make([]Piece, len(i.pTable[key+1:]))
+                                        copy(temp, i.pTable[key+1:])
+                                        i.pTable = append(i.pTable[:key], newPieces...)
+                                        i.pTable = append(i.pTable, temp...)
+                                }
+                                break
+                        }
+                }
+        } else {
+                i.pTable = append(i.pTable, Piece{false, len(i.addBuffer), len(text)})
+        }
+        i.addBuffer += text
+        temp := make([]HistoryItem, len(i.changeLog.changes[i.changeLog.position:]))
+        if i.changeLog.position != 0 {
+                copy(temp, i.changeLog.changes[:i.changeLog.position])
+                i.changeLog.changes = append(i.changeLog.changes[:i.changeLog.position],
+                        HistoryItem{1, int(indexSaver), len(text)})
+                i.changeLog.changes = append(i.changeLog.changes, temp...)
+        } else {
+                copy(temp, i.changeLog.changes[i.changeLog.position:])
+                newChLog := make([]HistoryItem, len(temp)+1)
+                newChLog[0] = HistoryItem{1, int(indexSaver), len(text)}
+                newChLog = append(newChLog[:1], temp...)
+                i.changeLog.changes = newChLog
+        }
+        i.changeLog.position++
+        return i
+}
+
+func (i MyEditor) Delete(offset, length uint) MyEditor {
+        if int(offset) > len(i.originBuffer)-1 {
+                return i
+        }
+        if int(length) > len(i.originBuffer) {
+                length = uint(len(i.originBuffer) - int(offset))
+        }
+        for key, val := range i.pTable {
+                if int(offset) >= val.offset && int(offset) <= int(val.offset+val.length) {
+                        newPieces := make([]Piece, 0)
+                        newPieceTable1 := Piece{origin: true, offset: val.offset,
+                                length: int(math.Abs(float64((int(offset) - int(val.offset)))))}
+                        newPieceTable2 := Piece{origin: true, offset: int(offset + length), length: val.length + val.offset - int(offset+length)}
+                        newPieces = append(newPieces, newPieceTable1, newPieceTable2)
+                        if len(i.pTable) == 1 {
+                                i.pTable = newPieces
+                        } else {
+                                temp := make([]Piece, len(i.pTable[key+1:]))
+                                copy(temp, i.pTable[key+1:])
+                                i.pTable = append(i.pTable[:key], newPieces...)
+                                i.pTable = append(i.pTable, temp...)
+                        }
+                        break
+                }
+        }
+        temp := make([]HistoryItem, len(i.changeLog.changes[i.changeLog.position:]))
+        if i.changeLog.position != 0 {
+                copy(temp, i.changeLog.changes[:i.changeLog.position])
+                i.changeLog.changes = append(i.changeLog.changes[:i.changeLog.position],
+                        HistoryItem{0, int(offset), int(length)})
+                i.changeLog.changes = append(i.changeLog.changes, temp...)
+        } else {
+                copy(temp, i.changeLog.changes[i.changeLog.position:])
+                newChLog := make([]HistoryItem, len(temp)+1)
+                newChLog[0] = HistoryItem{0, int(offset), int(length)}
+                newChLog = append(newChLog[:1], temp...)
+                i.changeLog.changes = newChLog
+        }
+        i.changeLog.position++
+        return i
+}
+
+func (i MyEditor) Undo() MyEditor {
+        if i.changeLog.position == 0 {
+                return i
+        }
+        sOffset := i.changeLog.changes[i.changeLog.position-1].offset
+        sLength := i.changeLog.changes[i.changeLog.position-1].length
+        modType := i.changeLog.changes[i.changeLog.position-1].typeOfModif
+        if modType == 1 {
+                for j := 0; j < len(i.pTable); j++ {
+                        if i.pTable[j].origin == false {
+                                if i.pTable[j].offset == sOffset && i.pTable[j].length == sLength {
+                                        i.pTable[j].length = 0
+                                }
+                        }
+                }
+        } else {
+                for key, value := range i.pTable {
+                        if value.origin == true {
+                                if key+1 < len(i.pTable) {
+                                        if value.length+value.offset == sOffset && i.pTable[key+1].offset == sOffset+sLength {
+                                                i.pTable[key].length = i.pTable[key+1].offset - value.offset
+                                                break
+                                        }
+                                }
+                        }
+                }
+        }
+        i.changeLog.position--
+        return i
+}
+
+func (i MyEditor) Redo() MyEditor {
+        if int(i.changeLog.position) == len(i.changeLog.changes) {
+                return i
+        }
+        sOffset := i.changeLog.changes[i.changeLog.position].offset
+        sLength := i.changeLog.changes[i.changeLog.position].length
+        modType := i.changeLog.changes[i.changeLog.position].typeOfModif
+        if modType == 1 {
+                for key, value := range i.pTable {
+                        if value.origin == false {
+                                if value.offset == sOffset {
+                                        i.pTable[key].length = sLength
+                                        break
+                                }
+                        }
+                }
+        } else {
+                for key, value := range i.pTable {
+                        if value.origin == true {
+                                if key+1 < len(i.pTable) {
+                                        if value.length+value.offset == i.pTable[key+1].offset {
+                                                i.pTable[key].length = sOffset - value.offset
+                                                break
+                                        }
+                                }
+                        }
+                }
+        }
+        i.changeLog.position++
+        return i
+}
