GoPLS Viewer

Home|gopls/go/callgraph/vta/internal/trie/builder.go
1// Copyright 2021 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 file.
4
5package trie
6
7// Collision functions combine a left and right hand side (lhs and rhs) values
8// the two values are associated with the same key and produces the value that
9// will be stored for the key.
10//
11// Collision functions must be idempotent:
12//
13//    collision(x, x) == x for all x.
14//
15// Collisions functions may be applied whenever a value is inserted
16// or two maps are merged, or intersected.
17type Collision func(lhs interface{}, rhs interface{}) interface{}
18
19// TakeLhs always returns the left value in a collision.
20func TakeLhs(lhsrhs interface{}) interface{} { return lhs }
21
22// TakeRhs always returns the right hand side in a collision.
23func TakeRhs(lhsrhs interface{}) interface{} { return rhs }
24
25// Builder creates new Map. Each Builder has a unique Scope.
26//
27// IMPORTANT:  Nodes are hash-consed internally to reduce memory consumption. To
28// support hash-consing Builders keep an internal Map of all of the Maps that they
29// have created. To GC any of the Maps created by the Builder, all references to
30// the Builder must be dropped. This includes MutMaps.
31type Builder struct {
32    scope Scope
33
34    // hash-consing maps for each node type.
35    empty    *empty
36    leaves   map[leaf]*leaf
37    branches map[branch]*branch
38    // It may be possible to support more types of patricia tries
39    // (e.g. non-hash-consed) by making Builder an interface and abstracting
40    // the mkLeaf and mkBranch functions.
41}
42
43// NewBuilder creates a new Builder with a unique Scope.
44func NewBuilder() *Builder {
45    s := newScope()
46    return &Builder{
47        scope:    s,
48        empty:    &empty{s},
49        leaves:   make(map[leaf]*leaf),
50        branchesmake(map[branch]*branch),
51    }
52}
53
54func (b *BuilderScope() Scope { return b.scope }
55
56// Rescope changes the builder's scope to a new unique Scope.
57//
58// Any Maps created using the previous scope need to be Cloned
59// before any operation.
60//
61// This makes the old internals of the Builder eligible to be GC'ed.
62func (b *BuilderRescope() {
63    s := newScope()
64    b.scope = s
65    b.empty = &empty{s}
66    b.leaves = make(map[leaf]*leaf)
67    b.branches = make(map[branch]*branch)
68}
69
70// Empty is the empty map.
71func (b *BuilderEmpty() Map { return Map{b.Scope(), b.empty} }
72
73// InsertWith inserts a new association from k to v into the Map m to create a new map
74// in the current scope and handle collisions using the collision function c.
75//
76// This is roughly corresponds to updating a map[uint64]interface{} by:
77//
78//    if _, ok := m[k]; ok { m[k] = c(m[k], v} else { m[k] = v}
79//
80// An insertion or update happened whenever Insert(m, ...) != m .
81func (b *BuilderInsertWith(c Collisionm Mapk uint64v interface{}) Map {
82    m = b.Clone(m)
83    return Map{b.Scope(), b.insert(cm.nb.mkLeaf(key(k), v), false)}
84}
85
86// Inserts a new association from key to value into the Map m to create
87// a new map in the current scope.
88//
89// If there was a previous value mapped by key, keep the previously mapped value.
90// This is roughly corresponds to updating a map[uint64]interface{} by:
91//
92//    if _, ok := m[k]; ok { m[k] = val }
93//
94// This is equivalent to b.Merge(m, b.Create({k: v})).
95func (b *BuilderInsert(m Mapk uint64v interface{}) Map {
96    return b.InsertWith(TakeLhsmkv)
97}
98
99// Updates a (key, value) in the map. This is roughly corresponds to
100// updating a map[uint64]interface{} by:
101//
102//    m[key] = val
103func (b *BuilderUpdate(m Mapkey uint64val interface{}) Map {
104    return b.InsertWith(TakeRhsmkeyval)
105}
106
107// Merge two maps lhs and rhs to create a new map in the current scope.
108//
109// Whenever there is a key in both maps (a collision), the resulting value mapped by
110// the key will be `c(lhs[key], rhs[key])`.
111func (b *BuilderMergeWith(c Collisionlhsrhs MapMap {
112    lhsrhs = b.Clone(lhs), b.Clone(rhs)
113    return Map{b.Scope(), b.merge(clhs.nrhs.n)}
114}
115
116// Merge two maps lhs and rhs to create a new map in the current scope.
117//
118// Whenever there is a key in both maps (a collision), the resulting value mapped by
119// the key will be the value in lhs `b.Collision(lhs[key], rhs[key])`.
120func (b *BuilderMerge(lhsrhs MapMap {
121    return b.MergeWith(TakeLhslhsrhs)
122}
123
124// Clone returns a Map that contains the same (key, value) elements
125// within b.Scope(), i.e. return m if m.Scope() == b.Scope() or return
126// a deep copy of m within b.Scope() otherwise.
127func (b *BuilderClone(m MapMap {
128    if m.Scope() == b.Scope() {
129        return m
130    } else if m.n == nil {
131        return Map{b.Scope(), b.empty}
132    }
133    return Map{b.Scope(), b.clone(m.n)}
134}
135func (b *Builderclone(n nodenode {
136    switch n := n.(type) {
137    case *empty:
138        return b.empty
139    case *leaf:
140        return b.mkLeaf(n.kn.v)
141    case *branch:
142        return b.mkBranch(n.prefixn.branchingb.clone(n.left), b.clone(n.right))
143    default:
144        panic("unreachable")
145    }
146}
147
148// Remove a key from a Map m and return the resulting Map.
149func (b *BuilderRemove(m Mapk uint64Map {
150    m = b.Clone(m)
151    return Map{b.Scope(), b.remove(m.nkey(k))}
152}
153
154// Intersect Maps lhs and rhs and returns a map with all of the keys in
155// both lhs and rhs and the value comes from lhs, i.e.
156//
157//    {(k, lhs[k]) | k in lhs, k in rhs}.
158func (b *BuilderIntersect(lhsrhs MapMap {
159    return b.IntersectWith(TakeLhslhsrhs)
160}
161
162// IntersectWith take lhs and rhs and returns the intersection
163// with the value coming from the collision function, i.e.
164//
165//    {(k, c(lhs[k], rhs[k]) ) | k in lhs, k in rhs}.
166//
167// The elements of the resulting map are always { <k, c(lhs[k], rhs[k]) > }
168// for each key k that a key in both lhs and rhs.
169func (b *BuilderIntersectWith(c Collisionlhsrhs MapMap {
170    lr := b.Clone(lhs), b.Clone(rhs)
171    return Map{b.Scope(), b.intersect(cl.nr.n)}
172}
173
174// MutMap is a convenient wrapper for a Map and a *Builder that will be used to create
175// new Maps from it.
176type MutMap struct {
177    B *Builder
178    M Map
179}
180
181// MutEmpty is an empty MutMap for a builder.
182func (b *BuilderMutEmpty() MutMap {
183    return MutMap{bb.Empty()}
184}
185
186// Insert an element into the map using the collision function for the builder.
187// Returns true if the element was inserted.
188func (mm *MutMapInsert(k uint64v interface{}) bool {
189    old := mm.M
190    mm.M = mm.B.Insert(oldkv)
191    return old != mm.M
192}
193
194// Updates an element in the map. Returns true if the map was updated.
195func (mm *MutMapUpdate(k uint64v interface{}) bool {
196    old := mm.M
197    mm.M = mm.B.Update(oldkv)
198    return old != mm.M
199}
200
201// Removes a key from the map. Returns true if the element was removed.
202func (mm *MutMapRemove(k uint64bool {
203    old := mm.M
204    mm.M = mm.B.Remove(oldk)
205    return old != mm.M
206}
207
208// Merge another map into the current one using the collision function
209// for the builder. Returns true if the map changed.
210func (mm *MutMapMerge(other Mapbool {
211    old := mm.M
212    mm.M = mm.B.Merge(oldother)
213    return old != mm.M
214}
215
216// Intersect another map into the current one using the collision function
217// for the builder. Returns true if the map changed.
218func (mm *MutMapIntersect(other Mapbool {
219    old := mm.M
220    mm.M = mm.B.Intersect(oldother)
221    return old != mm.M
222}
223
224func (b *BuilderCreate(m map[uint64]interface{}) Map {
225    var leaves []*leaf
226    for kv := range m {
227        leaves = append(leavesb.mkLeaf(key(k), v))
228    }
229    return Map{b.Scope(), b.create(leaves)}
230}
231
232// Merge another map into the current one using the collision function
233// for the builder. Returns true if the map changed.
234func (mm *MutMapMergeWith(c Collisionother Mapbool {
235    old := mm.M
236    mm.M = mm.B.MergeWith(coldother)
237    return old != mm.M
238}
239
240// creates a map for a collection of leaf nodes.
241func (b *Buildercreate(leaves []*leafnode {
242    n := len(leaves)
243    if n == 0 {
244        return b.empty
245    } else if n == 1 {
246        return leaves[0]
247    }
248    // Note: we can do a more sophisicated algorithm by:
249    // - sorting the leaves ahead of time,
250    // - taking the prefix and branching bit of the min and max key,
251    // - binary searching for the branching bit,
252    // - splitting exactly where the branch will be, and
253    // - making the branch node for this prefix + branching bit.
254    // Skipping until this is a performance bottleneck.
255
256    m := n / 2 // (n >= 2) ==> 1 <= m < n
257    lr := leaves[:m], leaves[m:]
258    return b.merge(nilb.create(l), b.create(r))
259}
260
261// mkLeaf returns the hash-consed representative of (k, v) in the current scope.
262func (b *BuildermkLeaf(k keyv interface{}) *leaf {
263    l := &leaf{kkvv}
264    if repok := b.leaves[*l]; ok {
265        return rep
266    }
267    b.leaves[*l] = l
268    return l
269}
270
271// mkBranch returns the hash-consed representative of the tuple
272//
273//    (prefix, branch, left, right)
274//
275// in the current scope.
276func (b *BuildermkBranch(p prefixbp bitposleft noderight node) *branch {
277    br := &branch{
278        sz:        left.size() + right.size(),
279        prefix:    p,
280        branchingbp,
281        left:      left,
282        right:     right,
283    }
284    if repok := b.branches[*br]; ok {
285        return rep
286    }
287    b.branches[*br] = br
288    return br
289}
290
291// join two maps with prefixes p0 and p1 that are *known* to disagree.
292func (b *Builderjoin(p0 prefixt0 nodep1 prefixt1 node) *branch {
293    m := branchingBit(p0p1)
294    var leftright node
295    if zeroBit(p0m) {
296        leftright = t0t1
297    } else {
298        leftright = t1t0
299    }
300    prefix := mask(p0m)
301    return b.mkBranch(prefixmleftright)
302}
303
304// collide two leaves with the same key to create a leaf
305// with the collided value.
306func (b *Buildercollide(c Collisionleftright *leaf) *leaf {
307    if left == right {
308        return left // c is idempotent: c(x, x) == x
309    }
310    val := left.v // keep the left value by default if c is nil
311    if c != nil {
312        val = c(left.vright.v)
313    }
314    switch val {
315    case left.v:
316        return left
317    case right.v:
318        return right
319    default:
320        return b.mkLeaf(left.kval)
321    }
322}
323
324// inserts a leaf l into a map m and returns the resulting map.
325// When lhs is true, l is the left hand side in a collision.
326// Both l and m are in the current scope.
327func (b *Builderinsert(c Collisionm nodel *leaflhs boolnode {
328    switch m := m.(type) {
329    case *empty:
330        return l
331    case *leaf:
332        if m.k == l.k {
333            leftright := lm
334            if !lhs {
335                leftright = rightleft
336            }
337            return b.collide(cleftright)
338        }
339        return b.join(prefix(l.k), lprefix(m.k), m)
340    case *branch:
341        // fallthrough
342    }
343    // m is a branch
344    br := m.(*branch)
345    if !matchPrefix(prefix(l.k), br.prefixbr.branching) {
346        return b.join(prefix(l.k), lbr.prefixbr)
347    }
348    var leftright node
349    if zeroBit(prefix(l.k), br.branching) {
350        leftright = b.insert(cbr.leftllhs), br.right
351    } else {
352        leftright = br.leftb.insert(cbr.rightllhs)
353    }
354    if left == br.left && right == br.right {
355        return m
356    }
357    return b.mkBranch(br.prefixbr.branchingleftright)
358}
359
360// merge two maps in the current scope.
361func (b *Buildermerge(c Collisionlhsrhs nodenode {
362    if lhs == rhs {
363        return lhs
364    }
365    switch lhs := lhs.(type) {
366    case *empty:
367        return rhs
368    case *leaf:
369        return b.insert(crhslhstrue)
370    case *branch:
371        switch rhs := rhs.(type) {
372        case *empty:
373            return lhs
374        case *leaf:
375            return b.insert(clhsrhsfalse)
376        case *branch:
377            // fallthrough
378        }
379    }
380
381    // Last remaining case is branch branch merging.
382    // For brevity, we adopt the Okasaki and Gill naming conventions
383    // for branching and prefixes.
384    st := lhs.(*branch), rhs.(*branch)
385    pm := s.prefixs.branching
386    qn := t.prefixt.branching
387
388    if m == n && p == q { // prefixes are identical.
389        leftright := b.merge(cs.leftt.left), b.merge(cs.rightt.right)
390        return b.mkBranch(pmleftright)
391    }
392    if !prefixesOverlap(pmqn) {
393        return b.join(psqt// prefixes are disjoint.
394    }
395    // prefixesOverlap(p, m, q, n) && !(m ==n && p == q)
396    // By prefixesOverlap(...), either:
397    //   higher(m, n) && matchPrefix(q, p, m), or
398    //   higher(n, m) && matchPrefix(p, q, n)
399    // So either s or t may can be merged with one branch or the other.
400    switch {
401    case ord(mn) && zeroBit(qm):
402        return b.mkBranch(pmb.merge(cs.leftt), s.right)
403    case ord(mn) && !zeroBit(qm):
404        return b.mkBranch(pms.leftb.merge(cs.rightt))
405    case ord(nm) && zeroBit(pn):
406        return b.mkBranch(qnb.merge(cst.left), t.right)
407    default:
408        return b.mkBranch(qnt.leftb.merge(cst.right))
409    }
410}
411
412func (b *Builderremove(m nodek keynode {
413    switch m := m.(type) {
414    case *empty:
415        return m
416    case *leaf:
417        if m.k == k {
418            return b.empty
419        }
420        return m
421    case *branch:
422        // fallthrough
423    }
424    br := m.(*branch)
425    kp := prefix(k)
426    if !matchPrefix(kpbr.prefixbr.branching) {
427        // The prefix does not match. kp is not in br.
428        return br
429    }
430    // the prefix matches. try to remove from the left or right branch.
431    leftright := br.leftbr.right
432    if zeroBit(kpbr.branching) {
433        left = b.remove(leftk// k may be in the left branch.
434    } else {
435        right = b.remove(rightk// k may be in the right branch.
436    }
437    if left == br.left && right == br.right {
438        return br // no update
439    } else if _ok := left.(*empty); ok {
440        return right // left updated and is empty.
441    } else if _ok := right.(*empty); ok {
442        return left // right updated and is empty.
443    }
444    // Either left or right updated. Both left and right are not empty.
445    // The left and right branches still share the same prefix and disagree
446    // on the same branching bit. It is safe to directly create the branch.
447    return b.mkBranch(br.prefixbr.branchingleftright)
448}
449
450func (b *Builderintersect(c Collisionlr nodenode {
451    if l == r {
452        return l
453    }
454    switch l := l.(type) {
455    case *empty:
456        return b.empty
457    case *leaf:
458        if rleaf := r.find(l.k); rleaf != nil {
459            return b.collide(clrleaf)
460        }
461        return b.empty
462    case *branch:
463        switch r := r.(type) {
464        case *empty:
465            return b.empty
466        case *leaf:
467            if lleaf := l.find(r.k); lleaf != nil {
468                return b.collide(clleafr)
469            }
470            return b.empty
471        case *branch:
472            // fallthrough
473        }
474    }
475    // Last remaining case is branch branch intersection.
476    st := l.(*branch), r.(*branch)
477    pm := s.prefixs.branching
478    qn := t.prefixt.branching
479
480    if m == n && p == q {
481        // prefixes are identical.
482        leftright := b.intersect(cs.leftt.left), b.intersect(cs.rightt.right)
483        if _ok := left.(*empty); ok {
484            return right
485        } else if _ok := right.(*empty); ok {
486            return left
487        }
488        // The left and right branches are both non-empty.
489        // They still share the same prefix and disagree on the same branching bit.
490        // It is safe to directly create the branch.
491        return b.mkBranch(pmleftright)
492    }
493
494    if !prefixesOverlap(pmqn) {
495        return b.empty // The prefixes share no keys.
496    }
497    // prefixesOverlap(p, m, q, n) && !(m ==n && p == q)
498    // By prefixesOverlap(...), either:
499    //   ord(m, n) && matchPrefix(q, p, m), or
500    //   ord(n, m) && matchPrefix(p, q, n)
501    // So either s or t may be a strict subtree of the other.
502    var lhsrhs node
503    switch {
504    case ord(mn) && zeroBit(qm):
505        lhsrhs = s.leftt
506    case ord(mn) && !zeroBit(qm):
507        lhsrhs = s.rightt
508    case ord(nm) && zeroBit(pn):
509        lhsrhs = st.left
510    default:
511        lhsrhs = st.right
512    }
513    return b.intersect(clhsrhs)
514}
515
MembersX
Builder.clone.b
Builder.Update.key
MutMap.Update.old
Builder.join.prefix
Builder.collide.right
Builder.intersect.r
Builder.Update.val
MutMap.Merge
MutMap.Intersect.old
Builder.insert
Builder.merge.BlockStmt.left
Builder.Insert.k
Builder.leaves
MutMap.Insert.mm
Builder.mkLeaf
Builder.mkLeaf.k
Builder.mkLeaf.l
Builder.mkBranch.p
Builder.join.m
Builder
Builder.merge
Builder.merge.q
Builder.collide.val
TakeLhs.rhs
Builder.Merge
Builder.Remove.m
Builder.IntersectWith.b
Builder.Create.b
MutMap.MergeWith.c
TakeLhs.lhs
Builder.Remove
Builder.join
Builder.intersect.BlockStmt.right
Builder.Update.m
Builder.Empty.b
Builder.Create
Builder.Rescope
Builder.collide
Builder.collide.b
Builder.Intersect.lhs
MutMap.Remove
Builder.merge.rhs
Builder.intersect.q
Builder.Intersect
Builder.join.left
Builder.insert.left
Builder.mkBranch.right
Builder.Update.b
Builder.IntersectWith
MutMap.Remove.mm
Builder.Create.RangeStmt_7222.v
Builder.join.p1
Builder.intersect.b
Builder.intersect.rhs
Builder.InsertWith.m
MutMap.Insert.v
MutMap.Merge.old
MutMap.Intersect.other
Builder.join.p0
Builder.merge.m
Builder.Merge.lhs
Builder.Rescope.s
Builder.clone
Builder.create.leaves
Builder.create.n
Builder.intersect.BlockStmt.BlockStmt.lleaf
Builder.empty
Builder.Empty
Builder.Remove.k
Builder.Create.m
Builder.collide.c
Builder.merge.lhs
Builder.intersect.BlockStmt.left
TakeLhs
MutMap.Insert.old
MutMap.Update.k
Builder.Create.leaves
Builder.MergeWith.rhs
Builder.IntersectWith.r
MutMap.Merge.other
Collision
Builder.Scope.b
Builder.InsertWith.c
MutMap.MergeWith.other
Builder.mkLeaf.b
Builder.insert.l
Builder.remove.left
TakeRhs.rhs
Builder.Scope
Builder.Insert
Builder.Update
Builder.Intersect.b
Builder.MutEmpty
Builder.join.t0
Builder.branches
Builder.MutEmpty.b
MutMap.Remove.old
Builder.create.b
Builder.mkBranch.left
Builder.collide.left
Builder.insert.c
Builder.insert.m
Builder.InsertWith.k
Builder.merge.BlockStmt.right
Builder.remove.m
Builder.remove.k
Builder.merge.b
Builder.MergeWith.c
MutMap.Insert.k
MutMap.Remove.k
Builder.mkBranch.bp
Builder.insert.lhs
Builder.insert.BlockStmt.BlockStmt.right
Builder.intersect.l
NewBuilder.s
Builder.join.right
Builder.remove.kp
Builder.mkBranch.b
Builder.InsertWith.v
Builder.Intersect.rhs
Builder.IntersectWith.rhs
MutMap.Update.v
Builder.intersect.BlockStmt.rleaf
Builder.scope
Builder.MergeWith.b
Builder.remove.b
Builder.Insert.v
Builder.InsertWith.b
MutMap.Insert
MutMap.Update.mm
Builder.merge.c
Builder.remove.right
Builder.intersect.p
Builder.intersect.n
NewBuilder
Builder.Rescope.b
Builder.Merge.b
Builder.IntersectWith.l
MutMap.MergeWith
Builder.intersect.m
TakeRhs
Builder.clone.n
MutMap.M
Builder.Create.RangeStmt_7222.k
Builder.mkBranch
Builder.join.b
Builder.intersect
Builder.intersect.c
Builder.Clone
MutMap.Merge.mm
MutMap.MergeWith.mm
MutMap.MergeWith.old
Builder.Insert.b
Builder.Remove.b
Builder.IntersectWith.lhs
Builder.join.t1
Builder.remove
Builder.Insert.m
MutMap.Intersect.mm
MutMap.Intersect
Builder.create
Builder.insert.b
Builder.intersect.lhs
MutMap.B
Builder.InsertWith
Builder.MergeWith
Builder.MergeWith.lhs
Builder.Clone.b
Builder.Clone.m
Builder.IntersectWith.c
MutMap
TakeRhs.lhs
Builder.mkLeaf.v
Builder.mkBranch.br
Builder.merge.n
MutMap.Update
Builder.insert.BlockStmt.BlockStmt.left
Builder.insert.right
Builder.merge.p
Builder.Merge.rhs
Members
X