github.com/jd-ly/tools@v0.5.7/go/ssa/interp/map.go (about) 1 // Copyright 2013 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 interp 6 7 // Custom hashtable atop map. 8 // For use when the key's equivalence relation is not consistent with ==. 9 10 // The Go specification doesn't address the atomicity of map operations. 11 // The FAQ states that an implementation is permitted to crash on 12 // concurrent map access. 13 14 import ( 15 "go/types" 16 ) 17 18 type hashable interface { 19 hash(t types.Type) int 20 eq(t types.Type, x interface{}) bool 21 } 22 23 type entry struct { 24 key hashable 25 value value 26 next *entry 27 } 28 29 // A hashtable atop the built-in map. Since each bucket contains 30 // exactly one hash value, there's no need to perform hash-equality 31 // tests when walking the linked list. Rehashing is done by the 32 // underlying map. 33 type hashmap struct { 34 keyType types.Type 35 table map[int]*entry 36 length int // number of entries in map 37 } 38 39 // makeMap returns an empty initialized map of key type kt, 40 // preallocating space for reserve elements. 41 func makeMap(kt types.Type, reserve int) value { 42 if usesBuiltinMap(kt) { 43 return make(map[value]value, reserve) 44 } 45 return &hashmap{keyType: kt, table: make(map[int]*entry, reserve)} 46 } 47 48 // delete removes the association for key k, if any. 49 func (m *hashmap) delete(k hashable) { 50 if m != nil { 51 hash := k.hash(m.keyType) 52 head := m.table[hash] 53 if head != nil { 54 if k.eq(m.keyType, head.key) { 55 m.table[hash] = head.next 56 m.length-- 57 return 58 } 59 prev := head 60 for e := head.next; e != nil; e = e.next { 61 if k.eq(m.keyType, e.key) { 62 prev.next = e.next 63 m.length-- 64 return 65 } 66 prev = e 67 } 68 } 69 } 70 } 71 72 // lookup returns the value associated with key k, if present, or 73 // value(nil) otherwise. 74 func (m *hashmap) lookup(k hashable) value { 75 if m != nil { 76 hash := k.hash(m.keyType) 77 for e := m.table[hash]; e != nil; e = e.next { 78 if k.eq(m.keyType, e.key) { 79 return e.value 80 } 81 } 82 } 83 return nil 84 } 85 86 // insert updates the map to associate key k with value v. If there 87 // was already an association for an eq() (though not necessarily ==) 88 // k, the previous key remains in the map and its associated value is 89 // updated. 90 func (m *hashmap) insert(k hashable, v value) { 91 hash := k.hash(m.keyType) 92 head := m.table[hash] 93 for e := head; e != nil; e = e.next { 94 if k.eq(m.keyType, e.key) { 95 e.value = v 96 return 97 } 98 } 99 m.table[hash] = &entry{ 100 key: k, 101 value: v, 102 next: head, 103 } 104 m.length++ 105 } 106 107 // len returns the number of key/value associations in the map. 108 func (m *hashmap) len() int { 109 if m != nil { 110 return m.length 111 } 112 return 0 113 } 114 115 // entries returns a rangeable map of entries. 116 func (m *hashmap) entries() map[int]*entry { 117 if m != nil { 118 return m.table 119 } 120 return nil 121 }