Пламен обнови решението на 07.11.2018 16:30 (преди 9 месеца)
+package main
+
+import (
+ "strings"
+)
+
+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 chunk struct {
piece
щеше да е по добро име, както каза Миро...
+ buffer []byte
+ offset int
+ length int
+}
+
+type editor struct {
+ previous Editor
+ next Editor
+ origin []byte
+ add []byte
+ chunks []chunk
+}
+
+func (e editor) Insert(position uint, text string) Editor {
+ textBytes := []byte(text)
+ addOffset := len(e.add)
+ e.add = append(e.add, textBytes...)
+
+ newChunk := chunk{
+ buffer: e.add,
+ offset: addOffset,
+ length: len(textBytes),
+ }
+
+ var nextChunks []chunk
+ currentLength := 0
+ intPosition := int(position)
+
+ newChunkInserted := false
+ for _, currentChunk := range e.chunks {
+ if intPosition > currentLength &&
+ intPosition < currentLength+currentChunk.length {
+ // Split currentChunk in two and tuck the newChunk between:
+
+ splitPoint := intPosition - currentLength
+
+ nextChunks = append(nextChunks,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: currentChunk.offset,
+ length: splitPoint,
+ },
+ newChunk,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: currentChunk.offset + splitPoint,
+ length: currentChunk.length - splitPoint,
+ })
+ currentLength += currentChunk.length + newChunk.length
+ newChunkInserted = true
+ } else if intPosition == currentLength {
+ // take both currentChunk and newChunk, newChunk first:
+ nextChunks = append(nextChunks, newChunk, currentChunk)
+ currentLength += currentChunk.length + newChunk.length
+ newChunkInserted = true
+ } else if intPosition+newChunk.length == currentLength+currentChunk.length {
Dead code...
+ // take both currentChunk and newChunk, currentChunk first:
+ nextChunks = append(nextChunks, currentChunk, newChunk)
+ currentLength += currentChunk.length + newChunk.length
+ } else {
+ // Take as-is:
+ nextChunks = append(nextChunks, currentChunk)
+ currentLength += currentChunk.length
+ }
+ }
+
+ if !newChunkInserted {
+ nextChunks = append(nextChunks, newChunk)
+ }
+
+ newEditor := editor{
+ origin: e.origin,
+ add: e.add,
+ chunks: nextChunks,
+ }
+ previousEditor := editor{
+ origin: e.origin,
+ add: e.add,
+ chunks: e.chunks,
+ previous: e.previous,
+ next: newEditor,
+ }
+ newEditor.previous = previousEditor
+
+ return newEditor
+}
+
+func (e editor) Delete(offset, length uint) Editor {
+ intOffset := int(offset)
+ intLength := int(length)
+
+ var nextChunks []chunk
+ currentLength := 0
+ for _, currentChunk := range e.chunks {
+ if currentLength+currentChunk.length < intOffset ||
+ currentLength > intOffset+intLength {
+ // Take "as-is":
+ nextChunks = append(nextChunks, currentChunk)
+ } else if currentLength < intOffset &&
+ currentLength+currentChunk.length < intOffset+intLength {
+ // take the first part:
+
+ splitPoint := intOffset - currentLength
+
+ nextChunks = append(nextChunks,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: currentChunk.offset,
+ length: splitPoint,
+ })
+ } else if currentLength > intOffset &&
+ currentLength+currentChunk.length > intOffset+intLength {
+ // take the second part:
+
+ splitPoint := intOffset + intLength - currentLength
+
+ nextChunks = append(nextChunks,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: currentChunk.offset + splitPoint,
+ length: currentChunk.length - splitPoint,
+ })
+ } else if currentLength <= intOffset &&
+ currentLength+currentChunk.length >= intOffset+intLength {
+ if currentLength < intOffset {
+ nextChunks = append(nextChunks,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: currentChunk.offset,
+ length: intOffset - currentChunk.offset,
+ })
+ }
+ nextChunks = append(nextChunks,
+ chunk{
+ buffer: currentChunk.buffer,
+ offset: intOffset + intLength,
+ length: currentLength + currentChunk.length - (intOffset + intLength),
+ })
+ } // else skip the chunk entirely
+ currentLength += currentChunk.length
+ }
+
+ newEditor := editor{
+ origin: e.origin,
+ add: e.add,
+ chunks: nextChunks,
+ }
+ previousEditor := editor{
+ origin: e.origin,
+ add: e.add,
+ chunks: e.chunks,
+ previous: e.previous,
+ next: newEditor,
+ }
+ newEditor.previous = previousEditor
+
+ return newEditor
+}
+
+func (e editor) Undo() Editor {
+ if e.previous != nil {
+ return e.previous
+ }
+
+ return e
+}
+
+func (e editor) Redo() Editor {
+ if e.next != nil {
+ return e.next
+ }
+
+ return e
+}
+
+func (e editor) String() string {
+ var builder strings.Builder
+
+ for _, chunk := range e.chunks {
+ builder.Write(chunk.buffer[chunk.offset : chunk.offset+chunk.length])
+ }
+
+ return builder.String()
+}
+
+// NewEditor returns a new editor
+func NewEditor(origin string) Editor {
+ originBytes := []byte(origin)
+
+ return editor{
+ origin: originBytes,
+ chunks: []chunk{
+ chunk{
+ buffer: originBytes,
+ offset: 0,
+ length: len(originBytes),
+ },
+ },
+ }
+}
Nothing to see here, move along. Нямах време и писах в последните възможни моменти.
piece
щеше да е по добро име, както каза Миро...Dead code...