diff options
Diffstat (limited to 'vendor/github.com/google/go-cmp/cmp/internal')
6 files changed, 939 insertions, 0 deletions
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go new file mode 100644 index 0000000..42afa49 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go | |||
@@ -0,0 +1,17 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | // +build !debug | ||
6 | |||
7 | package diff | ||
8 | |||
9 | var debug debugger | ||
10 | |||
11 | type debugger struct{} | ||
12 | |||
13 | func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { | ||
14 | return f | ||
15 | } | ||
16 | func (debugger) Update() {} | ||
17 | func (debugger) Finish() {} | ||
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go new file mode 100644 index 0000000..fd9f7f1 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go | |||
@@ -0,0 +1,122 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | // +build debug | ||
6 | |||
7 | package diff | ||
8 | |||
9 | import ( | ||
10 | "fmt" | ||
11 | "strings" | ||
12 | "sync" | ||
13 | "time" | ||
14 | ) | ||
15 | |||
16 | // The algorithm can be seen running in real-time by enabling debugging: | ||
17 | // go test -tags=debug -v | ||
18 | // | ||
19 | // Example output: | ||
20 | // === RUN TestDifference/#34 | ||
21 | // ┌───────────────────────────────┐ | ||
22 | // │ \ · · · · · · · · · · · · · · │ | ||
23 | // │ · # · · · · · · · · · · · · · │ | ||
24 | // │ · \ · · · · · · · · · · · · · │ | ||
25 | // │ · · \ · · · · · · · · · · · · │ | ||
26 | // │ · · · X # · · · · · · · · · · │ | ||
27 | // │ · · · # \ · · · · · · · · · · │ | ||
28 | // │ · · · · · # # · · · · · · · · │ | ||
29 | // │ · · · · · # \ · · · · · · · · │ | ||
30 | // │ · · · · · · · \ · · · · · · · │ | ||
31 | // │ · · · · · · · · \ · · · · · · │ | ||
32 | // │ · · · · · · · · · \ · · · · · │ | ||
33 | // │ · · · · · · · · · · \ · · # · │ | ||
34 | // │ · · · · · · · · · · · \ # # · │ | ||
35 | // │ · · · · · · · · · · · # # # · │ | ||
36 | // │ · · · · · · · · · · # # # # · │ | ||
37 | // │ · · · · · · · · · # # # # # · │ | ||
38 | // │ · · · · · · · · · · · · · · \ │ | ||
39 | // └───────────────────────────────┘ | ||
40 | // [.Y..M.XY......YXYXY.|] | ||
41 | // | ||
42 | // The grid represents the edit-graph where the horizontal axis represents | ||
43 | // list X and the vertical axis represents list Y. The start of the two lists | ||
44 | // is the top-left, while the ends are the bottom-right. The '·' represents | ||
45 | // an unexplored node in the graph. The '\' indicates that the two symbols | ||
46 | // from list X and Y are equal. The 'X' indicates that two symbols are similar | ||
47 | // (but not exactly equal) to each other. The '#' indicates that the two symbols | ||
48 | // are different (and not similar). The algorithm traverses this graph trying to | ||
49 | // make the paths starting in the top-left and the bottom-right connect. | ||
50 | // | ||
51 | // The series of '.', 'X', 'Y', and 'M' characters at the bottom represents | ||
52 | // the currently established path from the forward and reverse searches, | ||
53 | // separated by a '|' character. | ||
54 | |||
55 | const ( | ||
56 | updateDelay = 100 * time.Millisecond | ||
57 | finishDelay = 500 * time.Millisecond | ||
58 | ansiTerminal = true // ANSI escape codes used to move terminal cursor | ||
59 | ) | ||
60 | |||
61 | var debug debugger | ||
62 | |||
63 | type debugger struct { | ||
64 | sync.Mutex | ||
65 | p1, p2 EditScript | ||
66 | fwdPath, revPath *EditScript | ||
67 | grid []byte | ||
68 | lines int | ||
69 | } | ||
70 | |||
71 | func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { | ||
72 | dbg.Lock() | ||
73 | dbg.fwdPath, dbg.revPath = p1, p2 | ||
74 | top := "┌─" + strings.Repeat("──", nx) + "┐\n" | ||
75 | row := "│ " + strings.Repeat("· ", nx) + "│\n" | ||
76 | btm := "└─" + strings.Repeat("──", nx) + "┘\n" | ||
77 | dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) | ||
78 | dbg.lines = strings.Count(dbg.String(), "\n") | ||
79 | fmt.Print(dbg) | ||
80 | |||
81 | // Wrap the EqualFunc so that we can intercept each result. | ||
82 | return func(ix, iy int) (r Result) { | ||
83 | cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] | ||
84 | for i := range cell { | ||
85 | cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot | ||
86 | } | ||
87 | switch r = f(ix, iy); { | ||
88 | case r.Equal(): | ||
89 | cell[0] = '\\' | ||
90 | case r.Similar(): | ||
91 | cell[0] = 'X' | ||
92 | default: | ||
93 | cell[0] = '#' | ||
94 | } | ||
95 | return | ||
96 | } | ||
97 | } | ||
98 | |||
99 | func (dbg *debugger) Update() { | ||
100 | dbg.print(updateDelay) | ||
101 | } | ||
102 | |||
103 | func (dbg *debugger) Finish() { | ||
104 | dbg.print(finishDelay) | ||
105 | dbg.Unlock() | ||
106 | } | ||
107 | |||
108 | func (dbg *debugger) String() string { | ||
109 | dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] | ||
110 | for i := len(*dbg.revPath) - 1; i >= 0; i-- { | ||
111 | dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) | ||
112 | } | ||
113 | return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) | ||
114 | } | ||
115 | |||
116 | func (dbg *debugger) print(d time.Duration) { | ||
117 | if ansiTerminal { | ||
118 | fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor | ||
119 | } | ||
120 | fmt.Print(dbg) | ||
121 | time.Sleep(d) | ||
122 | } | ||
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go new file mode 100644 index 0000000..260befe --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go | |||
@@ -0,0 +1,363 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | // Package diff implements an algorithm for producing edit-scripts. | ||
6 | // The edit-script is a sequence of operations needed to transform one list | ||
7 | // of symbols into another (or vice-versa). The edits allowed are insertions, | ||
8 | // deletions, and modifications. The summation of all edits is called the | ||
9 | // Levenshtein distance as this problem is well-known in computer science. | ||
10 | // | ||
11 | // This package prioritizes performance over accuracy. That is, the run time | ||
12 | // is more important than obtaining a minimal Levenshtein distance. | ||
13 | package diff | ||
14 | |||
15 | // EditType represents a single operation within an edit-script. | ||
16 | type EditType uint8 | ||
17 | |||
18 | const ( | ||
19 | // Identity indicates that a symbol pair is identical in both list X and Y. | ||
20 | Identity EditType = iota | ||
21 | // UniqueX indicates that a symbol only exists in X and not Y. | ||
22 | UniqueX | ||
23 | // UniqueY indicates that a symbol only exists in Y and not X. | ||
24 | UniqueY | ||
25 | // Modified indicates that a symbol pair is a modification of each other. | ||
26 | Modified | ||
27 | ) | ||
28 | |||
29 | // EditScript represents the series of differences between two lists. | ||
30 | type EditScript []EditType | ||
31 | |||
32 | // String returns a human-readable string representing the edit-script where | ||
33 | // Identity, UniqueX, UniqueY, and Modified are represented by the | ||
34 | // '.', 'X', 'Y', and 'M' characters, respectively. | ||
35 | func (es EditScript) String() string { | ||
36 | b := make([]byte, len(es)) | ||
37 | for i, e := range es { | ||
38 | switch e { | ||
39 | case Identity: | ||
40 | b[i] = '.' | ||
41 | case UniqueX: | ||
42 | b[i] = 'X' | ||
43 | case UniqueY: | ||
44 | b[i] = 'Y' | ||
45 | case Modified: | ||
46 | b[i] = 'M' | ||
47 | default: | ||
48 | panic("invalid edit-type") | ||
49 | } | ||
50 | } | ||
51 | return string(b) | ||
52 | } | ||
53 | |||
54 | // stats returns a histogram of the number of each type of edit operation. | ||
55 | func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { | ||
56 | for _, e := range es { | ||
57 | switch e { | ||
58 | case Identity: | ||
59 | s.NI++ | ||
60 | case UniqueX: | ||
61 | s.NX++ | ||
62 | case UniqueY: | ||
63 | s.NY++ | ||
64 | case Modified: | ||
65 | s.NM++ | ||
66 | default: | ||
67 | panic("invalid edit-type") | ||
68 | } | ||
69 | } | ||
70 | return | ||
71 | } | ||
72 | |||
73 | // Dist is the Levenshtein distance and is guaranteed to be 0 if and only if | ||
74 | // lists X and Y are equal. | ||
75 | func (es EditScript) Dist() int { return len(es) - es.stats().NI } | ||
76 | |||
77 | // LenX is the length of the X list. | ||
78 | func (es EditScript) LenX() int { return len(es) - es.stats().NY } | ||
79 | |||
80 | // LenY is the length of the Y list. | ||
81 | func (es EditScript) LenY() int { return len(es) - es.stats().NX } | ||
82 | |||
83 | // EqualFunc reports whether the symbols at indexes ix and iy are equal. | ||
84 | // When called by Difference, the index is guaranteed to be within nx and ny. | ||
85 | type EqualFunc func(ix int, iy int) Result | ||
86 | |||
87 | // Result is the result of comparison. | ||
88 | // NSame is the number of sub-elements that are equal. | ||
89 | // NDiff is the number of sub-elements that are not equal. | ||
90 | type Result struct{ NSame, NDiff int } | ||
91 | |||
92 | // Equal indicates whether the symbols are equal. Two symbols are equal | ||
93 | // if and only if NDiff == 0. If Equal, then they are also Similar. | ||
94 | func (r Result) Equal() bool { return r.NDiff == 0 } | ||
95 | |||
96 | // Similar indicates whether two symbols are similar and may be represented | ||
97 | // by using the Modified type. As a special case, we consider binary comparisons | ||
98 | // (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. | ||
99 | // | ||
100 | // The exact ratio of NSame to NDiff to determine similarity may change. | ||
101 | func (r Result) Similar() bool { | ||
102 | // Use NSame+1 to offset NSame so that binary comparisons are similar. | ||
103 | return r.NSame+1 >= r.NDiff | ||
104 | } | ||
105 | |||
106 | // Difference reports whether two lists of lengths nx and ny are equal | ||
107 | // given the definition of equality provided as f. | ||
108 | // | ||
109 | // This function returns an edit-script, which is a sequence of operations | ||
110 | // needed to convert one list into the other. The following invariants for | ||
111 | // the edit-script are maintained: | ||
112 | // • eq == (es.Dist()==0) | ||
113 | // • nx == es.LenX() | ||
114 | // • ny == es.LenY() | ||
115 | // | ||
116 | // This algorithm is not guaranteed to be an optimal solution (i.e., one that | ||
117 | // produces an edit-script with a minimal Levenshtein distance). This algorithm | ||
118 | // favors performance over optimality. The exact output is not guaranteed to | ||
119 | // be stable and may change over time. | ||
120 | func Difference(nx, ny int, f EqualFunc) (es EditScript) { | ||
121 | // This algorithm is based on traversing what is known as an "edit-graph". | ||
122 | // See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" | ||
123 | // by Eugene W. Myers. Since D can be as large as N itself, this is | ||
124 | // effectively O(N^2). Unlike the algorithm from that paper, we are not | ||
125 | // interested in the optimal path, but at least some "decent" path. | ||
126 | // | ||
127 | // For example, let X and Y be lists of symbols: | ||
128 | // X = [A B C A B B A] | ||
129 | // Y = [C B A B A C] | ||
130 | // | ||
131 | // The edit-graph can be drawn as the following: | ||
132 | // A B C A B B A | ||
133 | // ┌─────────────┐ | ||
134 | // C │_|_|\|_|_|_|_│ 0 | ||
135 | // B │_|\|_|_|\|\|_│ 1 | ||
136 | // A │\|_|_|\|_|_|\│ 2 | ||
137 | // B │_|\|_|_|\|\|_│ 3 | ||
138 | // A │\|_|_|\|_|_|\│ 4 | ||
139 | // C │ | |\| | | | │ 5 | ||
140 | // └─────────────┘ 6 | ||
141 | // 0 1 2 3 4 5 6 7 | ||
142 | // | ||
143 | // List X is written along the horizontal axis, while list Y is written | ||
144 | // along the vertical axis. At any point on this grid, if the symbol in | ||
145 | // list X matches the corresponding symbol in list Y, then a '\' is drawn. | ||
146 | // The goal of any minimal edit-script algorithm is to find a path from the | ||
147 | // top-left corner to the bottom-right corner, while traveling through the | ||
148 | // fewest horizontal or vertical edges. | ||
149 | // A horizontal edge is equivalent to inserting a symbol from list X. | ||
150 | // A vertical edge is equivalent to inserting a symbol from list Y. | ||
151 | // A diagonal edge is equivalent to a matching symbol between both X and Y. | ||
152 | |||
153 | // Invariants: | ||
154 | // • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx | ||
155 | // • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny | ||
156 | // | ||
157 | // In general: | ||
158 | // • fwdFrontier.X < revFrontier.X | ||
159 | // • fwdFrontier.Y < revFrontier.Y | ||
160 | // Unless, it is time for the algorithm to terminate. | ||
161 | fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} | ||
162 | revPath := path{-1, point{nx, ny}, make(EditScript, 0)} | ||
163 | fwdFrontier := fwdPath.point // Forward search frontier | ||
164 | revFrontier := revPath.point // Reverse search frontier | ||
165 | |||
166 | // Search budget bounds the cost of searching for better paths. | ||
167 | // The longest sequence of non-matching symbols that can be tolerated is | ||
168 | // approximately the square-root of the search budget. | ||
169 | searchBudget := 4 * (nx + ny) // O(n) | ||
170 | |||
171 | // The algorithm below is a greedy, meet-in-the-middle algorithm for | ||
172 | // computing sub-optimal edit-scripts between two lists. | ||
173 | // | ||
174 | // The algorithm is approximately as follows: | ||
175 | // • Searching for differences switches back-and-forth between | ||
176 | // a search that starts at the beginning (the top-left corner), and | ||
177 | // a search that starts at the end (the bottom-right corner). The goal of | ||
178 | // the search is connect with the search from the opposite corner. | ||
179 | // • As we search, we build a path in a greedy manner, where the first | ||
180 | // match seen is added to the path (this is sub-optimal, but provides a | ||
181 | // decent result in practice). When matches are found, we try the next pair | ||
182 | // of symbols in the lists and follow all matches as far as possible. | ||
183 | // • When searching for matches, we search along a diagonal going through | ||
184 | // through the "frontier" point. If no matches are found, we advance the | ||
185 | // frontier towards the opposite corner. | ||
186 | // • This algorithm terminates when either the X coordinates or the | ||
187 | // Y coordinates of the forward and reverse frontier points ever intersect. | ||
188 | // | ||
189 | // This algorithm is correct even if searching only in the forward direction | ||
190 | // or in the reverse direction. We do both because it is commonly observed | ||
191 | // that two lists commonly differ because elements were added to the front | ||
192 | // or end of the other list. | ||
193 | // | ||
194 | // Running the tests with the "debug" build tag prints a visualization of | ||
195 | // the algorithm running in real-time. This is educational for understanding | ||
196 | // how the algorithm works. See debug_enable.go. | ||
197 | f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) | ||
198 | for { | ||
199 | // Forward search from the beginning. | ||
200 | if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { | ||
201 | break | ||
202 | } | ||
203 | for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { | ||
204 | // Search in a diagonal pattern for a match. | ||
205 | z := zigzag(i) | ||
206 | p := point{fwdFrontier.X + z, fwdFrontier.Y - z} | ||
207 | switch { | ||
208 | case p.X >= revPath.X || p.Y < fwdPath.Y: | ||
209 | stop1 = true // Hit top-right corner | ||
210 | case p.Y >= revPath.Y || p.X < fwdPath.X: | ||
211 | stop2 = true // Hit bottom-left corner | ||
212 | case f(p.X, p.Y).Equal(): | ||
213 | // Match found, so connect the path to this point. | ||
214 | fwdPath.connect(p, f) | ||
215 | fwdPath.append(Identity) | ||
216 | // Follow sequence of matches as far as possible. | ||
217 | for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { | ||
218 | if !f(fwdPath.X, fwdPath.Y).Equal() { | ||
219 | break | ||
220 | } | ||
221 | fwdPath.append(Identity) | ||
222 | } | ||
223 | fwdFrontier = fwdPath.point | ||
224 | stop1, stop2 = true, true | ||
225 | default: | ||
226 | searchBudget-- // Match not found | ||
227 | } | ||
228 | debug.Update() | ||
229 | } | ||
230 | // Advance the frontier towards reverse point. | ||
231 | if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { | ||
232 | fwdFrontier.X++ | ||
233 | } else { | ||
234 | fwdFrontier.Y++ | ||
235 | } | ||
236 | |||
237 | // Reverse search from the end. | ||
238 | if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { | ||
239 | break | ||
240 | } | ||
241 | for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { | ||
242 | // Search in a diagonal pattern for a match. | ||
243 | z := zigzag(i) | ||
244 | p := point{revFrontier.X - z, revFrontier.Y + z} | ||
245 | switch { | ||
246 | case fwdPath.X >= p.X || revPath.Y < p.Y: | ||
247 | stop1 = true // Hit bottom-left corner | ||
248 | case fwdPath.Y >= p.Y || revPath.X < p.X: | ||
249 | stop2 = true // Hit top-right corner | ||
250 | case f(p.X-1, p.Y-1).Equal(): | ||
251 | // Match found, so connect the path to this point. | ||
252 | revPath.connect(p, f) | ||
253 | revPath.append(Identity) | ||
254 | // Follow sequence of matches as far as possible. | ||
255 | for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { | ||
256 | if !f(revPath.X-1, revPath.Y-1).Equal() { | ||
257 | break | ||
258 | } | ||
259 | revPath.append(Identity) | ||
260 | } | ||
261 | revFrontier = revPath.point | ||
262 | stop1, stop2 = true, true | ||
263 | default: | ||
264 | searchBudget-- // Match not found | ||
265 | } | ||
266 | debug.Update() | ||
267 | } | ||
268 | // Advance the frontier towards forward point. | ||
269 | if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { | ||
270 | revFrontier.X-- | ||
271 | } else { | ||
272 | revFrontier.Y-- | ||
273 | } | ||
274 | } | ||
275 | |||
276 | // Join the forward and reverse paths and then append the reverse path. | ||
277 | fwdPath.connect(revPath.point, f) | ||
278 | for i := len(revPath.es) - 1; i >= 0; i-- { | ||
279 | t := revPath.es[i] | ||
280 | revPath.es = revPath.es[:i] | ||
281 | fwdPath.append(t) | ||
282 | } | ||
283 | debug.Finish() | ||
284 | return fwdPath.es | ||
285 | } | ||
286 | |||
287 | type path struct { | ||
288 | dir int // +1 if forward, -1 if reverse | ||
289 | point // Leading point of the EditScript path | ||
290 | es EditScript | ||
291 | } | ||
292 | |||
293 | // connect appends any necessary Identity, Modified, UniqueX, or UniqueY types | ||
294 | // to the edit-script to connect p.point to dst. | ||
295 | func (p *path) connect(dst point, f EqualFunc) { | ||
296 | if p.dir > 0 { | ||
297 | // Connect in forward direction. | ||
298 | for dst.X > p.X && dst.Y > p.Y { | ||
299 | switch r := f(p.X, p.Y); { | ||
300 | case r.Equal(): | ||
301 | p.append(Identity) | ||
302 | case r.Similar(): | ||
303 | p.append(Modified) | ||
304 | case dst.X-p.X >= dst.Y-p.Y: | ||
305 | p.append(UniqueX) | ||
306 | default: | ||
307 | p.append(UniqueY) | ||
308 | } | ||
309 | } | ||
310 | for dst.X > p.X { | ||
311 | p.append(UniqueX) | ||
312 | } | ||
313 | for dst.Y > p.Y { | ||
314 | p.append(UniqueY) | ||
315 | } | ||
316 | } else { | ||
317 | // Connect in reverse direction. | ||
318 | for p.X > dst.X && p.Y > dst.Y { | ||
319 | switch r := f(p.X-1, p.Y-1); { | ||
320 | case r.Equal(): | ||
321 | p.append(Identity) | ||
322 | case r.Similar(): | ||
323 | p.append(Modified) | ||
324 | case p.Y-dst.Y >= p.X-dst.X: | ||
325 | p.append(UniqueY) | ||
326 | default: | ||
327 | p.append(UniqueX) | ||
328 | } | ||
329 | } | ||
330 | for p.X > dst.X { | ||
331 | p.append(UniqueX) | ||
332 | } | ||
333 | for p.Y > dst.Y { | ||
334 | p.append(UniqueY) | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | func (p *path) append(t EditType) { | ||
340 | p.es = append(p.es, t) | ||
341 | switch t { | ||
342 | case Identity, Modified: | ||
343 | p.add(p.dir, p.dir) | ||
344 | case UniqueX: | ||
345 | p.add(p.dir, 0) | ||
346 | case UniqueY: | ||
347 | p.add(0, p.dir) | ||
348 | } | ||
349 | debug.Update() | ||
350 | } | ||
351 | |||
352 | type point struct{ X, Y int } | ||
353 | |||
354 | func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } | ||
355 | |||
356 | // zigzag maps a consecutive sequence of integers to a zig-zag sequence. | ||
357 | // [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] | ||
358 | func zigzag(x int) int { | ||
359 | if x&1 != 0 { | ||
360 | x = ^x | ||
361 | } | ||
362 | return x >> 1 | ||
363 | } | ||
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go new file mode 100644 index 0000000..4c35ff1 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go | |||
@@ -0,0 +1,49 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | // Package function identifies function types. | ||
6 | package function | ||
7 | |||
8 | import "reflect" | ||
9 | |||
10 | type funcType int | ||
11 | |||
12 | const ( | ||
13 | _ funcType = iota | ||
14 | |||
15 | ttbFunc // func(T, T) bool | ||
16 | tibFunc // func(T, I) bool | ||
17 | trFunc // func(T) R | ||
18 | |||
19 | Equal = ttbFunc // func(T, T) bool | ||
20 | EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool | ||
21 | Transformer = trFunc // func(T) R | ||
22 | ValueFilter = ttbFunc // func(T, T) bool | ||
23 | Less = ttbFunc // func(T, T) bool | ||
24 | ) | ||
25 | |||
26 | var boolType = reflect.TypeOf(true) | ||
27 | |||
28 | // IsType reports whether the reflect.Type is of the specified function type. | ||
29 | func IsType(t reflect.Type, ft funcType) bool { | ||
30 | if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { | ||
31 | return false | ||
32 | } | ||
33 | ni, no := t.NumIn(), t.NumOut() | ||
34 | switch ft { | ||
35 | case ttbFunc: // func(T, T) bool | ||
36 | if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { | ||
37 | return true | ||
38 | } | ||
39 | case tibFunc: // func(T, I) bool | ||
40 | if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { | ||
41 | return true | ||
42 | } | ||
43 | case trFunc: // func(T) R | ||
44 | if ni == 1 && no == 1 { | ||
45 | return true | ||
46 | } | ||
47 | } | ||
48 | return false | ||
49 | } | ||
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/format.go b/vendor/github.com/google/go-cmp/cmp/internal/value/format.go new file mode 100644 index 0000000..657e508 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/format.go | |||
@@ -0,0 +1,277 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | // Package value provides functionality for reflect.Value types. | ||
6 | package value | ||
7 | |||
8 | import ( | ||
9 | "fmt" | ||
10 | "reflect" | ||
11 | "strconv" | ||
12 | "strings" | ||
13 | "unicode" | ||
14 | ) | ||
15 | |||
16 | var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() | ||
17 | |||
18 | // Format formats the value v as a string. | ||
19 | // | ||
20 | // This is similar to fmt.Sprintf("%+v", v) except this: | ||
21 | // * Prints the type unless it can be elided | ||
22 | // * Avoids printing struct fields that are zero | ||
23 | // * Prints a nil-slice as being nil, not empty | ||
24 | // * Prints map entries in deterministic order | ||
25 | func Format(v reflect.Value, conf FormatConfig) string { | ||
26 | conf.printType = true | ||
27 | conf.followPointers = true | ||
28 | conf.realPointers = true | ||
29 | return formatAny(v, conf, nil) | ||
30 | } | ||
31 | |||
32 | type FormatConfig struct { | ||
33 | UseStringer bool // Should the String method be used if available? | ||
34 | printType bool // Should we print the type before the value? | ||
35 | PrintPrimitiveType bool // Should we print the type of primitives? | ||
36 | followPointers bool // Should we recursively follow pointers? | ||
37 | realPointers bool // Should we print the real address of pointers? | ||
38 | } | ||
39 | |||
40 | func formatAny(v reflect.Value, conf FormatConfig, visited map[uintptr]bool) string { | ||
41 | // TODO: Should this be a multi-line printout in certain situations? | ||
42 | |||
43 | if !v.IsValid() { | ||
44 | return "<non-existent>" | ||
45 | } | ||
46 | if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() { | ||
47 | if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() { | ||
48 | return "<nil>" | ||
49 | } | ||
50 | |||
51 | const stringerPrefix = "s" // Indicates that the String method was used | ||
52 | s := v.Interface().(fmt.Stringer).String() | ||
53 | return stringerPrefix + formatString(s) | ||
54 | } | ||
55 | |||
56 | switch v.Kind() { | ||
57 | case reflect.Bool: | ||
58 | return formatPrimitive(v.Type(), v.Bool(), conf) | ||
59 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
60 | return formatPrimitive(v.Type(), v.Int(), conf) | ||
61 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||
62 | if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr { | ||
63 | // Unnamed uints are usually bytes or words, so use hexadecimal. | ||
64 | return formatPrimitive(v.Type(), formatHex(v.Uint()), conf) | ||
65 | } | ||
66 | return formatPrimitive(v.Type(), v.Uint(), conf) | ||
67 | case reflect.Float32, reflect.Float64: | ||
68 | return formatPrimitive(v.Type(), v.Float(), conf) | ||
69 | case reflect.Complex64, reflect.Complex128: | ||
70 | return formatPrimitive(v.Type(), v.Complex(), conf) | ||
71 | case reflect.String: | ||
72 | return formatPrimitive(v.Type(), formatString(v.String()), conf) | ||
73 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: | ||
74 | return formatPointer(v, conf) | ||
75 | case reflect.Ptr: | ||
76 | if v.IsNil() { | ||
77 | if conf.printType { | ||
78 | return fmt.Sprintf("(%v)(nil)", v.Type()) | ||
79 | } | ||
80 | return "<nil>" | ||
81 | } | ||
82 | if visited[v.Pointer()] || !conf.followPointers { | ||
83 | return formatPointer(v, conf) | ||
84 | } | ||
85 | visited = insertPointer(visited, v.Pointer()) | ||
86 | return "&" + formatAny(v.Elem(), conf, visited) | ||
87 | case reflect.Interface: | ||
88 | if v.IsNil() { | ||
89 | if conf.printType { | ||
90 | return fmt.Sprintf("%v(nil)", v.Type()) | ||
91 | } | ||
92 | return "<nil>" | ||
93 | } | ||
94 | return formatAny(v.Elem(), conf, visited) | ||
95 | case reflect.Slice: | ||
96 | if v.IsNil() { | ||
97 | if conf.printType { | ||
98 | return fmt.Sprintf("%v(nil)", v.Type()) | ||
99 | } | ||
100 | return "<nil>" | ||
101 | } | ||
102 | if visited[v.Pointer()] { | ||
103 | return formatPointer(v, conf) | ||
104 | } | ||
105 | visited = insertPointer(visited, v.Pointer()) | ||
106 | fallthrough | ||
107 | case reflect.Array: | ||
108 | var ss []string | ||
109 | subConf := conf | ||
110 | subConf.printType = v.Type().Elem().Kind() == reflect.Interface | ||
111 | for i := 0; i < v.Len(); i++ { | ||
112 | s := formatAny(v.Index(i), subConf, visited) | ||
113 | ss = append(ss, s) | ||
114 | } | ||
115 | s := fmt.Sprintf("{%s}", strings.Join(ss, ", ")) | ||
116 | if conf.printType { | ||
117 | return v.Type().String() + s | ||
118 | } | ||
119 | return s | ||
120 | case reflect.Map: | ||
121 | if v.IsNil() { | ||
122 | if conf.printType { | ||
123 | return fmt.Sprintf("%v(nil)", v.Type()) | ||
124 | } | ||
125 | return "<nil>" | ||
126 | } | ||
127 | if visited[v.Pointer()] { | ||
128 | return formatPointer(v, conf) | ||
129 | } | ||
130 | visited = insertPointer(visited, v.Pointer()) | ||
131 | |||
132 | var ss []string | ||
133 | keyConf, valConf := conf, conf | ||
134 | keyConf.printType = v.Type().Key().Kind() == reflect.Interface | ||
135 | keyConf.followPointers = false | ||
136 | valConf.printType = v.Type().Elem().Kind() == reflect.Interface | ||
137 | for _, k := range SortKeys(v.MapKeys()) { | ||
138 | sk := formatAny(k, keyConf, visited) | ||
139 | sv := formatAny(v.MapIndex(k), valConf, visited) | ||
140 | ss = append(ss, fmt.Sprintf("%s: %s", sk, sv)) | ||
141 | } | ||
142 | s := fmt.Sprintf("{%s}", strings.Join(ss, ", ")) | ||
143 | if conf.printType { | ||
144 | return v.Type().String() + s | ||
145 | } | ||
146 | return s | ||
147 | case reflect.Struct: | ||
148 | var ss []string | ||
149 | subConf := conf | ||
150 | subConf.printType = true | ||
151 | for i := 0; i < v.NumField(); i++ { | ||
152 | vv := v.Field(i) | ||
153 | if isZero(vv) { | ||
154 | continue // Elide zero value fields | ||
155 | } | ||
156 | name := v.Type().Field(i).Name | ||
157 | subConf.UseStringer = conf.UseStringer | ||
158 | s := formatAny(vv, subConf, visited) | ||
159 | ss = append(ss, fmt.Sprintf("%s: %s", name, s)) | ||
160 | } | ||
161 | s := fmt.Sprintf("{%s}", strings.Join(ss, ", ")) | ||
162 | if conf.printType { | ||
163 | return v.Type().String() + s | ||
164 | } | ||
165 | return s | ||
166 | default: | ||
167 | panic(fmt.Sprintf("%v kind not handled", v.Kind())) | ||
168 | } | ||
169 | } | ||
170 | |||
171 | func formatString(s string) string { | ||
172 | // Use quoted string if it the same length as a raw string literal. | ||
173 | // Otherwise, attempt to use the raw string form. | ||
174 | qs := strconv.Quote(s) | ||
175 | if len(qs) == 1+len(s)+1 { | ||
176 | return qs | ||
177 | } | ||
178 | |||
179 | // Disallow newlines to ensure output is a single line. | ||
180 | // Only allow printable runes for readability purposes. | ||
181 | rawInvalid := func(r rune) bool { | ||
182 | return r == '`' || r == '\n' || !unicode.IsPrint(r) | ||
183 | } | ||
184 | if strings.IndexFunc(s, rawInvalid) < 0 { | ||
185 | return "`" + s + "`" | ||
186 | } | ||
187 | return qs | ||
188 | } | ||
189 | |||
190 | func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string { | ||
191 | if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") { | ||
192 | return fmt.Sprintf("%v(%v)", t, v) | ||
193 | } | ||
194 | return fmt.Sprintf("%v", v) | ||
195 | } | ||
196 | |||
197 | func formatPointer(v reflect.Value, conf FormatConfig) string { | ||
198 | p := v.Pointer() | ||
199 | if !conf.realPointers { | ||
200 | p = 0 // For deterministic printing purposes | ||
201 | } | ||
202 | s := formatHex(uint64(p)) | ||
203 | if conf.printType { | ||
204 | return fmt.Sprintf("(%v)(%s)", v.Type(), s) | ||
205 | } | ||
206 | return s | ||
207 | } | ||
208 | |||
209 | func formatHex(u uint64) string { | ||
210 | var f string | ||
211 | switch { | ||
212 | case u <= 0xff: | ||
213 | f = "0x%02x" | ||
214 | case u <= 0xffff: | ||
215 | f = "0x%04x" | ||
216 | case u <= 0xffffff: | ||
217 | f = "0x%06x" | ||
218 | case u <= 0xffffffff: | ||
219 | f = "0x%08x" | ||
220 | case u <= 0xffffffffff: | ||
221 | f = "0x%010x" | ||
222 | case u <= 0xffffffffffff: | ||
223 | f = "0x%012x" | ||
224 | case u <= 0xffffffffffffff: | ||
225 | f = "0x%014x" | ||
226 | case u <= 0xffffffffffffffff: | ||
227 | f = "0x%016x" | ||
228 | } | ||
229 | return fmt.Sprintf(f, u) | ||
230 | } | ||
231 | |||
232 | // insertPointer insert p into m, allocating m if necessary. | ||
233 | func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool { | ||
234 | if m == nil { | ||
235 | m = make(map[uintptr]bool) | ||
236 | } | ||
237 | m[p] = true | ||
238 | return m | ||
239 | } | ||
240 | |||
241 | // isZero reports whether v is the zero value. | ||
242 | // This does not rely on Interface and so can be used on unexported fields. | ||
243 | func isZero(v reflect.Value) bool { | ||
244 | switch v.Kind() { | ||
245 | case reflect.Bool: | ||
246 | return v.Bool() == false | ||
247 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
248 | return v.Int() == 0 | ||
249 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||
250 | return v.Uint() == 0 | ||
251 | case reflect.Float32, reflect.Float64: | ||
252 | return v.Float() == 0 | ||
253 | case reflect.Complex64, reflect.Complex128: | ||
254 | return v.Complex() == 0 | ||
255 | case reflect.String: | ||
256 | return v.String() == "" | ||
257 | case reflect.UnsafePointer: | ||
258 | return v.Pointer() == 0 | ||
259 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: | ||
260 | return v.IsNil() | ||
261 | case reflect.Array: | ||
262 | for i := 0; i < v.Len(); i++ { | ||
263 | if !isZero(v.Index(i)) { | ||
264 | return false | ||
265 | } | ||
266 | } | ||
267 | return true | ||
268 | case reflect.Struct: | ||
269 | for i := 0; i < v.NumField(); i++ { | ||
270 | if !isZero(v.Field(i)) { | ||
271 | return false | ||
272 | } | ||
273 | } | ||
274 | return true | ||
275 | } | ||
276 | return false | ||
277 | } | ||
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go new file mode 100644 index 0000000..fe8aa27 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go | |||
@@ -0,0 +1,111 @@ | |||
1 | // Copyright 2017, The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE.md file. | ||
4 | |||
5 | package value | ||
6 | |||
7 | import ( | ||
8 | "fmt" | ||
9 | "math" | ||
10 | "reflect" | ||
11 | "sort" | ||
12 | ) | ||
13 | |||
14 | // SortKeys sorts a list of map keys, deduplicating keys if necessary. | ||
15 | // The type of each value must be comparable. | ||
16 | func SortKeys(vs []reflect.Value) []reflect.Value { | ||
17 | if len(vs) == 0 { | ||
18 | return vs | ||
19 | } | ||
20 | |||
21 | // Sort the map keys. | ||
22 | sort.Sort(valueSorter(vs)) | ||
23 | |||
24 | // Deduplicate keys (fails for NaNs). | ||
25 | vs2 := vs[:1] | ||
26 | for _, v := range vs[1:] { | ||
27 | if isLess(vs2[len(vs2)-1], v) { | ||
28 | vs2 = append(vs2, v) | ||
29 | } | ||
30 | } | ||
31 | return vs2 | ||
32 | } | ||
33 | |||
34 | // TODO: Use sort.Slice once Google AppEngine is on Go1.8 or above. | ||
35 | type valueSorter []reflect.Value | ||
36 | |||
37 | func (vs valueSorter) Len() int { return len(vs) } | ||
38 | func (vs valueSorter) Less(i, j int) bool { return isLess(vs[i], vs[j]) } | ||
39 | func (vs valueSorter) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] } | ||
40 | |||
41 | // isLess is a generic function for sorting arbitrary map keys. | ||
42 | // The inputs must be of the same type and must be comparable. | ||
43 | func isLess(x, y reflect.Value) bool { | ||
44 | switch x.Type().Kind() { | ||
45 | case reflect.Bool: | ||
46 | return !x.Bool() && y.Bool() | ||
47 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
48 | return x.Int() < y.Int() | ||
49 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||
50 | return x.Uint() < y.Uint() | ||
51 | case reflect.Float32, reflect.Float64: | ||
52 | fx, fy := x.Float(), y.Float() | ||
53 | return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) | ||
54 | case reflect.Complex64, reflect.Complex128: | ||
55 | cx, cy := x.Complex(), y.Complex() | ||
56 | rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) | ||
57 | if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { | ||
58 | return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) | ||
59 | } | ||
60 | return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) | ||
61 | case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: | ||
62 | return x.Pointer() < y.Pointer() | ||
63 | case reflect.String: | ||
64 | return x.String() < y.String() | ||
65 | case reflect.Array: | ||
66 | for i := 0; i < x.Len(); i++ { | ||
67 | if isLess(x.Index(i), y.Index(i)) { | ||
68 | return true | ||
69 | } | ||
70 | if isLess(y.Index(i), x.Index(i)) { | ||
71 | return false | ||
72 | } | ||
73 | } | ||
74 | return false | ||
75 | case reflect.Struct: | ||
76 | for i := 0; i < x.NumField(); i++ { | ||
77 | if isLess(x.Field(i), y.Field(i)) { | ||
78 | return true | ||
79 | } | ||
80 | if isLess(y.Field(i), x.Field(i)) { | ||
81 | return false | ||
82 | } | ||
83 | } | ||
84 | return false | ||
85 | case reflect.Interface: | ||
86 | vx, vy := x.Elem(), y.Elem() | ||
87 | if !vx.IsValid() || !vy.IsValid() { | ||
88 | return !vx.IsValid() && vy.IsValid() | ||
89 | } | ||
90 | tx, ty := vx.Type(), vy.Type() | ||
91 | if tx == ty { | ||
92 | return isLess(x.Elem(), y.Elem()) | ||
93 | } | ||
94 | if tx.Kind() != ty.Kind() { | ||
95 | return vx.Kind() < vy.Kind() | ||
96 | } | ||
97 | if tx.String() != ty.String() { | ||
98 | return tx.String() < ty.String() | ||
99 | } | ||
100 | if tx.PkgPath() != ty.PkgPath() { | ||
101 | return tx.PkgPath() < ty.PkgPath() | ||
102 | } | ||
103 | // This can happen in rare situations, so we fallback to just comparing | ||
104 | // the unique pointer for a reflect.Type. This guarantees deterministic | ||
105 | // ordering within a program, but it is obviously not stable. | ||
106 | return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() | ||
107 | default: | ||
108 | // Must be Func, Map, or Slice; which are not comparable. | ||
109 | panic(fmt.Sprintf("%T is not comparable", x.Type())) | ||
110 | } | ||
111 | } | ||