Решение на Piece table от Ivan Borshukov

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

Към профила на Ivan Borshukov

Резултати

  • 10 точки от тестове
  • 0 бонус точки
  • 10 точки общо
  • 8 успешни тест(а)
  • 0 неуспешни тест(а)

Код

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 PieceTable struct {
parent *PieceTable
child *PieceTable
pieces []Piece
origin []byte
add []byte
}
func NewEditor(text string) Editor {
return &PieceTable{
origin: []byte(text),
pieces: []Piece{{
origin: true,
offset: 0,
length: uint(len(text)),
}},
}
}
func (pt *PieceTable) Insert(position uint, text string) Editor {
var (
offset = uint(len(pt.add))
l, r = pt.split(position)
)
pt.add = append(pt.add, text...)
pieces := make([]Piece, len(l.pieces)+len(r.pieces)+1)
pieces = append(pieces, l.pieces...)
pieces = append(pieces, Piece{false, offset, uint(len(text))})
pieces = append(pieces, r.pieces...)
return pt.slice(pieces)
}
func (pt *PieceTable) Delete(offset, length uint) Editor {
l, _ := pt.split(offset)
_, r := pt.split(offset + length)
pieces := make([]Piece, len(l.pieces)+len(r.pieces))
copy(pieces, l.pieces)
copy(pieces[len(l.pieces):], r.pieces)
return pt.slice(pieces)
}
func (pt *PieceTable) Undo() Editor {
if pt.parent == nil {
return pt
}
return pt.parent
}
func (pt *PieceTable) Redo() Editor {
if pt.child == nil {
return pt
}
return pt.child
}
func (pt PieceTable) String() string {
var (
s strings.Builder
buf []byte
)
for _, p := range pt.pieces {
if p.origin {
buf = pt.origin
} else {
buf = pt.add
}
s.Write(buf[p.offset : p.offset+p.length])
}
return s.String()
}
func (pt *PieceTable) split(offset uint) (*PieceTable, *PieceTable) {
var pos uint
for i, p := range pt.pieces {
if pos == offset {
return pt.slice(pt.pieces[:i]), pt.slice(pt.pieces[i:])
}
pos += p.length
if pos > offset {
l, r := p.split(offset - (pos - p.length))
before := make([]Piece, len(pt.pieces[:i])+1)
copy(before, pt.pieces[:i])
before[len(before)-1] = l
after := make([]Piece, 0, len(pt.pieces[i:]))
after = append(after, r)
if len(pt.pieces[i:]) > 1 {
after = append(after, pt.pieces[i+1:]...)
}
return pt.slice(before), pt.slice(after)
}
}
// Somewhere after the EOF.
return pt.slice(pt.pieces), &PieceTable{}
}
func (pt *PieceTable) slice(pieces []Piece) *PieceTable {
var child = &PieceTable{parent: pt, pieces: pieces, origin: pt.origin, add: pt.add}
pt.child = child
return child
}
// Piece is a record in a piece table.
type Piece struct {
// origin is true if points to the original (read-only) buffer.
origin bool
// offset from the start of the used buffer.
offset uint
// length of given piece
length uint
}
func (p Piece) split(pos uint) (Piece, Piece) {
return Piece{origin: p.origin, offset: p.offset, length: pos},
Piece{origin: p.origin, offset: p.offset + pos, length: p.length - pos}
}

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

PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.003s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s
PASS
ok  	_/tmp/d20181107-53-1d4avgu	0.002s

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

Ivan обнови решението на 31.10.2018 21:56 (преди 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 PieceTable struct {
+ parent *PieceTable
+ child *PieceTable
+ pieces []Piece
+ origin []byte
+ add []byte
+}
+
+func NewEditor(text string) Editor {
+ return &PieceTable{
+ origin: []byte(text),
+ pieces: []Piece{{
+ origin: true,
+ offset: 0,
+ length: uint(len(text)),
+ }},
+ }
+}
+
+func (pt *PieceTable) Insert(position uint, text string) Editor {
+ var (
+ offset = uint(len(pt.add))
+ l, r = pt.split(position)
+ )
+
+ pt.add = append(pt.add, text...)
+ pieces := make([]Piece, len(l.pieces)+len(r.pieces)+1)
+ pieces = append(pieces, l.pieces...)
+ pieces = append(pieces, Piece{false, offset, uint(len(text))})
+ pieces = append(pieces, r.pieces...)
+ return pt.slice(pieces)
+}
+
+func (pt *PieceTable) Delete(offset, length uint) Editor {
+ l, _ := pt.split(offset)
+ _, r := pt.split(offset + length)
+
+ pieces := make([]Piece, len(l.pieces)+len(r.pieces))
+ copy(pieces, l.pieces)
+ copy(pieces[len(l.pieces):], r.pieces)
+
+ return pt.slice(pieces)
+}
+func (pt *PieceTable) Undo() Editor {
+ if pt.parent == nil {
+ return pt
+ }
+
+ return pt.parent
+}
+
+func (pt *PieceTable) Redo() Editor {
+ if pt.child == nil {
+ return pt
+ }
+ return pt.child
+}
+
+func (pt PieceTable) String() string {
+ var (
+ s strings.Builder
+ buf []byte
+ )
+
+ for _, p := range pt.pieces {
+ if p.origin {
+ buf = pt.origin
+ } else {
+ buf = pt.add
+ }
+
+ s.Write(buf[p.offset : p.offset+p.length])
+ }
+ return s.String()
+}
+
+func (pt *PieceTable) split(offset uint) (*PieceTable, *PieceTable) {
+ var pos uint
+
+ for i, p := range pt.pieces {
+ if pos == offset {
+ return pt.slice(pt.pieces[:i]), pt.slice(pt.pieces[i:])
+ }
+
+ pos += p.length
+
+ if pos > offset {
+ l, r := p.split(offset - (pos - p.length))
+
+ before := make([]Piece, len(pt.pieces[:i])+1)
+ copy(before, pt.pieces[:i])
+ before[len(before)-1] = l
+
+ after := make([]Piece, 0, len(pt.pieces[i:]))
+ after = append(after, r)
+ if len(pt.pieces[i:]) > 1 {
+ after = append(after, pt.pieces[i+1:]...)
+ }
+
+ return pt.slice(before), pt.slice(after)
+
+ }
+ }
+
+ // Somewhere after the EOF.
+ return pt.slice(pt.pieces), &PieceTable{}
+}
+
+func (pt *PieceTable) slice(pieces []Piece) *PieceTable {
+ var child = &PieceTable{parent: pt, pieces: pieces, origin: pt.origin, add: pt.add}
+ pt.child = child
+ return child
+}
+
+// Piece is a record in a piece table.
+type Piece struct {
+ // origin is true if points to the original (read-only) buffer.
+ origin bool
+
+ // offset from the start of the used buffer.
+ offset uint
+
+ // length of given piece
+ length uint
+}
+
+func (p Piece) split(pos uint) (Piece, Piece) {
+ return Piece{origin: p.origin, offset: p.offset, length: pos},
+ Piece{origin: p.origin, offset: p.offset + pos, length: p.length - pos}
+}