github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/callgraph/vta/internal/trie/trie.go (about)

     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  
     5  // trie implements persistent Patricia trie maps.
     6  //
     7  // Each Map is effectively a map from uint64 to interface{}. Patricia tries are
     8  // a form of radix tree that are particularly appropriate when many maps will be
     9  // created, merged together and large amounts of sharing are expected (e.g.
    10  // environment abstract domains in program analysis).
    11  //
    12  // This implementation closely follows the paper:
    13  //   C. Okasaki and A. Gill, “Fast mergeable integer maps,” in ACM SIGPLAN
    14  //   Workshop on ML, September 1998, pp. 77–86.
    15  // Each Map is immutable and can be read from concurrently. The map does not
    16  // guarantee that the value pointed to by the interface{} value is not updated
    17  // concurrently.
    18  //
    19  // These Maps are optimized for situations where there will be many maps created at
    20  // with a high degree of sharing and combining of maps together. If you do not expect,
    21  // significant amount of sharing, the builtin map[T]U is much better choice!
    22  //
    23  // Each Map is created by a Builder. Each Builder has a unique Scope and each node is
    24  // created within this scope. Maps x and y are == if they contains the same
    25  // (key,value) mappings and have equal scopes.
    26  //
    27  // Internally these are big endian Patricia trie nodes, and the keys are sorted.
    28  package trie
    29  
    30  import (
    31  	"fmt"
    32  	"strings"
    33  )
    34  
    35  // Map is effectively a finite mapping from uint64 keys to interface{} values.
    36  // Maps are immutable and can be read from concurrently.
    37  //
    38  // Notes on concurrency:
    39  // - A Map value itself is an interface and assignments to a Map value can race.
    40  // - Map does not guarantee that the value pointed to by the interface{} value
    41  //   is not updated concurrently.
    42  type Map struct {
    43  	s Scope
    44  	n node
    45  }
    46  
    47  func (m Map) Scope() Scope {
    48  	return m.s
    49  }
    50  func (m Map) Size() int {
    51  	if m.n == nil {
    52  		return 0
    53  	}
    54  	return m.n.size()
    55  }
    56  func (m Map) Lookup(k uint64) (interface{}, bool) {
    57  	if m.n != nil {
    58  		if leaf := m.n.find(key(k)); leaf != nil {
    59  			return leaf.v, true
    60  		}
    61  	}
    62  	return nil, false
    63  }
    64  
    65  // Converts the map into a {<key>: <value>[, ...]} string. This uses the default
    66  // %s string conversion for <value>.
    67  func (m Map) String() string {
    68  	var kvs []string
    69  	m.Range(func(u uint64, i interface{}) bool {
    70  		kvs = append(kvs, fmt.Sprintf("%d: %s", u, i))
    71  		return true
    72  	})
    73  	return fmt.Sprintf("{%s}", strings.Join(kvs, ", "))
    74  }
    75  
    76  // Range over the leaf (key, value) pairs in the map in order and
    77  // applies cb(key, value) to each. Stops early if cb returns false.
    78  // Returns true if all elements were visited without stopping early.
    79  func (m Map) Range(cb func(uint64, interface{}) bool) bool {
    80  	if m.n != nil {
    81  		return m.n.visit(cb)
    82  	}
    83  	return true
    84  }
    85  
    86  // DeepEqual returns true if m and other contain the same (k, v) mappings
    87  // [regardless of Scope].
    88  //
    89  // Equivalently m.DeepEqual(other) <=> reflect.DeepEqual(Elems(m), Elems(other))
    90  func (m Map) DeepEqual(other Map) bool {
    91  	if m.Scope() == other.Scope() {
    92  		return m.n == other.n
    93  	}
    94  	if (m.n == nil) || (other.n == nil) {
    95  		return m.Size() == 0 && other.Size() == 0
    96  	}
    97  	return m.n.deepEqual(other.n)
    98  }
    99  
   100  // Elems are the (k,v) elements in the Map as a map[uint64]interface{}
   101  func Elems(m Map) map[uint64]interface{} {
   102  	dest := make(map[uint64]interface{}, m.Size())
   103  	m.Range(func(k uint64, v interface{}) bool {
   104  		dest[k] = v
   105  		return true
   106  	})
   107  	return dest
   108  }
   109  
   110  // node is an internal node within a trie map.
   111  // A node is either empty, a leaf or a branch.
   112  type node interface {
   113  	size() int
   114  
   115  	// visit the leaves (key, value) pairs in the map in order and
   116  	// applies cb(key, value) to each. Stops early if cb returns false.
   117  	// Returns true if all elements were visited without stopping early.
   118  	visit(cb func(uint64, interface{}) bool) bool
   119  
   120  	// Two nodes contain the same elements regardless of scope.
   121  	deepEqual(node) bool
   122  
   123  	// find the leaf for the given key value or nil if it is not present.
   124  	find(k key) *leaf
   125  
   126  	// implementations must implement this.
   127  	nodeImpl()
   128  }
   129  
   130  // empty represents the empty map within a scope.
   131  //
   132  // The current builder ensure
   133  type empty struct {
   134  	s Scope
   135  }
   136  
   137  // leaf represents a single <key, value> pair.
   138  type leaf struct {
   139  	k key
   140  	v interface{}
   141  }
   142  
   143  // branch represents a tree node within the Patricia trie.
   144  //
   145  // All keys within the branch match a `prefix` of the key
   146  // up to a `branching` bit, and the left and right nodes
   147  // contain keys that disagree on the bit at the `branching` bit.
   148  type branch struct {
   149  	sz        int    // size. cached for O(1) lookup
   150  	prefix    prefix // == mask(p0, branching) for some p0
   151  	branching bitpos
   152  
   153  	// Invariants:
   154  	// - neither is nil.
   155  	// - neither is *empty.
   156  	// - all keys in left are <= p.
   157  	// - all keys in right are > p.
   158  	left, right node
   159  }
   160  
   161  // all of these types are Maps.
   162  var _ node = &empty{}
   163  var _ node = &leaf{}
   164  var _ node = &branch{}
   165  
   166  func (*empty) nodeImpl()  {}
   167  func (*leaf) nodeImpl()   {}
   168  func (*branch) nodeImpl() {}
   169  
   170  func (*empty) find(k key) *leaf { return nil }
   171  func (l *leaf) find(k key) *leaf {
   172  	if k == l.k {
   173  		return l
   174  	}
   175  	return nil
   176  }
   177  func (br *branch) find(k key) *leaf {
   178  	kp := prefix(k)
   179  	if !matchPrefix(kp, br.prefix, br.branching) {
   180  		return nil
   181  	}
   182  	if zeroBit(kp, br.branching) {
   183  		return br.left.find(k)
   184  	}
   185  	return br.right.find(k)
   186  }
   187  
   188  func (*empty) size() int     { return 0 }
   189  func (*leaf) size() int      { return 1 }
   190  func (br *branch) size() int { return br.sz }
   191  
   192  func (*empty) deepEqual(m node) bool {
   193  	_, ok := m.(*empty)
   194  	return ok
   195  }
   196  func (l *leaf) deepEqual(m node) bool {
   197  	if m, ok := m.(*leaf); ok {
   198  		return m == l || (l.k == m.k && l.v == m.v)
   199  	}
   200  	return false
   201  }
   202  
   203  func (br *branch) deepEqual(m node) bool {
   204  	if m, ok := m.(*branch); ok {
   205  		if br == m {
   206  			return true
   207  		}
   208  		return br.sz == m.sz && br.branching == m.branching && br.prefix == m.prefix &&
   209  			br.left.deepEqual(m.left) && br.right.deepEqual(m.right)
   210  	}
   211  	// if m is not a branch, m contains 0 or 1 elem.
   212  	// br contains at least 2 keys that disagree on a prefix.
   213  	return false
   214  }
   215  
   216  func (*empty) visit(cb func(uint64, interface{}) bool) bool {
   217  	return true
   218  }
   219  func (l *leaf) visit(cb func(uint64, interface{}) bool) bool {
   220  	return cb(uint64(l.k), l.v)
   221  }
   222  func (br *branch) visit(cb func(uint64, interface{}) bool) bool {
   223  	if !br.left.visit(cb) {
   224  		return false
   225  	}
   226  	return br.right.visit(cb)
   227  }