Improve diff package efficiency
This commit is contained in:
parent
1e5c90b3d7
commit
862df0c9e3
2 changed files with 91 additions and 18 deletions
|
@ -15,21 +15,19 @@
|
|||
package diff
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
)
|
||||
|
||||
type Operation struct {
|
||||
Op string `cork:"op,omietmpty" json:"op,omietmpty" structs:"op,omitempty"`
|
||||
From string `cork:"from,omitempty" json:"from,omitempty" structs:"from,omitempty"`
|
||||
Path string `cork:"path,omitempty" json:"path,omitempty" structs:"path,omitempty"`
|
||||
Value interface{} `cork:"value,omitempty" json:"value,omitempty" structs:"value,omitempty"`
|
||||
Before interface{} `cork:"-" json:"-" structs:"-"`
|
||||
Op string `cork:"op,omietmpty" json:"op,omietmpty"`
|
||||
From string `cork:"from,omitempty" json:"from,omitempty"`
|
||||
Path string `cork:"path,omitempty" json:"path,omitempty"`
|
||||
Value interface{} `cork:"value,omitempty" json:"value,omitempty"`
|
||||
Before interface{} `cork:"-" json:"-"`
|
||||
}
|
||||
|
||||
type Operations struct {
|
||||
|
@ -57,21 +55,41 @@ func (o *Operations) Rebase(other *Operations) (ops *Operations, err error) {
|
|||
func (o *Operations) Out() (ops []map[string]interface{}) {
|
||||
|
||||
for _, v := range o.Ops {
|
||||
ops = append(ops, structs.Map(v))
|
||||
|
||||
op := make(map[string]interface{})
|
||||
|
||||
if len(v.Op) > 0 {
|
||||
op["op"] = v.Op
|
||||
}
|
||||
|
||||
if len(v.From) > 0 {
|
||||
op["from"] = v.From
|
||||
}
|
||||
|
||||
if len(v.Path) > 0 {
|
||||
op["path"] = v.Path
|
||||
}
|
||||
|
||||
if v.Value != nil {
|
||||
op["value"] = v.Value
|
||||
}
|
||||
|
||||
ops = append(ops, op)
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func route(path string, part interface{}) string {
|
||||
if path == "" {
|
||||
return fmt.Sprintf("/%v", part)
|
||||
func route(path string, part string) string {
|
||||
if len(path) == 0 {
|
||||
return "/" + part
|
||||
} else {
|
||||
if strings.HasSuffix(path, "/") {
|
||||
return path + fmt.Sprintf("%v", part)
|
||||
if path[0] == '/' {
|
||||
return path + part
|
||||
} else {
|
||||
return path + fmt.Sprintf("/%v", part)
|
||||
return path + "/" + part
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,18 +238,18 @@ func (o *Operations) arrs(old, now []interface{}, path string) {
|
|||
var i int
|
||||
|
||||
for i = 0; i < len(old) && i < len(now); i++ {
|
||||
o.vals(old[i], now[i], route(path, i))
|
||||
o.vals(old[i], now[i], strconv.Itoa(i))
|
||||
}
|
||||
|
||||
for j := i; j < len(now); j++ {
|
||||
if j >= len(old) || !reflect.DeepEqual(now[j], old[j]) {
|
||||
o.op("add", "", route(path, j), nil, now[j])
|
||||
o.op("add", "", route(path, strconv.Itoa(j)), nil, now[j])
|
||||
}
|
||||
}
|
||||
|
||||
for j := i; j < len(old); j++ {
|
||||
if j >= len(now) || !reflect.DeepEqual(old[j], now[j]) {
|
||||
o.op("remove", "", route(path, j), old[j], nil)
|
||||
o.op("remove", "", route(path, strconv.Itoa(j)), old[j], nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
55
util/diff/diff_test.go
Normal file
55
util/diff/diff_test.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright © 2016 Abcum Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package diff
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
|
||||
Convey("Main", t, func() {
|
||||
So(nil, ShouldBeNil)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkFib1(b *testing.B) {
|
||||
|
||||
old := map[string]interface{}{
|
||||
"age": 18,
|
||||
"name": map[string]interface{}{
|
||||
"first": "T",
|
||||
"last": "M H",
|
||||
},
|
||||
"chainging": true,
|
||||
}
|
||||
|
||||
now := map[string]interface{}{
|
||||
"age": 29,
|
||||
"name": map[string]interface{}{
|
||||
"first": "Tobie",
|
||||
"last": "Morgan Hitchcock",
|
||||
},
|
||||
"changing": "This is a string",
|
||||
}
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
Diff(old, now)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue