Skip to content

Commit

Permalink
fix: factorization with LCS option
Browse files Browse the repository at this point in the history
  • Loading branch information
wI2L committed Feb 24, 2024
1 parent f20729a commit d3385d9
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 21 deletions.
11 changes: 10 additions & 1 deletion apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,25 @@ func (p Patch) apply(src []byte, valid bool) ([]byte, error) {
if err != nil {
return nil, err
}
toAddVal := op.Value

// If the operation is a move, delete the
// source value before adding it at its new
// position, to preserve array index position.
if op.Type == OperationMove {
r := gjson.GetBytes(tgt, fp)
if err != nil {
break
}
if r.Exists() {
toAddVal = r.Value()
}
tgt, err = sjson.DeleteBytes(tgt, fp)
if err != nil {
break
}
}
tgt, err = add(tgt, dp, op.Value)
tgt, err = add(tgt, dp, toAddVal)
if err != nil {
break // bail out to interpret error
}
Expand Down
34 changes: 20 additions & 14 deletions differ.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import (
// A Differ generates JSON Patch (RFC 6902).
// The zero value is an empty generator ready to use.
type Differ struct {
hashmap map[uint64]jsonNode
opts options
patch Patch
targetBytes []byte
ptr pointer
hasher hasher
isCompact bool
compactInPlace bool
hashmap map[uint64]jsonNode
opts options
patch Patch
snapshotPatchLen int
targetBytes []byte
ptr pointer
hasher hasher
isCompact bool
compactInPlace bool
}

type (
Expand Down Expand Up @@ -264,7 +265,7 @@ func (d *Differ) compareObjects(ptr pointer, src, tgt map[string]interface{}, do
}
case !inOld && inNew:
if !d.isIgnored(ptr) {
d.add(ptr.copy(), tgt[k], doc)
d.add(ptr.copy(), tgt[k], doc, false)
}
}
ptr.rewind()
Expand Down Expand Up @@ -321,7 +322,7 @@ comparisons:
for i := ml; i < tl; i++ {
ptr.appendIndex(i)
if !d.isIgnored(ptr) {
d.add(p, tgt[i], doc)
d.add(p, tgt[i], doc, false)
}
ptr.rewind()
}
Expand All @@ -331,6 +332,7 @@ comparisons:
func (d *Differ) compareArraysLCS(ptr pointer, src, tgt []interface{}, doc string) {
ptr.snapshot()
pairs := lcs(src, tgt)
d.snapshotPatchLen = len(d.patch)

var ai, bi int // src && tgt arrows
var add, remove int
Expand Down Expand Up @@ -380,7 +382,7 @@ func (d *Differ) compareArraysLCS(ptr pointer, src, tgt []interface{}, doc strin
// Opposite case of the previous condition.
ptr.appendIndex(bi)
if !d.isIgnored(ptr) {
d.add(ptr.copy(), tgt[bi], doc)
d.add(ptr.copy(), tgt[bi], doc, true)
}
ptr.rewind()
bi++
Expand Down Expand Up @@ -421,7 +423,7 @@ func (d *Differ) compareArraysLCS(ptr pointer, src, tgt []interface{}, doc strin
default: // bi < len(tgt)
ptr.appendIndex(bi)
if !d.isIgnored(ptr) {
d.add(ptr.copy(), tgt[bi], doc)
d.add(ptr.copy(), tgt[bi], doc, true)
}
ptr.rewind()
bi++
Expand Down Expand Up @@ -463,7 +465,7 @@ func (d *Differ) replace(path string, src, tgt interface{}, doc string) {
d.patch = d.patch.append(OperationReplace, emptyPointer, path, src, tgt, vl)
}

func (d *Differ) add(path string, v interface{}, doc string) {
func (d *Differ) add(path string, v interface{}, doc string, lcs bool) {
if !d.opts.factorize {
d.patch = d.patch.append(OperationAdd, emptyPointer, path, nil, v, 0)
return
Expand All @@ -478,7 +480,11 @@ func (d *Differ) add(path string, v interface{}, doc string) {
// be moved into one of its children.
if !strings.HasPrefix(path, op.Path) {
d.patch = d.patch.remove(idx)
d.patch = d.patch.append(OperationMove, op.Path, path, v, v, 0)
if !lcs {
d.patch = d.patch.append(OperationMove, op.Path, path, v, v, 0)
} else {
d.patch = d.patch.prepend(d.snapshotPatchLen, OperationMove, op.Path, path, v, v, 0)
}
}
return
}
Expand Down
2 changes: 1 addition & 1 deletion differ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func TestOptions(t *testing.T) {
{"testdata/tests/options/rationalization.json", makeopts(Rationalize())},
{"testdata/tests/options/equivalence.json", makeopts(Equivalent())},
{"testdata/tests/options/ignore.json", makeopts()},
{"testdata/tests/options/lcs.json", makeopts(LCS())},
{"testdata/tests/options/lcs.json", makeopts(LCS(), Factorize())},
{"testdata/tests/options/all.json", makeopts(Factorize(), Rationalize(), Invertible(), Equivalent())},
} {
var (
Expand Down
12 changes: 12 additions & 0 deletions operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ func (p *Patch) append(typ string, from, path string, src, tgt interface{}, vl i
})
}

func (p *Patch) prepend(startIdx int, typ string, from, path string, src, tgt interface{}, vl int) Patch {
op := Operation{
Type: typ,
From: from,
Path: path,
OldValue: src,
Value: tgt,
valueLen: vl,
}
return append((*p)[:startIdx], append([]Operation{op}, (*p)[startIdx:]...)...)
}

func (p *Patch) jsonLength() int {
if p == nil {
return 0
Expand Down
86 changes: 81 additions & 5 deletions testdata/tests/options/lcs.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
{ "op": "add", "path": "/3", "value": "f" }
]
}, {
"name": "reorder",
"name": "reorder bottom-up",
"before": [
"a",
"b",
Expand All @@ -97,10 +97,86 @@
"a"
],
"patch": [
{ "op": "remove", "path": "/0", "value": "c" },
{ "op": "remove", "path": "/0", "value": "b" },
{ "op": "add", "path": "/1", "value": "b" },
{ "op": "add", "path": "/2", "value": "a" }
{ "op": "move", "from": "/0", "path": "/2" },
{ "op": "move", "from": "/0", "path": "/1" }
]
}, {
"name": "reorder top-down",
"before": [
"c",
"b",
"a"
],
"after": [
"a",
"b",
"c"
],
"patch": [
{ "op": "move", "from": "/0", "path": "/2" },
{ "op": "move", "from": "/0", "path": "/1" }
]
}, {
"name": "reorder middle",
"before": [
"a",
"b",
"c",
"d",
"e",
"f"
],
"after": [
"a",
"e",
"d",
"c",
"b",
"f"
],
"patch": [
{ "op": "move", "from": "/1", "path": "/4" },
{ "op": "move", "from": "/1", "path": "/3" },
{ "op": "move", "from": "/1", "path": "/2" }
]
}, {
"name": "reorder shuffle",
"before": [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k"
],
"after": [
"f",
"i",
"b",
"d",
"a",
"k",
"c",
"h",
"g",
"e",
"j"
],
"patch": [
{ "op": "replace", "path": "/0", "value": "f" },
{ "op": "add", "path": "/1", "value": "i" },
{ "op": "remove", "path": "/3" },
{ "op": "replace", "path": "/4", "value": "a" },
{ "op": "replace", "path": "/5", "value": "k" },
{ "op": "replace", "path": "/6", "value": "c" },
{ "op": "replace", "path": "/8", "value": "g" },
{ "op": "add", "path": "/9", "value": "e" },
{ "op": "remove", "path": "/11" }
]
}, {
"name": "replace head",
Expand Down

0 comments on commit d3385d9

Please sign in to comment.