mirror of
https://github.com/jpeletier/koolnova2mqtt.git
synced 2026-07-16 16:26:57 +00:00
152 lines
3.4 KiB
Go
152 lines
3.4 KiB
Go
package bimap
|
|
|
|
// Package bimap provides a threadsafe bidirectional map
|
|
// original implementation by @vishalkuo: https://github.com/vishalkuo/bimap/
|
|
|
|
import "sync"
|
|
|
|
// BiMap is a bi-directional hashmap that is thread safe and supports immutability
|
|
type BiMap struct {
|
|
s sync.RWMutex
|
|
immutable bool
|
|
forward map[interface{}]interface{}
|
|
inverse map[interface{}]interface{}
|
|
}
|
|
|
|
// New returns a an empty, mutable, biMap
|
|
func New(content map[interface{}]interface{}) *BiMap {
|
|
b := &BiMap{forward: make(map[interface{}]interface{}), inverse: make(map[interface{}]interface{}), immutable: false}
|
|
if content != nil {
|
|
for k, v := range content {
|
|
b.Insert(k, v)
|
|
}
|
|
}
|
|
|
|
return b
|
|
}
|
|
|
|
// Insert puts a key and value into the BiMap, provided its mutable. Also creates the reverse mapping from value to key.
|
|
func (b *BiMap) Insert(k interface{}, v interface{}) {
|
|
b.s.RLock()
|
|
if b.immutable {
|
|
panic("Cannot modify immutable map")
|
|
}
|
|
b.s.RUnlock()
|
|
|
|
b.s.Lock()
|
|
defer b.s.Unlock()
|
|
b.forward[k] = v
|
|
b.inverse[v] = k
|
|
}
|
|
|
|
// Exists checks whether or not a key exists in the BiMap
|
|
func (b *BiMap) Exists(k interface{}) bool {
|
|
b.s.RLock()
|
|
defer b.s.RUnlock()
|
|
_, ok := b.forward[k]
|
|
return ok
|
|
}
|
|
|
|
// ExistsInverse checks whether or not a value exists in the BiMap
|
|
func (b *BiMap) ExistsInverse(k interface{}) bool {
|
|
b.s.RLock()
|
|
defer b.s.RUnlock()
|
|
|
|
_, ok := b.inverse[k]
|
|
return ok
|
|
}
|
|
|
|
// Get returns the value for a given key in the BiMap and whether or not the element was present.
|
|
func (b *BiMap) Get(k interface{}) (interface{}, bool) {
|
|
if !b.Exists(k) {
|
|
return "", false
|
|
}
|
|
b.s.RLock()
|
|
defer b.s.RUnlock()
|
|
return b.forward[k], true
|
|
|
|
}
|
|
|
|
// GetInverse returns the key for a given value in the BiMap and whether or not the element was present.
|
|
func (b *BiMap) GetInverse(v interface{}) (interface{}, bool) {
|
|
if !b.ExistsInverse(v) {
|
|
return "", false
|
|
}
|
|
b.s.RLock()
|
|
defer b.s.RUnlock()
|
|
return b.inverse[v], true
|
|
|
|
}
|
|
|
|
// Delete removes a key-value pair from the BiMap for a given key. Returns if the key doesn't exist
|
|
func (b *BiMap) Delete(k interface{}) {
|
|
b.s.RLock()
|
|
if b.immutable {
|
|
panic("Cannot modify immutable map")
|
|
}
|
|
b.s.RUnlock()
|
|
|
|
if !b.Exists(k) {
|
|
return
|
|
}
|
|
val, _ := b.Get(k)
|
|
b.s.Lock()
|
|
defer b.s.Unlock()
|
|
delete(b.forward, k)
|
|
delete(b.inverse, val)
|
|
}
|
|
|
|
// DeleteInverse emoves a key-value pair from the BiMap for a given value. Returns if the value doesn't exist
|
|
func (b *BiMap) DeleteInverse(v interface{}) {
|
|
b.s.RLock()
|
|
if b.immutable {
|
|
panic("Cannot modify immutable map")
|
|
}
|
|
b.s.RUnlock()
|
|
|
|
if !b.ExistsInverse(v) {
|
|
return
|
|
}
|
|
|
|
key, _ := b.GetInverse(v)
|
|
b.s.Lock()
|
|
defer b.s.Unlock()
|
|
delete(b.inverse, v)
|
|
delete(b.forward, key)
|
|
|
|
}
|
|
|
|
// Size returns the number of elements in the bimap
|
|
func (b *BiMap) Size() int {
|
|
b.s.RLock()
|
|
defer b.s.RUnlock()
|
|
return len(b.forward)
|
|
}
|
|
|
|
// MakeImmutable freezes the BiMap preventing any further write actions from taking place
|
|
func (b *BiMap) MakeImmutable() {
|
|
b.s.Lock()
|
|
defer b.s.Unlock()
|
|
b.immutable = true
|
|
}
|
|
|
|
// GetInverseMap returns a regular go map mapping from the BiMap's values to its keys
|
|
func (b *BiMap) GetInverseMap() map[interface{}]interface{} {
|
|
return b.inverse
|
|
}
|
|
|
|
// GetForwardMap returns a regular go map mapping from the BiMap's keys to its values
|
|
func (b *BiMap) GetForwardMap() map[interface{}]interface{} {
|
|
return b.forward
|
|
}
|
|
|
|
// Lock manually locks the BiMap's mutex
|
|
func (b *BiMap) Lock() {
|
|
b.s.Lock()
|
|
}
|
|
|
|
// Unlock manually unlocks the BiMap's mutex
|
|
func (b *BiMap) Unlock() {
|
|
b.s.Unlock()
|
|
}
|