github.com/MetalBlockchain/metalgo@v1.11.9/utils/bimap/bimap.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package bimap 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "errors" 10 11 "golang.org/x/exp/maps" 12 13 "github.com/MetalBlockchain/metalgo/utils" 14 ) 15 16 var ( 17 _ json.Marshaler = (*BiMap[int, int])(nil) 18 _ json.Unmarshaler = (*BiMap[int, int])(nil) 19 20 nullBytes = []byte("null") 21 errNotBijective = errors.New("map not bijective") 22 ) 23 24 type Entry[K, V any] struct { 25 Key K 26 Value V 27 } 28 29 // BiMap is a bi-directional map. 30 type BiMap[K, V comparable] struct { 31 keyToValue map[K]V 32 valueToKey map[V]K 33 } 34 35 // New creates a new empty bimap. 36 func New[K, V comparable]() *BiMap[K, V] { 37 return &BiMap[K, V]{ 38 keyToValue: make(map[K]V), 39 valueToKey: make(map[V]K), 40 } 41 } 42 43 // Put the key value pair into the map. If either [key] or [val] was previously 44 // in the map, the previous entries will be removed and returned. 45 // 46 // Note: Unlike normal maps, it's possible that Put removes 0, 1, or 2 existing 47 // entries to ensure that mappings are one-to-one. 48 func (m *BiMap[K, V]) Put(key K, val V) []Entry[K, V] { 49 var removed []Entry[K, V] 50 oldVal, oldValDeleted := m.DeleteKey(key) 51 if oldValDeleted { 52 removed = append(removed, Entry[K, V]{ 53 Key: key, 54 Value: oldVal, 55 }) 56 } 57 oldKey, oldKeyDeleted := m.DeleteValue(val) 58 if oldKeyDeleted { 59 removed = append(removed, Entry[K, V]{ 60 Key: oldKey, 61 Value: val, 62 }) 63 } 64 m.keyToValue[key] = val 65 m.valueToKey[val] = key 66 return removed 67 } 68 69 // GetKey that maps to the provided value. 70 func (m *BiMap[K, V]) GetKey(val V) (K, bool) { 71 key, ok := m.valueToKey[val] 72 return key, ok 73 } 74 75 // GetValue that is mapped to the provided key. 76 func (m *BiMap[K, V]) GetValue(key K) (V, bool) { 77 val, ok := m.keyToValue[key] 78 return val, ok 79 } 80 81 // HasKey returns true if [key] is in the map. 82 func (m *BiMap[K, _]) HasKey(key K) bool { 83 _, ok := m.keyToValue[key] 84 return ok 85 } 86 87 // HasValue returns true if [val] is in the map. 88 func (m *BiMap[_, V]) HasValue(val V) bool { 89 _, ok := m.valueToKey[val] 90 return ok 91 } 92 93 // DeleteKey removes [key] from the map and returns the value it mapped to. 94 func (m *BiMap[K, V]) DeleteKey(key K) (V, bool) { 95 val, ok := m.keyToValue[key] 96 if !ok { 97 return utils.Zero[V](), false 98 } 99 delete(m.keyToValue, key) 100 delete(m.valueToKey, val) 101 return val, true 102 } 103 104 // DeleteValue removes [val] from the map and returns the key that mapped to it. 105 func (m *BiMap[K, V]) DeleteValue(val V) (K, bool) { 106 key, ok := m.valueToKey[val] 107 if !ok { 108 return utils.Zero[K](), false 109 } 110 delete(m.keyToValue, key) 111 delete(m.valueToKey, val) 112 return key, true 113 } 114 115 // Keys returns the keys of the map. The keys will be in an indeterminate order. 116 func (m *BiMap[K, _]) Keys() []K { 117 return maps.Keys(m.keyToValue) 118 } 119 120 // Values returns the values of the map. The values will be in an indeterminate 121 // order. 122 func (m *BiMap[_, V]) Values() []V { 123 return maps.Values(m.keyToValue) 124 } 125 126 // Len return the number of entries in this map. 127 func (m *BiMap[K, V]) Len() int { 128 return len(m.keyToValue) 129 } 130 131 func (m *BiMap[K, V]) MarshalJSON() ([]byte, error) { 132 return json.Marshal(m.keyToValue) 133 } 134 135 func (m *BiMap[K, V]) UnmarshalJSON(b []byte) error { 136 if bytes.Equal(b, nullBytes) { 137 return nil 138 } 139 var keyToValue map[K]V 140 if err := json.Unmarshal(b, &keyToValue); err != nil { 141 return err 142 } 143 valueToKey := make(map[V]K, len(keyToValue)) 144 for k, v := range keyToValue { 145 valueToKey[v] = k 146 } 147 if len(keyToValue) != len(valueToKey) { 148 return errNotBijective 149 } 150 151 m.keyToValue = keyToValue 152 m.valueToKey = valueToKey 153 return nil 154 }