package cmap import "sync" // Map represents a map safe for concurrent use type Map[K comparable, V any] struct { mutex sync.RWMutex data map[K]V } // New creates a new generic Map func New[K comparable, V any]() *Map[K, V] { return &Map[K, V]{data: map[K]V{}} } // Put puts the key-value pair into m func (m *Map[K, V]) Put(key K, value V) { m.mutex.Lock() defer m.mutex.Unlock() m.data[key] = value } // GetHas returns the corresponding value for the given key in m // as well as a bool indicating if a value was present at all func (m *Map[K, V]) GetHas(key K) (V, bool) { m.mutex.RLock() defer m.mutex.RUnlock() value, ok := m.data[key] return value, ok } // Get returns the corresponding value for the given key in m func (m *Map[K, V]) Get(key K) V { value, _ := m.GetHas(key) return value } // Has returns a bool indicating if a value was present for the given key func (m *Map[K, V]) Has(key K) bool { _, ok := m.GetHas(key) return ok } // Delete deletes the key-value pair from m func (m *Map[K, V]) Delete(key K) { m.mutex.Lock() defer m.mutex.Unlock() delete(m.data, key) } // Count returns the amount of key-value pairs currently stored in m func (m *Map[K, V]) Count() int { m.mutex.RLock() defer m.mutex.RUnlock() return len(m.data) } // Iter calls f for every key-value pair stored in m. // Be aware that this locks m for write access // as pointer types could be modified in f func (m *Map[K, V]) Iter(f func(key K, value V)) { m.mutex.Lock() defer m.mutex.Unlock() for key, value := range m.data { f(key, value) } } // Keys returns a slice containing all currently stored keys in m. // Pointer values are returned as they were received func (m *Map[K, V]) Keys() []K { m.mutex.RLock() defer m.mutex.RUnlock() keys := make([]K, 0, len(m.data)) for key := range m.data { keys = append(keys, key) } return keys } // Values returns a slice containing all currently stored values in m. // Pointer values are returned as they were received func (m *Map[K, V]) Values() []V { m.mutex.RLock() defer m.mutex.RUnlock() values := make([]V, 0, len(m.data)) for _, value := range m.data { values = append(values, value) } return values } // Do calls f with the underlying primitive map. // Be aware that this locks m for write access // so Do can be used for reading as well as modifiying m. func (m *Map[K, V]) Do(f func(m map[K]V)) { m.mutex.Lock() defer m.mutex.Unlock() f(m.data) } // DoWithError calls f with the underlying primitive map and returns its error. // Be aware that this locks m for write access // so Do can be used for reading as well as modifiying m. func (m *Map[K, V]) DoWithError(f func(m map[K]V) error) error { m.mutex.Lock() defer m.mutex.Unlock() return f(m.data) } // Clone returns a copy of the underlying map data func (m *Map[K, V]) Clone() map[K]V { m.mutex.RLock() defer m.mutex.RUnlock() c := map[K]V{} for key, value := range m.data { c[key] = value } return c }