this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/core/adt: deduplicate Vertex.Structs by StructLit

This avoids some duplicate entries with the same struct literal
but a different Environment or CloseInfo.

Those two fields of StructInfo are only used by tools/trim;
the export and toposort packages only use StructLit for their ordering.

Deduplicating with the three fields makes no difference to tools/trim,
so it's best if we deduplicate by StructLit. To avoid minor changes
to ordering in the toposort and export tests, we also track how many
times each StructLit had repeated calls to Vertex.AddStruct.
The toposort algorithm needs this to apply the proper weight to a
StructLit in its dependency analysis.

Note that we remove the result parameter from AddStruct,
which was never used and just made the logic harder to follow.

The allocation savings here are tiny but not the point of this change.
The big advantage is that we can further simplify the Vertex.Structs
structure once this change has been applied,
reducing the allocations past the cost of the added Repeats field.

│ old │ new │
│ B/op │ B/op vs base │
Roman 6.452Gi ± ∞ ¹ 6.471Gi ± ∞ ¹ +0.29% (p=1.000 n=1)

│ old │ new │
│ allocs/op │ allocs/op vs base │
Roman 68.00M ± ∞ ¹ 67.97M ± ∞ ¹ -0.04% (p=1.000 n=1)

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I6f36792b68d91e0b2edc42768367700f69e99e3d
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1226964
Reviewed-by: Marcel van Lohuizen <mpvl@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+45 -19
+11 -7
internal/core/adt/composite.go
··· 483 483 484 484 CloseInfo 485 485 486 + // Repeats tracks how many additional times this struct appeared via [Vertex.AddStruct]. 487 + // This is used by toposort to give proper weight to repeated structs. 488 + Repeats int 489 + 486 490 // Embed indicates the struct in which this struct is embedded (originally), 487 491 // or nil if this is a root structure. 488 492 // Embed *StructInfo ··· 1409 1413 v.Conjuncts = append(v.Conjuncts, c) 1410 1414 } 1411 1415 1412 - func (v *Vertex) AddStruct(s *StructLit, env *Environment, ci CloseInfo) *StructInfo { 1416 + func (v *Vertex) AddStruct(s *StructLit, env *Environment, ci CloseInfo) { 1417 + for _, t := range v.Structs { 1418 + if t.StructLit == s { 1419 + t.Repeats++ 1420 + return 1421 + } 1422 + } 1413 1423 info := StructInfo{ 1414 1424 StructLit: s, 1415 1425 Env: env, 1416 1426 CloseInfo: ci, 1417 1427 } 1418 - for _, t := range v.Structs { 1419 - if *t == info { // TODO: check for different identity. 1420 - return t 1421 - } 1422 - } 1423 1428 t := &info 1424 1429 v.Structs = append(v.Structs, t) 1425 - return t 1426 1430 } 1427 1431 1428 1432 // Path computes the sequence of Features leading from the root to of the
+14 -2
internal/core/export/toposort.go
··· 30 30 } 31 31 32 32 func extractFeatures(in []*adt.StructInfo) (a [][]adt.Feature) { 33 - a = make([][]adt.Feature, 0, len(in)) 33 + // Calculate total entries accounting for repeats. 34 + // Total occurrences = 1 + Repeats for each StructInfo. 35 + totalEntries := 0 36 + for _, s := range in { 37 + if len(s.Decls) > 0 { 38 + totalEntries += 1 + s.Repeats 39 + } 40 + } 41 + a = make([][]adt.Feature, 0, totalEntries) 34 42 for _, s := range in { 35 43 sorted := make([]adt.Feature, 0, len(s.Decls)) 36 44 for _, e := range s.Decls { ··· 43 51 // Lists with a single element may still be useful to distinguish 44 52 // between known and unknown fields: unknown fields are sorted last. 45 53 if len(sorted) > 0 { 46 - a = append(a, sorted) 54 + occurrences := 1 + s.Repeats 55 + // Add this front (1 + Repeats) times to give it proper weight 56 + for i := 0; i < occurrences; i++ { 57 + a = append(a, sorted) 58 + } 47 59 } 48 60 } 49 61 return a
+20 -10
internal/core/toposort/vertex.go
··· 231 231 nodeToStructMetas[node] = m 232 232 return m 233 233 } 234 - structMetas := make([]structMeta, len(structInfos)) 234 + 235 + totalMetas := 0 236 + for _, s := range structInfos { 237 + totalMetas += 1 + s.Repeats 238 + } 239 + structMetas := make([]structMeta, totalMetas) 235 240 236 241 // Create all the structMetas and map to them from a StructInfo's 237 242 // StructLit, and all its internal Decls. Initial attempt at 238 243 // recording a position, which will be correct only for direct use 239 244 // of literal structs in the calculation of vertex v. 240 - for i, s := range structInfos { 245 + // For each StructInfo, create (1 + Repeats) copies of its structMeta. 246 + metaIdx := 0 247 + for _, s := range structInfos { 241 248 sl := s.StructLit 242 - sMeta := &structMetas[i] 243 - sMeta.structInfo = s 249 + for range 1 + s.Repeats { 250 + sMeta := &structMetas[metaIdx] 251 + metaIdx++ 252 + sMeta.structInfo = s 244 253 245 - if src := sl.Source(); src != nil { 246 - sMeta.pos = src.Pos() 247 - } 248 - structMetaMap(sl)[sMeta] = true 249 - for _, decl := range sl.Decls { 250 - structMetaMap(decl)[sMeta] = true 254 + if src := sl.Source(); src != nil { 255 + sMeta.pos = src.Pos() 256 + } 257 + structMetaMap(sl)[sMeta] = true 258 + for _, decl := range sl.Decls { 259 + structMetaMap(decl)[sMeta] = true 260 + } 251 261 } 252 262 } 253 263