builder.go (14983B)
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 package 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. 17 type Collision func(lhs any, rhs any) any 18 19 // TakeLhs always returns the left value in a collision. 20 func TakeLhs(lhs, rhs any) any { return lhs } 21 22 // TakeRhs always returns the right hand side in a collision. 23 func TakeRhs(lhs, rhs any) any { 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. 31 type 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. 44 func NewBuilder() *Builder { 45 s := newScope() 46 return &Builder{ 47 scope: s, 48 empty: &empty{s}, 49 leaves: make(map[leaf]*leaf), 50 branches: make(map[branch]*branch), 51 } 52 } 53 54 func (b *Builder) Scope() 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. 62 func (b *Builder) Rescope() { 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. 71 func (b *Builder) Empty() 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 . 81 func (b *Builder) InsertWith(c Collision, m Map, k uint64, v any) Map { 82 m = b.Clone(m) 83 return Map{b.Scope(), b.insert(c, m.n, b.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})). 95 func (b *Builder) Insert(m Map, k uint64, v any) Map { 96 return b.InsertWith(TakeLhs, m, k, v) 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 103 func (b *Builder) Update(m Map, key uint64, val any) Map { 104 return b.InsertWith(TakeRhs, m, key, val) 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])`. 111 func (b *Builder) MergeWith(c Collision, lhs, rhs Map) Map { 112 lhs, rhs = b.Clone(lhs), b.Clone(rhs) 113 return Map{b.Scope(), b.merge(c, lhs.n, rhs.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])`. 120 func (b *Builder) Merge(lhs, rhs Map) Map { 121 return b.MergeWith(TakeLhs, lhs, rhs) 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. 127 func (b *Builder) Clone(m Map) Map { 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 } 135 func (b *Builder) clone(n node) node { 136 switch n := n.(type) { 137 case *empty: 138 return b.empty 139 case *leaf: 140 return b.mkLeaf(n.k, n.v) 141 case *branch: 142 return b.mkBranch(n.prefix, n.branching, b.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. 149 func (b *Builder) Remove(m Map, k uint64) Map { 150 m = b.Clone(m) 151 return Map{b.Scope(), b.remove(m.n, key(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}. 158 func (b *Builder) Intersect(lhs, rhs Map) Map { 159 return b.IntersectWith(TakeLhs, lhs, rhs) 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. 169 func (b *Builder) IntersectWith(c Collision, lhs, rhs Map) Map { 170 l, r := b.Clone(lhs), b.Clone(rhs) 171 return Map{b.Scope(), b.intersect(c, l.n, r.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. 176 type MutMap struct { 177 B *Builder 178 M Map 179 } 180 181 // MutEmpty is an empty MutMap for a builder. 182 func (b *Builder) MutEmpty() MutMap { 183 return MutMap{b, b.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. 188 func (mm *MutMap) Insert(k uint64, v any) bool { 189 old := mm.M 190 mm.M = mm.B.Insert(old, k, v) 191 return old != mm.M 192 } 193 194 // Updates an element in the map. Returns true if the map was updated. 195 func (mm *MutMap) Update(k uint64, v any) bool { 196 old := mm.M 197 mm.M = mm.B.Update(old, k, v) 198 return old != mm.M 199 } 200 201 // Removes a key from the map. Returns true if the element was removed. 202 func (mm *MutMap) Remove(k uint64) bool { 203 old := mm.M 204 mm.M = mm.B.Remove(old, k) 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. 210 func (mm *MutMap) Merge(other Map) bool { 211 old := mm.M 212 mm.M = mm.B.Merge(old, other) 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. 218 func (mm *MutMap) Intersect(other Map) bool { 219 old := mm.M 220 mm.M = mm.B.Intersect(old, other) 221 return old != mm.M 222 } 223 224 func (b *Builder) Create(m map[uint64]any) Map { 225 var leaves []*leaf 226 for k, v := range m { 227 leaves = append(leaves, b.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. 234 func (mm *MutMap) MergeWith(c Collision, other Map) bool { 235 old := mm.M 236 mm.M = mm.B.MergeWith(c, old, other) 237 return old != mm.M 238 } 239 240 // creates a map for a collection of leaf nodes. 241 func (b *Builder) create(leaves []*leaf) node { 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 sophisticated 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 l, r := leaves[:m], leaves[m:] 258 return b.merge(nil, b.create(l), b.create(r)) 259 } 260 261 // mkLeaf returns the hash-consed representative of (k, v) in the current scope. 262 func (b *Builder) mkLeaf(k key, v any) *leaf { 263 rep, ok := b.leaves[leaf{k, v}] 264 if !ok { 265 rep = &leaf{k, v} // heap-allocated copy 266 b.leaves[leaf{k, v}] = rep 267 } 268 return rep 269 } 270 271 // mkBranch returns the hash-consed representative of the tuple 272 // 273 // (prefix, branch, left, right) 274 // 275 // in the current scope. 276 func (b *Builder) mkBranch(p prefix, bp bitpos, left node, right node) *branch { 277 br := branch{ 278 sz: left.size() + right.size(), 279 prefix: p, 280 branching: bp, 281 left: left, 282 right: right, 283 } 284 rep, ok := b.branches[br] 285 if !ok { 286 rep = new(branch) // heap-allocated copy 287 *rep = br 288 b.branches[br] = rep 289 } 290 return rep 291 } 292 293 // join two maps with prefixes p0 and p1 that are *known* to disagree. 294 func (b *Builder) join(p0 prefix, t0 node, p1 prefix, t1 node) *branch { 295 m := branchingBit(p0, p1) 296 var left, right node 297 if zeroBit(p0, m) { 298 left, right = t0, t1 299 } else { 300 left, right = t1, t0 301 } 302 prefix := mask(p0, m) 303 return b.mkBranch(prefix, m, left, right) 304 } 305 306 // collide two leaves with the same key to create a leaf 307 // with the collided value. 308 func (b *Builder) collide(c Collision, left, right *leaf) *leaf { 309 if left == right { 310 return left // c is idempotent: c(x, x) == x 311 } 312 val := left.v // keep the left value by default if c is nil 313 if c != nil { 314 val = c(left.v, right.v) 315 } 316 switch val { 317 case left.v: 318 return left 319 case right.v: 320 return right 321 default: 322 return b.mkLeaf(left.k, val) 323 } 324 } 325 326 // inserts a leaf l into a map m and returns the resulting map. 327 // When lhs is true, l is the left hand side in a collision. 328 // Both l and m are in the current scope. 329 func (b *Builder) insert(c Collision, m node, l *leaf, lhs bool) node { 330 switch m := m.(type) { 331 case *empty: 332 return l 333 case *leaf: 334 if m.k == l.k { 335 left, right := l, m 336 if !lhs { 337 left, right = right, left 338 } 339 return b.collide(c, left, right) 340 } 341 return b.join(prefix(l.k), l, prefix(m.k), m) 342 case *branch: 343 // fallthrough 344 } 345 // m is a branch 346 br := m.(*branch) 347 if !matchPrefix(prefix(l.k), br.prefix, br.branching) { 348 return b.join(prefix(l.k), l, br.prefix, br) 349 } 350 var left, right node 351 if zeroBit(prefix(l.k), br.branching) { 352 left, right = b.insert(c, br.left, l, lhs), br.right 353 } else { 354 left, right = br.left, b.insert(c, br.right, l, lhs) 355 } 356 if left == br.left && right == br.right { 357 return m 358 } 359 return b.mkBranch(br.prefix, br.branching, left, right) 360 } 361 362 // merge two maps in the current scope. 363 func (b *Builder) merge(c Collision, lhs, rhs node) node { 364 if lhs == rhs { 365 return lhs 366 } 367 switch lhs := lhs.(type) { 368 case *empty: 369 return rhs 370 case *leaf: 371 return b.insert(c, rhs, lhs, true) 372 case *branch: 373 switch rhs := rhs.(type) { 374 case *empty: 375 return lhs 376 case *leaf: 377 return b.insert(c, lhs, rhs, false) 378 case *branch: 379 // fallthrough 380 } 381 } 382 383 // Last remaining case is branch merging. 384 // For brevity, we adopt the Okasaki and Gill naming conventions 385 // for branching and prefixes. 386 s, t := lhs.(*branch), rhs.(*branch) 387 p, m := s.prefix, s.branching 388 q, n := t.prefix, t.branching 389 390 if m == n && p == q { // prefixes are identical. 391 left, right := b.merge(c, s.left, t.left), b.merge(c, s.right, t.right) 392 return b.mkBranch(p, m, left, right) 393 } 394 if !prefixesOverlap(p, m, q, n) { 395 return b.join(p, s, q, t) // prefixes are disjoint. 396 } 397 // prefixesOverlap(p, m, q, n) && !(m ==n && p == q) 398 // By prefixesOverlap(...), either: 399 // higher(m, n) && matchPrefix(q, p, m), or 400 // higher(n, m) && matchPrefix(p, q, n) 401 // So either s or t may can be merged with one branch or the other. 402 switch { 403 case ord(m, n) && zeroBit(q, m): 404 return b.mkBranch(p, m, b.merge(c, s.left, t), s.right) 405 case ord(m, n) && !zeroBit(q, m): 406 return b.mkBranch(p, m, s.left, b.merge(c, s.right, t)) 407 case ord(n, m) && zeroBit(p, n): 408 return b.mkBranch(q, n, b.merge(c, s, t.left), t.right) 409 default: 410 return b.mkBranch(q, n, t.left, b.merge(c, s, t.right)) 411 } 412 } 413 414 func (b *Builder) remove(m node, k key) node { 415 switch m := m.(type) { 416 case *empty: 417 return m 418 case *leaf: 419 if m.k == k { 420 return b.empty 421 } 422 return m 423 case *branch: 424 // fallthrough 425 } 426 br := m.(*branch) 427 kp := prefix(k) 428 if !matchPrefix(kp, br.prefix, br.branching) { 429 // The prefix does not match. kp is not in br. 430 return br 431 } 432 // the prefix matches. try to remove from the left or right branch. 433 left, right := br.left, br.right 434 if zeroBit(kp, br.branching) { 435 left = b.remove(left, k) // k may be in the left branch. 436 } else { 437 right = b.remove(right, k) // k may be in the right branch. 438 } 439 if left == br.left && right == br.right { 440 return br // no update 441 } else if _, ok := left.(*empty); ok { 442 return right // left updated and is empty. 443 } else if _, ok := right.(*empty); ok { 444 return left // right updated and is empty. 445 } 446 // Either left or right updated. Both left and right are not empty. 447 // The left and right branches still share the same prefix and disagree 448 // on the same branching bit. It is safe to directly create the branch. 449 return b.mkBranch(br.prefix, br.branching, left, right) 450 } 451 452 func (b *Builder) intersect(c Collision, l, r node) node { 453 if l == r { 454 return l 455 } 456 switch l := l.(type) { 457 case *empty: 458 return b.empty 459 case *leaf: 460 if rleaf := r.find(l.k); rleaf != nil { 461 return b.collide(c, l, rleaf) 462 } 463 return b.empty 464 case *branch: 465 switch r := r.(type) { 466 case *empty: 467 return b.empty 468 case *leaf: 469 if lleaf := l.find(r.k); lleaf != nil { 470 return b.collide(c, lleaf, r) 471 } 472 return b.empty 473 case *branch: 474 // fallthrough 475 } 476 } 477 // Last remaining case is branch intersection. 478 s, t := l.(*branch), r.(*branch) 479 p, m := s.prefix, s.branching 480 q, n := t.prefix, t.branching 481 482 if m == n && p == q { 483 // prefixes are identical. 484 left, right := b.intersect(c, s.left, t.left), b.intersect(c, s.right, t.right) 485 if _, ok := left.(*empty); ok { 486 return right 487 } else if _, ok := right.(*empty); ok { 488 return left 489 } 490 // The left and right branches are both non-empty. 491 // They still share the same prefix and disagree on the same branching bit. 492 // It is safe to directly create the branch. 493 return b.mkBranch(p, m, left, right) 494 } 495 496 if !prefixesOverlap(p, m, q, n) { 497 return b.empty // The prefixes share no keys. 498 } 499 // prefixesOverlap(p, m, q, n) && !(m ==n && p == q) 500 // By prefixesOverlap(...), either: 501 // ord(m, n) && matchPrefix(q, p, m), or 502 // ord(n, m) && matchPrefix(p, q, n) 503 // So either s or t may be a strict subtree of the other. 504 var lhs, rhs node 505 switch { 506 case ord(m, n) && zeroBit(q, m): 507 lhs, rhs = s.left, t 508 case ord(m, n) && !zeroBit(q, m): 509 lhs, rhs = s.right, t 510 case ord(n, m) && zeroBit(p, n): 511 lhs, rhs = s, t.left 512 default: 513 lhs, rhs = s, t.right 514 } 515 return b.intersect(c, lhs, rhs) 516 }