Codebase list golang-github-kylelemons-godebug / 60ca602
Ensure stable map ordering for cycle ID allocation Kyle Lemons 6 years ago
3 changed file(s) with 108 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
168168 }
169169 return n
170170 case reflect.Map:
171 n := keyvals{}
171 // Extract the keys and sort them for stable iteration
172172 keys := val.MapKeys()
173 ptr := val.Pointer()
173 pairs := make([]mapPair, 0, len(keys))
174174 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 {
176185 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),
179188 })
180189 }
181 sort.Sort(n)
182190 return n
183191 case reflect.Struct:
184192 n := keyvals{}
220228
221229 return rawVal(val.String())
222230 }
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 }
202202 {
203203 desc: "circular list",
204204 raw: circular(3),
205 cfg: &Config{
206 TrackCycles: true,
207 },
205 cfg: CycleTracker,
208206 ptrs: new(pointerTracker),
209207 want: target{1, keyvals{
210208 {"Value", rawVal("1")},
216214 }},
217215 }},
218216 }},
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 },
219268 },
220269 }
221270
255304 recent = n
256305 }
257306 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
258338 }
259339
260340 func BenchmarkVal2node(b *testing.B) {
5555 }
5656
5757 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 }
6258
6359 func (l keyvals) WriteTo(w *bytes.Buffer, indent string, cfg *Config) {
6460 w.WriteByte('{')