Решение на Piece table от Георги Божинов

Обратно към всички решения

Към профила на Георги Божинов

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 7 успешни тест(а)
  • 1 неуспешни тест(а)

Код

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
}

Лог от изпълнението

PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
--- FAIL: TestOutOfBound (0.00s)
panic: runtime error: index out of range [recovered]
	panic: runtime error: index out of range

goroutine 6 [running]:
testing.tRunner.func1(0xc0000b2100)
	/usr/local/go/src/testing/testing.go:792 +0x387
panic(0x5132e0, 0x61afe0)
	/usr/local/go/src/runtime/panic.go:513 +0x1b9
_/tmp/d20181107-53-nda6rq.PieceTable.Delete(0xc000018100, 0xe, 0x10, 0x0, 0x0, 0x0, 0xc000014260, 0x1, 0x1, 0xc00000a100, ...)
	/tmp/d20181107-53-nda6rq/solution.go:125 +0xcd4
_/tmp/d20181107-53-nda6rq.TestOutOfBound(0xc0000b2100)
	/tmp/d20181107-53-nda6rq/solution_test.go:23 +0x377
testing.tRunner(0xc0000b2100, 0x540d98)
	/usr/local/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x353
exit status 2
FAIL	_/tmp/d20181107-53-nda6rq	0.004s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s
PASS
ok  	_/tmp/d20181107-53-nda6rq	0.002s

История (1 версия и 0 коментара)

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