Skip to content

Commit

Permalink
feat: nested array equivalence
Browse files Browse the repository at this point in the history
Closes #29

                                           │     old     │                 new                  │
                                           │   sec/op    │    sec/op     vs base                │
Small/DifferReset/default-10                 1.239µ ± 1%    1.239µ ± 1%        ~ (p=0.361 n=10)
Small/Differ/default-10                      1.455µ ± 1%    1.462µ ± 0%        ~ (p=0.126 n=10)
Small/DifferReset/default-unordered-10       1.299µ ± 1%    1.303µ ± 1%        ~ (p=0.136 n=10)
Small/Differ/default-unordered-10            1.642µ ± 0%    1.642µ ± 1%        ~ (p=0.752 n=10)
Small/DifferReset/invertible-10              1.252µ ± 1%    1.250µ ± 1%        ~ (p=0.193 n=10)
Small/Differ/invertible-10                   1.593µ ± 0%    1.595µ ± 1%        ~ (p=0.590 n=10)
Small/DifferReset/factorize-10               2.041µ ± 1%    2.034µ ± 1%   -0.34% (p=0.009 n=10)
Small/Differ/factorize-10                    2.364µ ± 0%    2.357µ ± 1%        ~ (p=0.322 n=10)
Small/DifferReset/rationalize-10             1.318µ ± 1%    1.317µ ± 0%        ~ (p=0.485 n=10)
Small/Differ/rationalize-10                  1.540µ ± 1%    1.543µ ± 0%        ~ (p=0.284 n=10)
Small/DifferReset/equivalent-10              1.236µ ± 1%    1.236µ ± 1%        ~ (p=0.381 n=10)
Small/Differ/equivalent-10                   1.460µ ± 0%    1.460µ ± 1%        ~ (p=0.424 n=10)
Small/DifferReset/equivalent-unordered-10    1.334µ ± 1%    1.336µ ± 1%        ~ (p=0.752 n=10)
Small/Differ/equivalent-unordered-10         1.565µ ± 0%    1.565µ ± 1%        ~ (p=0.468 n=10)
Small/DifferReset/factor+ratio-10            2.115µ ± 1%    2.109µ ± 1%        ~ (p=0.302 n=10)
Small/Differ/factor+ratio-10                 2.439µ ± 0%    2.442µ ± 0%        ~ (p=0.564 n=10)
Small/DifferReset/all-10                     2.184µ ± 1%    2.188µ ± 1%        ~ (p=0.303 n=10)
Small/Differ/all-10                          2.644µ ± 0%    2.650µ ± 0%        ~ (p=0.196 n=10)
Small/DifferReset/all-unordered-10           2.286µ ± 1%    2.296µ ± 2%   +0.44% (p=0.014 n=10)
Small/Differ/all-unordered-10                2.742µ ± 0%    2.751µ ± 0%   +0.33% (p=0.004 n=10)
Medium/DifferReset/default-10                3.587µ ± 1%    3.597µ ± 1%        ~ (p=0.110 n=10)
Medium/Differ/default-10                     4.163µ ± 1%    4.178µ ± 1%        ~ (p=0.224 n=10)
Medium/DifferReset/default-unordered-10      3.876µ ± 1%    3.891µ ± 1%        ~ (p=0.101 n=10)
Medium/Differ/default-unordered-10           4.750µ ± 1%    4.753µ ± 0%        ~ (p=0.781 n=10)
Medium/DifferReset/invertible-10             3.638µ ± 1%    3.644µ ± 1%        ~ (p=0.256 n=10)
Medium/Differ/invertible-10                  4.535µ ± 1%    4.562µ ± 1%        ~ (p=0.093 n=10)
Medium/DifferReset/factorize-10              6.351µ ± 2%    6.361µ ± 1%        ~ (p=0.256 n=10)
Medium/Differ/factorize-10                   7.255µ ± 0%    7.266µ ± 1%        ~ (p=0.324 n=10)
Medium/DifferReset/rationalize-10            3.894µ ± 1%    3.903µ ± 1%        ~ (p=0.240 n=10)
Medium/Differ/rationalize-10                 4.261µ ± 1%    4.270µ ± 1%        ~ (p=0.493 n=10)
Medium/DifferReset/equivalent-10             5.689µ ± 2%    6.748µ ± 4%  +18.63% (p=0.000 n=10)
Medium/Differ/equivalent-10                  6.279µ ± 1%    8.547µ ± 0%  +36.11% (p=0.000 n=10)
Medium/DifferReset/equivalent-unordered-10   6.182µ ± 1%    6.630µ ± 2%   +7.24% (p=0.000 n=10)
Medium/Differ/equivalent-unordered-10        6.794µ ± 1%    8.554µ ± 1%  +25.91% (p=0.000 n=10)
Medium/DifferReset/factor+ratio-10           6.583µ ± 2%    6.598µ ± 1%        ~ (p=0.165 n=10)
Medium/Differ/factor+ratio-10                7.269µ ± 1%    7.300µ ± 1%        ~ (p=0.255 n=10)
Medium/DifferReset/all-10                    8.977µ ± 1%    9.829µ ± 3%   +9.50% (p=0.000 n=10)
Medium/Differ/all-10                         9.888µ ± 1%   12.267µ ± 0%  +24.07% (p=0.000 n=10)
Medium/DifferReset/all-unordered-10          9.772µ ± 1%    9.818µ ± 1%        ~ (p=0.382 n=10)
Medium/Differ/all-unordered-10               10.70µ ± 1%    12.28µ ± 1%  +14.71% (p=0.000 n=10)
geomean                                      3.178µ         3.281µ        +3.24%

                                           │     old      │                  new                  │
                                           │     B/op     │     B/op      vs base                 │
