|  | // Copyright 2016 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package sync_test | 
|  |  | 
|  | import ( | 
|  | "sync" | 
|  | "sync/atomic" | 
|  | ) | 
|  |  | 
|  | // This file contains reference map implementations for unit-tests. | 
|  |  | 
|  | // 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) | 
|  | Delete(interface{}) | 
|  | Range(func(key, value interface{}) (shouldContinue bool)) | 
|  | } | 
|  |  | 
|  | // 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) 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 | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // DeepCopyMap is an implementation of mapInterface using a Mutex and | 
|  | // atomic.Value.  It makes deep copies of the map on every write to avoid | 
|  | // acquiring the Mutex in Load. | 
|  | type DeepCopyMap struct { | 
|  | mu    sync.Mutex | 
|  | clean atomic.Value | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) Load(key interface{}) (value interface{}, ok bool) { | 
|  | clean, _ := m.clean.Load().(map[interface{}]interface{}) | 
|  | value, ok = clean[key] | 
|  | return value, ok | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) Store(key, value interface{}) { | 
|  | m.mu.Lock() | 
|  | dirty := m.dirty() | 
|  | dirty[key] = value | 
|  | m.clean.Store(dirty) | 
|  | m.mu.Unlock() | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { | 
|  | clean, _ := m.clean.Load().(map[interface{}]interface{}) | 
|  | actual, loaded = clean[key] | 
|  | if loaded { | 
|  | return actual, loaded | 
|  | } | 
|  |  | 
|  | m.mu.Lock() | 
|  | // Reload clean in case it changed while we were waiting on m.mu. | 
|  | clean, _ = m.clean.Load().(map[interface{}]interface{}) | 
|  | actual, loaded = clean[key] | 
|  | if !loaded { | 
|  | dirty := m.dirty() | 
|  | dirty[key] = value | 
|  | actual = value | 
|  | m.clean.Store(dirty) | 
|  | } | 
|  | m.mu.Unlock() | 
|  | return actual, loaded | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) Delete(key interface{}) { | 
|  | m.mu.Lock() | 
|  | dirty := m.dirty() | 
|  | delete(dirty, key) | 
|  | m.clean.Store(dirty) | 
|  | m.mu.Unlock() | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) Range(f func(key, value interface{}) (shouldContinue bool)) { | 
|  | clean, _ := m.clean.Load().(map[interface{}]interface{}) | 
|  | for k, v := range clean { | 
|  | if !f(k, v) { | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *DeepCopyMap) dirty() map[interface{}]interface{} { | 
|  | clean, _ := m.clean.Load().(map[interface{}]interface{}) | 
|  | dirty := make(map[interface{}]interface{}, len(clean)+1) | 
|  | for k, v := range clean { | 
|  | dirty[k] = v | 
|  | } | 
|  | return dirty | 
|  | } |