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
|
package diff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strconv"
|
||||||
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
Op string `cork:"op,omietmpty" json:"op,omietmpty" structs:"op,omitempty"`
|
Op string `cork:"op,omietmpty" json:"op,omietmpty"`
|
||||||
From string `cork:"from,omitempty" json:"from,omitempty" structs:"from,omitempty"`
|
From string `cork:"from,omitempty" json:"from,omitempty"`
|
||||||
Path string `cork:"path,omitempty" json:"path,omitempty" structs:"path,omitempty"`
|
Path string `cork:"path,omitempty" json:"path,omitempty"`
|
||||||
Value interface{} `cork:"value,omitempty" json:"value,omitempty" structs:"value,omitempty"`
|
Value interface{} `cork:"value,omitempty" json:"value,omitempty"`
|
||||||
Before interface{} `cork:"-" json:"-" structs:"-"`
|
Before interface{} `cork:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Operations struct {
|
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{}) {
|
func (o *Operations) Out() (ops []map[string]interface{}) {
|
||||||
|
|
||||||
for _, v := range o.Ops {
|
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
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func route(path string, part interface{}) string {
|
func route(path string, part string) string {
|
||||||
if path == "" {
|
if len(path) == 0 {
|
||||||
return fmt.Sprintf("/%v", part)
|
return "/" + part
|
||||||
} else {
|
} else {
|
||||||
if strings.HasSuffix(path, "/") {
|
if path[0] == '/' {
|
||||||
return path + fmt.Sprintf("%v", part)
|
return path + part
|
||||||
} else {
|
} 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
|
var i int
|
||||||
|
|
||||||
for i = 0; i < len(old) && i < len(now); i++ {
|
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++ {
|
for j := i; j < len(now); j++ {
|
||||||
if j >= len(old) || !reflect.DeepEqual(now[j], old[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++ {
|
for j := i; j < len(old); j++ {
|
||||||
if j >= len(now) || !reflect.DeepEqual(old[j], now[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