Small/DifferReset/default-10                   216.0 ± 0%     216.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/default-10                      1.164Ki ± 0%   1.164Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/default-unordered-10         312.0 ± 0%     312.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/default-unordered-10            2.008Ki ± 0%   2.008Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/invertible-10                216.0 ± 0%     216.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/invertible-10                   1.914Ki ± 0%   1.914Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/factorize-10                 400.0 ± 0%     400.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/factorize-10                    1.734Ki ± 0%   1.734Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/rationalize-10               224.0 ± 0%     224.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/rationalize-10                  1.172Ki ± 0%   1.172Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/equivalent-10                216.0 ± 0%     216.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/equivalent-10                   1.164Ki ± 0%   1.164Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/equivalent-unordered-10      216.0 ± 0%     216.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/equivalent-unordered-10         1.164Ki ± 0%   1.164Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/factor+ratio-10              408.0 ± 0%     408.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/factor+ratio-10                 1.742Ki ± 0%   1.742Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/all-10                       408.0 ± 0%     408.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/all-10                          2.492Ki ± 0%   2.492Ki ± 0%       ~ (p=1.000 n=10) ¹
Small/DifferReset/all-unordered-10             520.0 ± 0%     520.0 ± 0%       ~ (p=1.000 n=10) ¹
Small/Differ/all-unordered-10                2.602Ki ± 0%   2.602Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/default-10                  624.0 ± 0%     624.0 ± 0%       ~ (p=1.000 n=10) ¹
Medium/Differ/default-10                     3.812Ki ± 0%   3.812Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/default-unordered-10        848.0 ± 0%     848.0 ± 0%       ~ (p=1.000 n=10) ¹
Medium/Differ/default-unordered-10           7.031Ki ± 0%   7.031Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/invertible-10               624.0 ± 0%     624.0 ± 0%       ~ (p=1.000 n=10) ¹
Medium/Differ/invertible-10                  6.812Ki ± 0%   6.812Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/factorize-10              1.373Ki ± 0%   1.372Ki ± 0%       ~ (p=0.370 n=10)
Medium/Differ/factorize-10                   5.654Ki ± 0%   5.654Ki ± 0%       ~ (p=1.000 n=10)
Medium/DifferReset/rationalize-10              672.0 ± 0%     672.0 ± 0%       ~ (p=1.000 n=10) ¹
Medium/Differ/rationalize-10                 2.359Ki ± 0%   2.359Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/equivalent-10             1.359Ki ± 0%   1.359Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/Differ/equivalent-10                  4.562Ki ± 0%   4.562Ki ± 0%       ~ (p=1.000 n=10) ¹
Medium/DifferReset/equivalent-unordered-10   1.453Ki ± 0%   1.359Ki ± 0%  -6.45% (p=0.000 n=10)
Medium/Differ/equivalent-unordered-10        4.656Ki ± 0%   4.562Ki ± 0%  -2.01% (p=0.000 n=10)
Medium/DifferReset/factor+ratio-10           1.420Ki ± 0%   1.419Ki ± 0%       ~ (p=1.000 n=10)
Medium/Differ/factor+ratio-10                4.200Ki ± 0%   4.200Ki ± 0%       ~ (p=0.628 n=10)
Medium/DifferReset/all-10                    2.170Ki ± 0%   2.170Ki ± 0%       ~ (p=0.861 n=10)
Medium/Differ/all-10                         6.451Ki ± 0%   6.451Ki ± 0%       ~ (p=0.650 n=10)
Medium/DifferReset/all-unordered-10          2.308Ki ± 0%   2.169Ki ± 0%  -6.01% (p=0.000 n=10)
Medium/Differ/all-unordered-10               6.589Ki ± 0%   6.450Ki ± 0%  -2.10% (p=0.000 n=10)
geomean                                      1.282Ki        1.277Ki       -0.43%
¹ all samples are equal

                                           │    old     │                 new                  │
                                           │ allocs/op  │ allocs/op   vs base                  │
