Ensure stable map ordering for cycle ID allocation
Kyle Lemons
6 years ago
168 | 168 |
}
|
169 | 169 |
return n
|
170 | 170 |
case reflect.Map:
|
171 | |
n := keyvals{}
|
|
171 |
// Extract the keys and sort them for stable iteration
|
172 | 172 |
keys := val.MapKeys()
|
173 | |
ptr := val.Pointer()
|
|
173 |
pairs := make([]mapPair, 0, len(keys))
|
174 | 174 |
for _, key := range keys {
|
175 | |
// TODO(kevlar): Support arbitrary type keys?
|
|
175 |
pairs = append(pairs, mapPair{
|
|
176 |
key: compactString(r.val2node(key)), // can't be cyclic
|
|
177 |
value: val.MapIndex(key),
|
|
178 |
})
|
|
179 |
}
|
|
180 |
sort.Sort(byKey(pairs))
|
|
181 |
|
|
182 |
// Process the keys into the final representation
|
|
183 |
ptr, n := val.Pointer(), keyvals{}
|
|
184 |
for _, pair := range pairs {
|
176 | 185 |
n = append(n, keyval{
|
177 | |
key: compactString(r.follow(ptr, key)),
|
178 | |
val: r.follow(ptr, val.MapIndex(key)),
|
|
186 |
key: pair.key,
|
|
187 |
val: r.follow(ptr, pair.value),
|
179 | 188 |
})
|
180 | 189 |
}
|
181 | |
sort.Sort(n)
|
182 | 190 |
return n
|
183 | 191 |
case reflect.Struct:
|
184 | 192 |
n := keyvals{}
|
|
220 | 228 |
|
221 | 229 |
return rawVal(val.String())
|
222 | 230 |
}
|
|
231 |
|
|
232 |
type mapPair struct {
|
|
233 |
key string
|
|
234 |
value reflect.Value
|
|
235 |
}
|
|
236 |
|
|
237 |
type byKey []mapPair
|
|
238 |
|
|
239 |
func (v byKey) Len() int { return len(v) }
|
|
240 |
func (v byKey) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
|
241 |
func (v byKey) Less(i, j int) bool { return v[i].key < v[j].key }
|
202 | 202 |
{
|
203 | 203 |
desc: "circular list",
|
204 | 204 |
raw: circular(3),
|
205 | |
cfg: &Config{
|
206 | |
TrackCycles: true,
|
207 | |
},
|
|
205 |
cfg: CycleTracker,
|
208 | 206 |
ptrs: new(pointerTracker),
|
209 | 207 |
want: target{1, keyvals{
|
210 | 208 |
{"Value", rawVal("1")},
|
|
216 | 214 |
}},
|
217 | 215 |
}},
|
218 | 216 |
}},
|
|
217 |
},
|
|
218 |
{
|
|
219 |
desc: "self referential maps",
|
|
220 |
raw: sefRef(),
|
|
221 |
cfg: CycleTracker,
|
|
222 |
ptrs: new(pointerTracker),
|
|
223 |
want: target{1, keyvals{
|
|
224 |
{"ID", rawVal("1")},
|
|
225 |
{"Child", keyvals{
|
|
226 |
{"2", target{2, keyvals{
|
|
227 |
{"ID", rawVal("2")},
|
|
228 |
{"Child", keyvals{
|
|
229 |
{"3", target{3, keyvals{
|
|
230 |
{"ID", rawVal("3")},
|
|
231 |
{"Child", keyvals{
|
|
232 |
{"1", ref{1}},
|
|
233 |
{"2", ref{2}},
|
|
234 |
{"3", ref{3}},
|
|
235 |
}},
|
|
236 |
}}},
|
|
237 |
}},
|
|
238 |
}}},
|
|
239 |
}},
|
|
240 |
}},
|
|
241 |
},
|
|
242 |
{
|
|
243 |
desc: "maps of cycles",
|
|
244 |
raw: map[string]*ListNode{
|
|
245 |
"1. one": circular(1),
|
|
246 |
"2. two": circular(2),
|
|
247 |
"3. three": circular(1),
|
|
248 |
},
|
|
249 |
cfg: CycleTracker,
|
|
250 |
ptrs: new(pointerTracker),
|
|
251 |
want: keyvals{
|
|
252 |
{"1. one", target{1, keyvals{
|
|
253 |
{"Value", rawVal("1")},
|
|
254 |
{"Next", ref{1}},
|
|
255 |
}}},
|
|
256 |
{"2. two", target{2, keyvals{
|
|
257 |
{"Value", rawVal("1")},
|
|
258 |
{"Next", keyvals{
|
|
259 |
{"Value", rawVal("2")},
|
|
260 |
{"Next", ref{2}},
|
|
261 |
}},
|
|
262 |
}}},
|
|
263 |
{"3. three", target{3, keyvals{
|
|
264 |
{"Value", rawVal("1")},
|
|
265 |
{"Next", ref{3}},
|
|
266 |
}}},
|
|
267 |
},
|
219 | 268 |
},
|
220 | 269 |
}
|
221 | 270 |
|
|
255 | 304 |
recent = n
|
256 | 305 |
}
|
257 | 306 |
return recent
|
|
307 |
}
|
|
308 |
|
|
309 |
type SelfReferential struct {
|
|
310 |
ID int
|
|
311 |
Child map[int]*SelfReferential
|
|
312 |
}
|
|
313 |
|
|
314 |
func sefRef() *SelfReferential {
|
|
315 |
sr1 := &SelfReferential{
|
|
316 |
ID: 1,
|
|
317 |
Child: make(map[int]*SelfReferential),
|
|
318 |
}
|
|
319 |
sr2 := &SelfReferential{
|
|
320 |
ID: 2,
|
|
321 |
Child: make(map[int]*SelfReferential),
|
|
322 |
}
|
|
323 |
sr3 := &SelfReferential{
|
|
324 |
ID: 3,
|
|
325 |
Child: make(map[int]*SelfReferential),
|
|
326 |
}
|
|
327 |
|
|
328 |
// Build a cycle
|
|
329 |
sr1.Child[2] = sr2
|
|
330 |
sr2.Child[3] = sr3
|
|
331 |
sr3.Child[1] = sr1
|
|
332 |
|
|
333 |
// Throw in some other stuff for funzies
|
|
334 |
sr3.Child[2] = sr2
|
|
335 |
sr3.Child[3] = sr3
|
|
336 |
//sr1.Child[3] = sr3
|
|
337 |
return sr1
|
258 | 338 |
}
|
259 | 339 |
|
260 | 340 |
func BenchmarkVal2node(b *testing.B) {
|
55 | 55 |
}
|
56 | 56 |
|
57 | 57 |
type keyvals []keyval
|
58 | |
|
59 | |
func (l keyvals) Len() int { return len(l) }
|
60 | |
func (l keyvals) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
61 | |
func (l keyvals) Less(i, j int) bool { return l[i].key < l[j].key }
|
62 | 58 |
|
63 | 59 |
func (l keyvals) WriteTo(w *bytes.Buffer, indent string, cfg *Config) {
|
64 | 60 |
w.WriteByte('{')
|