143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// 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 syncmap_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()
							 | 
						||
| 
								 | 
							
									defer m.mu.RUnlock()
							 | 
						||
| 
								 | 
							
									for k, v := range m.dirty {
							 | 
						||
| 
								 | 
							
										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
							 | 
						||
| 
								 | 
							
								}
							 |