Small/DifferReset/default-10                 9.000 ± 0%   9.000 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/default-10                      13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/default-unordered-10       13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/default-unordered-10            18.00 ± 0%   18.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/invertible-10              9.000 ± 0%   9.000 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/invertible-10                   14.00 ± 0%   14.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/factorize-10               21.00 ± 0%   21.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/factorize-10                    27.00 ± 0%   27.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/rationalize-10             10.00 ± 0%   10.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/rationalize-10                  14.00 ± 0%   14.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/equivalent-10              9.000 ± 0%   9.000 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/equivalent-10                   13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/equivalent-unordered-10    9.000 ± 0%   9.000 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/equivalent-unordered-10         13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/factor+ratio-10            22.00 ± 0%   22.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/factor+ratio-10                 28.00 ± 0%   28.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/all-10                     22.00 ± 0%   22.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/all-10                          29.00 ± 0%   29.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/DifferReset/all-unordered-10           25.00 ± 0%   25.00 ± 0%        ~ (p=1.000 n=10) ¹
Small/Differ/all-unordered-10                32.00 ± 0%   32.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/default-10                18.00 ± 0%   18.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/default-10                     24.00 ± 0%   24.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/default-unordered-10      26.00 ± 0%   26.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/default-unordered-10           33.00 ± 0%   33.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/invertible-10             18.00 ± 0%   18.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/invertible-10                  25.00 ± 0%   25.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/factorize-10              55.00 ± 0%   55.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/factorize-10                   64.00 ± 0%   64.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/rationalize-10            22.00 ± 0%   22.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/rationalize-10                 27.00 ± 0%   27.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/equivalent-10             26.00 ± 0%   26.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/equivalent-10                  32.00 ± 0%   32.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/equivalent-unordered-10   30.00 ± 0%   26.00 ± 0%  -13.33% (p=0.000 n=10)
Medium/Differ/equivalent-unordered-10        36.00 ± 0%   32.00 ± 0%  -11.11% (p=0.000 n=10)
Medium/DifferReset/factor+ratio-10           59.00 ± 0%   59.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/factor+ratio-10                67.00 ± 0%   67.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/all-10                    67.00 ± 0%   67.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/Differ/all-10                         76.00 ± 0%   76.00 ± 0%        ~ (p=1.000 n=10) ¹
Medium/DifferReset/all-unordered-10          74.00 ± 0%   67.00 ± 0%   -9.46% (p=0.000 n=10)
Medium/Differ/all-unordered-10               83.00 ± 0%   76.00 ± 0%   -8.43% (p=0.000 n=10)
geomean                                      24.63        24.36        -1.11%
¹ all samples are equal
  • Loading branch information
