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 | ||
|  | } |