Source file src/cmd/compile/internal/types2/trie.go
1 // Copyright 2026 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 types2 6 7 import "sort" 8 9 // A trie[V] maps keys to values V, similar to a map. 10 // A key is a list of integers; two keys collide if one of them is a prefix of the other. 11 // For instance, [1, 2] and [1, 2, 3] collide, but [1, 2, 3] and [1, 2, 4] do not. 12 // If all keys have length 1, a trie degenerates into an ordinary map[int]V. 13 type trie[V any] map[int]any // map value is either trie[V] (non-leaf node), or V (leaf node) 14 15 // insert inserts a value with a key into the trie; key must not be empty. 16 // If key doesn't collide with any other key in the trie, insert succeeds 17 // and returns (val, 0). Otherwise, insert fails and returns (alt, n) where 18 // alt is an unspecified but deterministically chosen value with a colliding 19 // key and n is the length > 0 of the common key prefix. The trie is not 20 // changed in this case. 21 func (tr trie[V]) insert(key []int, val V) (V, int) { 22 // A key serves as the path from the trie root to its corresponding value. 23 for l, index := range key { 24 if v, exists := tr[index]; exists { 25 // An entry already exists for this index; check its type to determine collision. 26 switch v := v.(type) { 27 case trie[V]: 28 // Path continues. 29 // Must check this case first in case V is any which would act as catch-all. 30 tr = v 31 case V: 32 // Collision: An existing key ends here. 33 // This means the existing key is a prefix of (or exactly equal to) key. 34 return v, l + 1 35 case nil: 36 // Handle esoteric case where V is any and val is nil. 37 var zero V 38 return zero, l + 1 39 default: 40 panic("trie.insert: invalid entry") 41 } 42 } else { 43 // Path doesn't exist yet, we need to build it. 44 if l == len(key)-1 { 45 // No prefix collision detected; insert val as a new leaf node. 46 tr[index] = val 47 return val, 0 48 } 49 node := make(trie[V]) 50 tr[index] = node 51 tr = node 52 } 53 } 54 55 if len(key) == 0 { 56 panic("trie.insert: key must not be empty") 57 } 58 59 // Collision: path ends here, but the trie continues. 60 // This means key is a prefix of an existing key. 61 // Return a value from the subtrie. 62 for len(tr) != 0 { 63 // see switch above 64 switch v := tr.pickValue().(type) { 65 case trie[V]: 66 tr = v 67 case V: 68 return v, len(key) 69 case nil: 70 var zero V 71 return zero, len(key) 72 default: 73 panic("trie.insert: invalid entry") 74 } 75 } 76 77 panic("trie.insert: unreachable") 78 } 79 80 // pickValue deterministically picks a value of the trie and returns it. 81 // Only called in case of a collision. 82 // The trie must not be empty. 83 func (tr trie[V]) pickValue() any { 84 var keys []int 85 for k := range tr { 86 keys = append(keys, k) 87 } 88 sort.Ints(keys) // guarantee deterministic element pick 89 return tr[keys[0]] 90 } 91