route/vendor/github.com/zclconf/go-cty/cty/diff/diff_list.go

114 lines
2.6 KiB
Go

package diff
import "github.com/zclconf/go-cty/cty"
// diffListsShallow takes two values that must be known, non-null lists of the
// same element type and returns a shallow diff that adds and removes only
// direct list members, even if they are themselves collection- or
// structural-typed values.
func diffListsShallow(old cty.Value, new cty.Value, path cty.Path) Diff {
var diff Diff
oldEls := make([]cty.Value, 0, old.LengthInt())
newEls := make([]cty.Value, 0, old.LengthInt())
it := old.ElementIterator()
for it.Next() {
_, v := it.Element()
oldEls = append(oldEls, v)
}
it = new.ElementIterator()
for it.Next() {
_, v := it.Element()
newEls = append(newEls, v)
}
lcs := longestCommonSubsequence(oldEls, newEls)
op := 0 // position in "old"
np := 0 // position in "new"
cp := 0 // position in "lcs"
ip := int64(0) // current index for diff changes
path = append(path, nil)
step := &path[len(path)-1]
for op < len(oldEls) || np < len(newEls) {
// We want to produce blocks of removes, adds, and contexts
// until we run out of items.
// Elements unique to old are deleted
for op < len(oldEls) {
if cp < len(lcs) {
eq := oldEls[op].Equals(lcs[cp])
if eq.IsKnown() && eq.True() {
break
}
}
*step = cty.IndexStep{
Key: cty.NumberIntVal(ip),
}
diff = append(diff, DeleteChange{
Path: path.Copy(),
OldValue: oldEls[op],
})
op++
}
// Elements unique to new are inserted
for np < len(newEls) {
if cp < len(lcs) {
eq := newEls[np].Equals(lcs[cp])
if eq.IsKnown() && eq.True() {
break
}
}
*step = cty.IndexStep{
Key: cty.NumberIntVal(ip),
}
var beforeVal cty.Value
if op < len(oldEls) {
beforeVal = oldEls[op]
} else {
beforeVal = cty.NullVal(old.Type().ElementType())
}
diff = append(diff, InsertChange{
Path: path.Copy(),
NewValue: newEls[np],
BeforeValue: beforeVal,
})
np++
ip++
}
// Elements common to both are context.
// For this loop we'll advance all three pointers at once because
// we expect to be walking through the same elements in all three.
for cp < len(lcs) && op < len(oldEls) && np < len(newEls) {
oeq := oldEls[op].Equals(lcs[cp])
if !(oeq.IsKnown() && oeq.True()) {
break
}
neq := newEls[np].Equals(lcs[cp])
if !(neq.IsKnown() && neq.True()) {
break
}
*step = cty.IndexStep{
Key: cty.NumberIntVal(ip),
}
diff = append(diff, Context{
Path: path.Copy(),
WantValue: lcs[cp],
})
cp++
op++
np++
ip++
}
}
return diff
}