mirror of
https://github.com/turbot/steampipe.git
synced 2026-02-16 16:00:11 -05:00
108 lines
2.5 KiB
Go
108 lines
2.5 KiB
Go
package modinstaller
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
type ChangeOperation int
|
|
|
|
const (
|
|
Insert ChangeOperation = iota
|
|
Delete
|
|
Replace
|
|
)
|
|
|
|
type Change struct {
|
|
Content []byte
|
|
Operation ChangeOperation
|
|
OffsetStart int
|
|
OffsetEnd int
|
|
}
|
|
|
|
type ChangeSet []*Change
|
|
|
|
func EmptyChangeSet() ChangeSet { return ChangeSet{} }
|
|
|
|
// MergeChangeSet creates a ChangeSet by merging the given ChangeSets in order
|
|
func MergeChangeSet(changeSets ...ChangeSet) ChangeSet {
|
|
changeSet := ChangeSet{}
|
|
for _, cs := range changeSets {
|
|
changeSet = append(changeSet, cs...)
|
|
}
|
|
return changeSet
|
|
}
|
|
|
|
// NewChangeSet creates a ChangeSet from the given changes
|
|
func NewChangeSet(changes ...*Change) ChangeSet {
|
|
return ChangeSet(changes)
|
|
}
|
|
|
|
func (c ChangeSet) SortByOffset() {
|
|
// sort the changes into descending order of byte offset
|
|
// this way, when a change is applied, even if it's replacement
|
|
// does not have the exact same bytes, we don't lose the offset information
|
|
// of the changes preceeding it
|
|
sort.Slice(c, func(i, j int) bool {
|
|
return c[i].OffsetStart > c[j].OffsetStart
|
|
})
|
|
}
|
|
|
|
type OperatorFunc func(*Change, []byte) []byte
|
|
|
|
type ByteSequence struct {
|
|
operators map[ChangeOperation]OperatorFunc
|
|
_underlying []byte
|
|
}
|
|
|
|
func NewByteSequence(b []byte) *ByteSequence {
|
|
byteSequence := new(ByteSequence)
|
|
byteSequence._underlying = make([]byte, len(b))
|
|
copy(byteSequence._underlying, b)
|
|
|
|
byteSequence.operators = map[ChangeOperation]OperatorFunc{
|
|
Insert: insert,
|
|
Delete: clear,
|
|
Replace: replace,
|
|
}
|
|
|
|
return byteSequence
|
|
}
|
|
|
|
func (b *ByteSequence) ApplyChanges(changeSet ChangeSet) {
|
|
changeSet.SortByOffset()
|
|
for _, change := range changeSet {
|
|
operation := change.Operation
|
|
if operator, ok := b.operators[operation]; ok {
|
|
b._underlying = operator(change, b._underlying)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply applies the given function on the byte sequence
|
|
func (bseq *ByteSequence) Apply(apply func([]byte) []byte) {
|
|
bseq._underlying = apply(bseq._underlying)
|
|
}
|
|
|
|
// Bytes returns the current underlying byte sequence
|
|
func (bseq *ByteSequence) Bytes() []byte {
|
|
return bseq._underlying
|
|
}
|
|
|
|
func clear(change *Change, source []byte) []byte {
|
|
left := source[:change.OffsetStart]
|
|
right := source[change.OffsetEnd:]
|
|
return append(left, right...)
|
|
}
|
|
|
|
func insert(change *Change, source []byte) []byte {
|
|
left := source[:change.OffsetStart]
|
|
right := source[change.OffsetStart:]
|
|
// prepend the content before the right part
|
|
right = append(change.Content, right...)
|
|
return append(left, right...)
|
|
}
|
|
|
|
func replace(change *Change, source []byte) []byte {
|
|
return insert(change, clear(change, source))
|
|
}
|