Skip to content

Instantly share code, notes, and snippets.

@CAFxX
Last active July 19, 2023 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CAFxX/00401f29fb64bd74dc9812b741db9df8 to your computer and use it in GitHub Desktop.
Save CAFxX/00401f29fb64bd74dc9812b741db9df8 to your computer and use it in GitHub Desktop.
package maps
type ReadMostlyMap[K comparable, V any] struct {
mu sync.Mutex
m atomic.Pointer // map[K]V
}
func map2ptr[K comparable, V any](m map[K]V) unsafe.Pointer {
im := any(m)
return *(*unsafe.Pointer)(unsafe.Pointer(&im))
}
func ptr2map[K comparable, V any](ptr unsafe.Pointer) map[K]V {
return *(*map[K]V)(ptr)
}
func (m *ReadMostlyMap[K, V]) loadMap() map[K]V {
return ptr2map(m.m.Load())
}
func (m *ReadMostlyMap[K, V]) storeMap(cm map[K]V) {
m.m.Store(map2ptr(cm))
}
func (m *ReadMostlyMap[K, V]) Get(key K) (value V, ok bool) {
cm := m.loadMap()
if cm != nil {
value, ok = cm[key]
}
return
}
func (m *ReadMostlyMap[K, V]) Set(key K, value V) {
m.update(func(m map[K]V) map[K]V {
if m[key] == value {
return nil
}
m = clone(m)
m[key] = value
return m
})
}
func (m *ReadMostlyMap[K, V]) Delete(key K) {
m.update(func(m map[K]V) map[K]V {
if _, exists := m[key]; !exists {
return nil
}
m = clone(m)
delete(m, key)
return m
})
}
func clone[K comparable, V any](m map[K]V) map[K]V {
if m == nil {
return make(map[K]V)
}
return maps.Clone(m)
}
func (m *ReadMostlyMap[K, V]) Clear() {
m.update(func(m map[K]V) map[K]V {
if len(m) == 0 {
return nil
}
return make(map[K]V)
})
}
func (m *ReadMostlyMap[K, V]) Update(f func(map[K]V)) {
m.mu.Lock()
defer m.mu.Unlock()
cm := m.loadMap()
nm := clone(cm)
f(nm)
m.storeMap(nm)
}
func (m *ReadMostlyMap[K, V]) update(f func(map[K]V) map[K]V) {
m.mu.Lock()
defer m.mu.Unlock()
cm := m.loadMap()
nm := f(cm)
if nm != nil {
m.storeMap(nm)
}
}
func (m *ReadMostlyMap[K, V]) Len() int {
cm := m.loadMap()
return len(cm)
}
func (m *ReadMostlyMap[K, V]) All(yield func(K, V) bool) bool {
cm := m.loadMap()
for k, v := range cm {
if !yield(k, v) {
return false
}
}
return true
}
func (m *ReadMostlyMap[K, V]) AllKeys(yield func(K) bool) bool {
return m.All(func(k K, _ V) bool {
return yield(k)
})
}
func (m *ReadMostlyMap[K, V]) AllValues(yield func(V) bool) bool {
return m.All(func(_ K, v V) bool {
return yield(v)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment