11package diff
22
33import (
4- // TODO: integrate with https://github.com/src-d/lapjv if perf is unacceptable
54 "fmt"
65 "github.com/heetch/lapjv"
76 "gopkg.in/bblfsh/sdk.v2/uast/nodes"
87)
98
109type decisionType interface {
1110 isDecisionType ()
11+ cost () int
1212}
1313
14- type basicDecisionType struct {}
14+ type basicDecision struct {
15+ privateCost int
16+ }
1517
16- func (_ basicDecisionType ) isDecisionType () {}
18+ func (basicDecision ) isDecisionType () {}
1719
18- type decision struct {
19- cost int
20- decision decisionType
21- }
20+ func (b basicDecision ) cost () int { return b .privateCost }
2221
2322// match decision types together with their params
24- type sameDecision struct { basicDecisionType }
25- type replaceDecision struct { basicDecisionType }
26- type matchDecision struct { basicDecisionType }
23+ type sameDecision struct { basicDecision }
24+ type replaceDecision struct { basicDecision }
25+ type matchDecision struct { basicDecision }
2726type permuteDecision struct {
28- basicDecisionType
27+ basicDecision
2928 permutation []int
3029}
3130
3231//convinience method for choosing the cheapest decision
33- func (self * decision ) minEq (candidate * decision ) {
34- if _ , ok := candidate .decision .(replaceDecision ); ok || self .cost > candidate .cost {
35- self .cost , self .decision = candidate .cost , candidate .decision
32+ func min (self , candidate decisionType ) decisionType {
33+ if self .cost () > candidate .cost () {
34+ return candidate
35+ } else {
36+ return self
3637 }
3738}
3839
@@ -41,16 +42,16 @@ type keyType struct{ k1, k2 ID }
4142
4243//cache for diff computation
4344type cacheStorage struct {
44- decisions map [keyType ]decision
45+ decisions map [keyType ]decisionType
4546 sizes map [ID ]int
4647 changes Changelist
4748}
4849
4950func emptyCacheStorage () cacheStorage {
5051 return cacheStorage {
51- make (map [keyType ]decision ),
52+ make (map [keyType ]decisionType ),
5253 make (map [ID ]int ),
53- make ([] Change , 0 ) ,
54+ nil ,
5455 }
5556}
5657
@@ -66,7 +67,7 @@ func (ds *cacheStorage) nodeSize(n nodes.Node) int {
6667}
6768
6869// find the cheapest way to naively match src and dst and return the action with its combined cost
69- func (ds * cacheStorage ) decideAction (src , dst nodes.Node ) decision {
70+ func (ds * cacheStorage ) decideAction (src , dst nodes.Node ) decisionType {
7071 label := keyType {nodes .UniqueKey (src ), nodes .UniqueKey (dst )}
7172
7273 if val , ok := ds .decisions [label ]; ok {
@@ -75,7 +76,9 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
7576
7677 // one can always just create the dst ignoring the src
7778 cost := ds .nodeSize (dst ) + 1
78- bestDecision := decision {cost , replaceDecision {}}
79+
80+ var bestDecision decisionType
81+ bestDecision = replaceDecision {basicDecision {cost }}
7982
8083 if nodes .KindOf (src ) != nodes .KindOf (dst ) {
8184 ds .decisions [label ] = bestDecision
@@ -86,10 +89,12 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
8689
8790 case nodes.Value :
8891 src , dst := src .(nodes.Value ), dst .(nodes.Value )
92+ cost = 0
8993 if src == dst {
90- bestDecision . minEq ( & decision { 0 , sameDecision {}})
94+ bestDecision = min ( bestDecision , sameDecision {basicDecision { cost }})
9195 } else {
92- bestDecision .minEq (& decision {1 , replaceDecision {}})
96+ cost = 1
97+ bestDecision = min (bestDecision , replaceDecision {basicDecision {cost }})
9398 }
9499
95100 case nodes.Object :
@@ -101,17 +106,17 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
101106 for key := range keyset {
102107 if in := keys [key ]; ! in {
103108 keys [key ] = true
104- cost += ds .decideAction (src [key ], dst [key ]).cost
109+ cost += ds .decideAction (src [key ], dst [key ]).cost ()
105110 }
106111 }
107112 }
108113 iterate (src )
109114 iterate (dst )
110115
111116 if cost == 0 {
112- bestDecision . minEq ( & decision { cost , sameDecision {}})
117+ bestDecision = min ( bestDecision , sameDecision {basicDecision { cost }})
113118 } else {
114- bestDecision . minEq ( & decision { cost , matchDecision {}})
119+ bestDecision = min ( bestDecision , matchDecision {basicDecision { cost }})
115120 }
116121
117122 case nodes.Array :
@@ -120,11 +125,11 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
120125 if len (src ) == len (dst ) && func () int {
121126 sum := 0
122127 for i := range src {
123- sum += ds .decideAction (src [i ], dst [i ]).cost
128+ sum += ds .decideAction (src [i ], dst [i ]).cost ()
124129 }
125130 return sum
126131 }() == 0 {
127- bestDecision . minEq ( & decision { cost , sameDecision {}})
132+ bestDecision = min ( bestDecision , sameDecision {basicDecision { cost }})
128133 break
129134 }
130135
@@ -133,22 +138,20 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
133138 }
134139
135140 if len (src ) < len (dst ) {
136- l := len (dst ) - len (src )
137- for i := 0 ; i < l ; i ++ {
138- src = append (src , nil )
139- }
141+ arr := make (nodes.Array , len (dst ))
142+ copy (arr , src )
143+ src = arr
140144 } else {
141- l := len (src ) - len (dst )
142- for i := 0 ; i < l ; i ++ {
143- dst = append (dst , nil )
144- }
145+ arr := make (nodes.Array , len (src ))
146+ copy (arr , dst )
147+ dst = arr
145148 }
146149 n := len (src )
147150 m := make ([][]int , n )
148151 for i := 0 ; i < n ; i ++ {
149152 m [i ] = make ([]int , n )
150153 for j := 0 ; j < n ; j ++ {
151- m [i ][j ] = ds .decideAction (src [i ], dst [j ]).cost
154+ m [i ][j ] = ds .decideAction (src [i ], dst [j ]).cost ()
152155 }
153156 }
154157
@@ -163,13 +166,14 @@ func (ds *cacheStorage) decideAction(src, dst nodes.Node) decision {
163166
164167 cost += res .Cost
165168
166- bestDecision . minEq ( & decision { cost , permuteDecision {permutation : res .InRow } })
169+ bestDecision = min ( bestDecision , permuteDecision {basicDecision { cost }, res .InRow })
167170
168171 case nil :
169- bestDecision .minEq (& decision {0 , sameDecision {}})
172+ cost = 0
173+ bestDecision = min (bestDecision , sameDecision {basicDecision {cost }})
170174
171175 default :
172- panic (fmt .Sprintf ("unknown node type %T" , src ))
176+ panic (fmt .Errorf ("unknown node type %T" , src ))
173177 }
174178
175179 ds .decisions [label ] = bestDecision
@@ -201,7 +205,7 @@ func (ds *cacheStorage) createRec(node nodes.Node) {
201205
202206func (ds * cacheStorage ) generateDifference (src , dst nodes.Node , parentID ID , parentKey Key ) {
203207 decision := ds .decideAction (src , dst )
204- switch d := decision .decision . (type ) {
208+ switch d := decision .(type ) {
205209
206210 //no action required if same
207211 case sameDecision :
@@ -238,9 +242,9 @@ func (ds *cacheStorage) generateDifference(src, dst nodes.Node, parentID ID, par
238242 l := len (dst ) - len (src )
239243 //add possible nils to src
240244 if l > 0 {
241- for i := 0 ; i < l ; i ++ {
242- src = append ( src , nil )
243- }
245+ arr := make (nodes. Array , len ( dst ))
246+ copy ( arr , src )
247+ src = arr
244248 }
245249 recreate := false
246250 if l != 0 {
@@ -254,9 +258,9 @@ func (ds *cacheStorage) generateDifference(src, dst nodes.Node, parentID ID, par
254258 }
255259 if recreate {
256260 //recreate src with right perm
257- newsrc := make ([]nodes.Node , 0 , len (dst ))
261+ newsrc := make ([]nodes.Node , len (dst ))
258262 for i := 0 ; i < len (dst ); i ++ {
259- newsrc = append ( newsrc , src [d.permutation [i ]])
263+ newsrc [ i ] = src [d.permutation [i ]]
260264 }
261265 src = newsrc
262266 ds .push (& Create {node : src }) // TODO: not create, only mutate...
@@ -267,13 +271,13 @@ func (ds *cacheStorage) generateDifference(src, dst nodes.Node, parentID ID, par
267271 }
268272
269273 default :
270- panic (fmt .Sprintf ("unknown decision %v" , d ))
274+ panic (fmt .Errorf ("unknown decision %v" , d ))
271275 }
272276}
273277
274278func Cost (src , dst nodes.Node ) int {
275279 ds := emptyCacheStorage ()
276- return ds .decideAction (src , dst ).cost
280+ return ds .decideAction (src , dst ).cost ()
277281}
278282
279283func Changes (src , dst nodes.Node ) Changelist {
0 commit comments