package util import ( "sync" ) // https://sreramk.medium.com/go-inside-sync-map-how-does-sync-map-work-internally-97e87b8e6bf // RWMutexMap is an implementation of mapInterface using a sync.RWMutex. type RWMutexMap struct { mu sync.RWMutex dirty map[interface{}]interface{} } func (m *RWMutexMap) Load(key interface{}) (value interface{}, ok bool) { m.mu.RLock() value, ok = m.dirty[key] m.mu.RUnlock() return } func (m *RWMutexMap) Store(key, value interface{}) { m.mu.Lock() if m.dirty == nil { m.dirty = make(map[interface{}]interface{}) } m.dirty[key] = value m.mu.Unlock() } func (m *RWMutexMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { m.mu.Lock() actual, loaded = m.dirty[key] if !loaded { actual = value if m.dirty == nil { m.dirty = make(map[interface{}]interface{}) } m.dirty[key] = value } m.mu.Unlock() return actual, loaded } func (m *RWMutexMap) LoadAndDelete(key interface{}) (value interface{}, loaded bool) { m.mu.Lock() value, loaded = m.dirty[key] if !loaded { m.mu.Unlock() return nil, false } delete(m.dirty, key) m.mu.Unlock() return value, loaded } func (m *RWMutexMap) Delete(key interface{}) { m.mu.Lock() delete(m.dirty, key) m.mu.Unlock() } func (m *RWMutexMap) Range(f func(key, value interface{}) (shouldContinue bool)) { m.mu.RLock() keys := make([]interface{}, 0, len(m.dirty)) for k := range m.dirty { keys = append(keys, k) } m.mu.RUnlock() for _, k := range keys { v, ok := m.Load(k) if !ok { continue } if !f(k, v) { break } } } // MapInterface is the interface Map implements. type MapInterface interface { Load(interface{}) (interface{}, bool) Store(key, value interface{}) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) LoadAndDelete(key interface{}) (value interface{}, loaded bool) Delete(interface{}) Range(func(key, value interface{}) (shouldContinue bool)) } func NewRWMutexMap() MapInterface { return &RWMutexMap{} }