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