1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-16 11:54:29 +00:00
arikawa/internal/moreatomic/syncmap.go
diamondburned c6679dc52c State: Separate Store into smaller interfaces, Cabinet API
This commit refactors the Store interface in State into smaller
interfaces in package store. These interfaces are combined into one
structure called a "Cabinet". The default implementation of those
interfaces have been rewritten in package defaultstore, while the old
no-op implementation stays with the store package.

This commit also omitted several state handlers for user events, as it
is unclear what they are actually structured like.
2020-11-29 16:57:58 -08:00

62 lines
1.2 KiB
Go

package moreatomic
import (
"sync"
"sync/atomic"
)
// Map is a thread-safe map that is a wrapper around sync.Map with slight API
// additions.
type Map struct {
smap atomic.Value
ctor func() interface{}
}
type sentinelType struct{}
var sentinel = sentinelType{}
func NewMap(ctor func() interface{}) *Map {
smap := atomic.Value{}
smap.Store(&sync.Map{})
return &Map{smap, ctor}
}
// Reset swaps the internal map out with a fresh one, dropping the old map. This
// method never errors.
func (sm *Map) Reset() error {
sm.smap.Store(&sync.Map{})
return nil
}
// LoadOrStore loads an existing value or stores a new value created from the
// given constructor then return that value.
func (sm *Map) LoadOrStore(k interface{}) (v interface{}, loaded bool) {
smap := sm.smap.Load().(*sync.Map)
v, loaded = smap.LoadOrStore(k, sentinel)
if loaded {
v = sm.ctor()
smap.Store(k, v)
}
return
}
// Load loads an existing value; it returns ok set to false if there is no
// value with that key.
func (sm *Map) Load(k interface{}) (lv interface{}, ok bool) {
smap := sm.smap.Load().(*sync.Map)
for {
lv, ok = smap.Load(k)
if !ok {
return nil, false
}
if lv != sentinel {
return lv, true
}
}
}