wI2L committed Nov 11, 2024
1 parent dfdd539 commit 19a2a0a
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
run:
go: "1.22"
go: "1.23"
timeout: 10m
linters:
disable-all: true
Expand Down Expand Up @@ -33,4 +33,4 @@ issues:
exclude-rules:
- path: (.+)_test.go
linters:
- funlen
- funlen
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-2023 William Poussier <william.poussier@gmail.com>
Copyright (c) 2020-2024 William Poussier <william.poussier@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions ci/bench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ set -e

rm -f .benchruns

echo "Starting benchmark..."
echo "Starting benchmarks..."

# Execute benchmarks multiple times.
# Execute benchmark multiple times.
for i in {1..10}
do
echo " + run #$i"
Expand Down
14 changes: 7 additions & 7 deletions differ.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (d *Differ) prepare(ptr pointer, src, tgt interface{}) {
if !areComparable(src, tgt) {
return
} else if deepEqual(src, tgt) {
k := d.hasher.digest(tgt)
k := d.hasher.digest(tgt, false)
if d.hashmap == nil {
d.hashmap = make(map[uint64]jsonNode)
}
Expand Down Expand Up @@ -259,11 +259,11 @@ func (d *Differ) compareObjects(ptr pointer, src, tgt map[string]interface{}, do
} else {
d.diff(ptr, src[k], tgt[k], doc)
}
case inOld && !inNew:
case inOld:
if !d.isIgnored(ptr) {
d.remove(ptr.copy(), src[k])
}
case !inOld && inNew:
case inNew:
if !d.isIgnored(ptr) {
d.add(ptr.copy(), tgt[k], doc, false)
}
Expand Down Expand Up @@ -440,13 +440,13 @@ func (d *Differ) unorderedDeepEqualSlice(src, tgt []interface{}) bool {
count := 0

for _, v := range src {
k := d.hasher.digest(v)
k := d.hasher.digest(v, d.opts.equivalent)
diff[k] = struct{}{}
count++
}
for _, v := range tgt {
k := d.hasher.digest(v)
// If the digest hash is not in the compare,
k := d.hasher.digest(v, d.opts.equivalent)
// If the digest hash is not in the comparison set,
// return early.
if _, ok := diff[k]; !ok {
return false
Expand Down Expand Up @@ -506,7 +506,7 @@ func (d *Differ) remove(path string, v interface{}) {

func (d *Differ) findUnchanged(v interface{}) string {
if d.hashmap != nil {
k := d.hasher.digest(v)
k := d.hasher.digest(v, false)
node, ok := d.hashmap[k]
if ok {
return node.ptr
Expand Down
46 changes: 36 additions & 10 deletions differ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,21 +295,50 @@ func Test_issue17(t *testing.T) {
t.Logf("%s", string(b))
}

func Test_issue29(t *testing.T) {
src := []byte(`{"a":{"b":[{"c":[4,5]},2,1]}}`)
tgt := []byte(`{"a":{"b":[{"c":[5,4]},1,2]}}`)

patch, err := CompareJSON(src, tgt, Equivalent())
if err != nil {
t.Error(err)
}
if len(patch) != 0 {
t.Errorf("expected 0 operations, got %d", len(patch))
}
t.Log(patch)
}

func Test_issue29_alt(t *testing.T) {
src := []byte(`{"a":{"b":[[7,6],2,[42,84]]}}`)
tgt := []byte(`{"a":{"b":[[6,7],1,[84,42]]}}`)

patch, err := CompareJSON(src, tgt, Equivalent())
if err != nil {
t.Error(err)
}
if len(patch) != 1 {
t.Errorf("expected 1 operations, got %d", len(patch))
t.Log(patch)
}
if op := patch[0]; op.Path != "/a/b/1" && op.Type != OperationReplace {
t.Errorf("expected replace operation at path /a/b/1, got %s at %s", op.Type, op.Path)
}
}

func Benchmark_sortStrings(b *testing.B) {
if testing.Short() {
b.Skip()
}
for _, v := range [][]string{
// 5
{
{ // 5
"medieval",
"bike",
"trust",
"sodium",
"hemisphere",
},
// 10
{
{ // 10
"general",
"lamp",
"journal",
Expand All @@ -321,8 +350,7 @@ func Benchmark_sortStrings(b *testing.B) {
"shoulder",
"certain",
},
// 15
{
{ // 15
"plant",
"instinct",
"infect",
Expand All @@ -339,8 +367,7 @@ func Benchmark_sortStrings(b *testing.B) {
"master",
"want",
},
// 20
{
{ // 20
"absorption",
"ditch",
"gradual",
Expand All @@ -362,8 +389,7 @@ func Benchmark_sortStrings(b *testing.B) {
"plug",
"notice",
},
// 25
{
{ // 25
"flesh",
"kidney",
"hard",
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/wI2L/jsondiff
go 1.21

require (
github.com/tidwall/gjson v1.17.1
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
Expand Down
35 changes: 30 additions & 5 deletions hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ import (
"encoding/binary"
"hash/maphash"
"math"
"slices"
)

type hasher struct {
mh maphash.Hash
}

func (h *hasher) digest(val interface{}) uint64 {
func (h *hasher) digest(val interface{}, sort bool) uint64 {
h.mh.Reset()
h.hash(val)
h.hash(val, sort)

return h.mh.Sum64()
}

func (h *hasher) hash(i interface{}) {
func (h *hasher) hash(i interface{}, sort bool) {
switch v := i.(type) {
case string:
_, _ = h.mh.WriteString(v)
Expand All @@ -34,8 +35,11 @@ func (h *hasher) hash(i interface{}) {
case nil:
_ = h.mh.WriteByte('0')
case []interface{}:
if sort {
h.sortArray(v)
}
for _, e := range v {
h.hash(e)
h.hash(e, sort)
}
case map[string]interface{}:
keys := make([]string, 0, len(v))
Expand All @@ -49,7 +53,28 @@ func (h *hasher) hash(i interface{}) {

for _, k := range keys {
_, _ = h.mh.WriteString(k)
h.hash(v[k])
h.hash(v[k], sort)
}
}
}

func (h *hasher) sortArray(a []interface{}) {
h1 := hasher{}
h2 := hasher{}

h1.mh.SetSeed(h.mh.Seed())
h2.mh.SetSeed(h.mh.Seed())

slices.SortStableFunc(a, func(a1, a2 interface{}) int {
d1 := h1.digest(a1, true)
d2 := h2.digest(a2, true)

if d1 > d2 {
return 1
} else if d1 < d2 {
return -1
} else {
return 0
}
})
}
6 changes: 3 additions & 3 deletions hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func Test_digestValue(t *testing.T) {
}
h := hasher{}

n1 := h.digest(data)
n2 := h.digest(data)
n1 := h.digest(data, false)
n2 := h.digest(data, false)

if n1 != n2 {
t.Errorf("expected hash sums to be equal: %d != %d", n1, n2)
Expand All @@ -45,7 +45,7 @@ func BenchmarkHashing(b *testing.B) {
b.Run("hasher-digestValue", func(b *testing.B) {
h := hasher{}
for i := 0; i < b.N; i++ {
_ = h.digest(data)
_ = h.digest(data, false)
}
})
b.Run("json.Marshal+hash", func(b *testing.B) {
Expand Down

0 comments on commit 19a2a0a

Please sign in to comment.