import (
"sync/atomic"
- "unsafe"
)
// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
// expunged is an arbitrary pointer that marks entries which have been deleted
// from the dirty map.
-var expunged = unsafe.Pointer(new(any))
+var expunged = new(any)
// An entry is a slot in the map corresponding to a particular key.
type entry struct {
// p != expunged. If p == expunged, an entry's associated value can be updated
// only after first setting m.dirty[key] = e so that lookups using the dirty
// map find the entry.
- p unsafe.Pointer // *interface{}
+ p atomic.Pointer[any]
}
func newEntry(i any) *entry {
- return &entry{p: unsafe.Pointer(&i)}
+ e := &entry{}
+ e.p.Store(&i)
+ return e
}
func (m *Map) loadReadOnly() readOnly {
}
func (e *entry) load() (value any, ok bool) {
- p := atomic.LoadPointer(&e.p)
+ p := e.p.Load()
if p == nil || p == expunged {
return nil, false
}
- return *(*any)(p), true
+ return *p, true
}
// Store sets the value for a key.
// unchanged.
func (e *entry) tryStore(i *any) bool {
for {
- p := atomic.LoadPointer(&e.p)
+ p := e.p.Load()
if p == expunged {
return false
}
- if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
+ if e.p.CompareAndSwap(p, i) {
return true
}
}
// If the entry was previously expunged, it must be added to the dirty map
// before m.mu is unlocked.
func (e *entry) unexpungeLocked() (wasExpunged bool) {
- return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
+ return e.p.CompareAndSwap(expunged, nil)
}
// storeLocked unconditionally stores a value to the entry.
//
// The entry must be known not to be expunged.
func (e *entry) storeLocked(i *any) {
- atomic.StorePointer(&e.p, unsafe.Pointer(i))
+ e.p.Store(i)
}
// LoadOrStore returns the existing value for the key if present.
// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
// returns with ok==false.
func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) {
- p := atomic.LoadPointer(&e.p)
+ p := e.p.Load()
if p == expunged {
return nil, false, false
}
if p != nil {
- return *(*any)(p), true, true
+ return *p, true, true
}
// Copy the interface after the first load to make this method more amenable
// shouldn't bother heap-allocating.
ic := i
for {
- if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
+ if e.p.CompareAndSwap(nil, &ic) {
return i, false, true
}
- p = atomic.LoadPointer(&e.p)
+ p = e.p.Load()
if p == expunged {
return nil, false, false
}
if p != nil {
- return *(*any)(p), true, true
+ return *p, true, true
}
}
}
func (e *entry) delete() (value any, ok bool) {
for {
- p := atomic.LoadPointer(&e.p)
+ p := e.p.Load()
if p == nil || p == expunged {
return nil, false
}
- if atomic.CompareAndSwapPointer(&e.p, p, nil) {
- return *(*any)(p), true
+ if e.p.CompareAndSwap(p, nil) {
+ return *p, true
}
}
}
}
func (e *entry) tryExpungeLocked() (isExpunged bool) {
- p := atomic.LoadPointer(&e.p)
+ p := e.p.Load()
for p == nil {
- if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
+ if e.p.CompareAndSwap(nil, expunged) {
return true
}
- p = atomic.LoadPointer(&e.p)
+ p = e.p.Load()
}
return p == expunged
}