github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/modinstaller/byte_sequence.go (about)

     1  package modinstaller
     2  
     3  import (
     4  	"sort"
     5  )
     6  
     7  type ChangeOperation int
     8  
     9  const (
    10  	Insert ChangeOperation = iota
    11  	Delete
    12  	Replace
    13  )
    14  
    15  type Change struct {
    16  	Content     []byte
    17  	Operation   ChangeOperation
    18  	OffsetStart int
    19  	OffsetEnd   int
    20  }
    21  
    22  type ChangeSet []*Change
    23  
    24  func EmptyChangeSet() ChangeSet { return ChangeSet{} }
    25  
    26  // MergeChangeSet creates a ChangeSet by merging the given ChangeSets in order
    27  func MergeChangeSet(changeSets ...ChangeSet) ChangeSet {
    28  	changeSet := ChangeSet{}
    29  	for _, cs := range changeSets {
    30  		changeSet = append(changeSet, cs...)
    31  	}
    32  	return changeSet
    33  }
    34  
    35  // NewChangeSet creates a ChangeSet from the given changes
    36  func NewChangeSet(changes ...*Change) ChangeSet {
    37  	return ChangeSet(changes)
    38  }
    39  
    40  func (c ChangeSet) SortByOffset() {
    41  	// sort the changes into descending order of byte offset
    42  	// this way, when a change is applied, even if it's replacement
    43  	// does not have the exact same bytes, we don't lose the offset information
    44  	// of the changes preceeding it
    45  	sort.Slice(c, func(i, j int) bool {
    46  		return c[i].OffsetStart > c[j].OffsetStart
    47  	})
    48  }
    49  
    50  type OperatorFunc func(*Change, []byte) []byte
    51  
    52  type ByteSequence struct {
    53  	operators   map[ChangeOperation]OperatorFunc
    54  	_underlying []byte
    55  }
    56  
    57  func NewByteSequence(b []byte) *ByteSequence {
    58  	byteSequence := new(ByteSequence)
    59  	byteSequence._underlying = make([]byte, len(b))
    60  	copy(byteSequence._underlying, b)
    61  
    62  	byteSequence.operators = map[ChangeOperation]OperatorFunc{
    63  		Insert:  insert,
    64  		Delete:  clear,
    65  		Replace: replace,
    66  	}
    67  
    68  	return byteSequence
    69  }
    70  
    71  func (b *ByteSequence) ApplyChanges(changeSet ChangeSet) {
    72  	changeSet.SortByOffset()
    73  	for _, change := range changeSet {
    74  		operation := change.Operation
    75  		if operator, ok := b.operators[operation]; ok {
    76  			b._underlying = operator(change, b._underlying)
    77  		}
    78  	}
    79  }
    80  
    81  // Apply applies the given function on the byte sequence
    82  func (bseq *ByteSequence) Apply(apply func([]byte) []byte) {
    83  	bseq._underlying = apply(bseq._underlying)
    84  }
    85  
    86  // Bytes returns the current underlying byte sequence
    87  func (bseq *ByteSequence) Bytes() []byte {
    88  	return bseq._underlying
    89  }
    90  
    91  func clear(change *Change, source []byte) []byte {
    92  	left := source[:change.OffsetStart]
    93  	right := source[change.OffsetEnd:]
    94  	return append(left, right...)
    95  }
    96  
    97  func insert(change *Change, source []byte) []byte {
    98  	left := source[:change.OffsetStart]
    99  	right := source[change.OffsetStart:]
   100  	// prepend the content before the right part
   101  	right = append(change.Content, right...)
   102  	return append(left, right...)
   103  }
   104  
   105  func replace(change *Change, source []byte) []byte {
   106  	return insert(change, clear(change, source))
   107  }