Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

152 рядки
3.4 KiB

  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package syncmap_test
  5. import (
  6. "sync"
  7. "sync/atomic"
  8. )
  9. // This file contains reference map implementations for unit-tests.
  10. // mapInterface is the interface Map implements.
  11. type mapInterface interface {
  12. Load(interface{}) (interface{}, bool)
  13. Store(key, value interface{})
  14. LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
  15. Delete(interface{})
  16. Range(func(key, value interface{}) (shouldContinue bool))
  17. }
  18. // RWMutexMap is an implementation of mapInterface using a sync.RWMutex.
  19. type RWMutexMap struct {
  20. mu sync.RWMutex
  21. dirty map[interface{}]interface{}
  22. }
  23. func (m *RWMutexMap) Load(key interface{}) (value interface{}, ok bool) {
  24. m.mu.RLock()
  25. value, ok = m.dirty[key]
  26. m.mu.RUnlock()
  27. return
  28. }
  29. func (m *RWMutexMap) Store(key, value interface{}) {
  30. m.mu.Lock()
  31. if m.dirty == nil {
  32. m.dirty = make(map[interface{}]interface{})
  33. }
  34. m.dirty[key] = value
  35. m.mu.Unlock()
  36. }
  37. func (m *RWMutexMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
  38. m.mu.Lock()
  39. actual, loaded = m.dirty[key]
  40. if !loaded {
  41. actual = value
  42. if m.dirty == nil {
  43. m.dirty = make(map[interface{}]interface{})
  44. }
  45. m.dirty[key] = value
  46. }
  47. m.mu.Unlock()
  48. return actual, loaded
  49. }
  50. func (m *RWMutexMap) Delete(key interface{}) {
  51. m.mu.Lock()
  52. delete(m.dirty, key)
  53. m.mu.Unlock()
  54. }
  55. func (m *RWMutexMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
  56. m.mu.RLock()
  57. keys := make([]interface{}, 0, len(m.dirty))
  58. for k := range m.dirty {
  59. keys = append(keys, k)
  60. }
  61. m.mu.RUnlock()
  62. for _, k := range keys {
  63. v, ok := m.Load(k)
  64. if !ok {
  65. continue
  66. }
  67. if !f(k, v) {
  68. break
  69. }
  70. }
  71. }
  72. // DeepCopyMap is an implementation of mapInterface using a Mutex and
  73. // atomic.Value. It makes deep copies of the map on every write to avoid
  74. // acquiring the Mutex in Load.
  75. type DeepCopyMap struct {
  76. mu sync.Mutex
  77. clean atomic.Value
  78. }
  79. func (m *DeepCopyMap) Load(key interface{}) (value interface{}, ok bool) {
  80. clean, _ := m.clean.Load().(map[interface{}]interface{})
  81. value, ok = clean[key]
  82. return value, ok
  83. }
  84. func (m *DeepCopyMap) Store(key, value interface{}) {
  85. m.mu.Lock()
  86. dirty := m.dirty()
  87. dirty[key] = value
  88. m.clean.Store(dirty)
  89. m.mu.Unlock()
  90. }
  91. func (m *DeepCopyMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
  92. clean, _ := m.clean.Load().(map[interface{}]interface{})
  93. actual, loaded = clean[key]
  94. if loaded {
  95. return actual, loaded
  96. }
  97. m.mu.Lock()
  98. // Reload clean in case it changed while we were waiting on m.mu.
  99. clean, _ = m.clean.Load().(map[interface{}]interface{})
  100. actual, loaded = clean[key]
  101. if !loaded {
  102. dirty := m.dirty()
  103. dirty[key] = value
  104. actual = value
  105. m.clean.Store(dirty)
  106. }
  107. m.mu.Unlock()
  108. return actual, loaded
  109. }
  110. func (m *DeepCopyMap) Delete(key interface{}) {
  111. m.mu.Lock()
  112. dirty := m.dirty()
  113. delete(dirty, key)
  114. m.clean.Store(dirty)
  115. m.mu.Unlock()
  116. }
  117. func (m *DeepCopyMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
  118. clean, _ := m.clean.Load().(map[interface{}]interface{})
  119. for k, v := range clean {
  120. if !f(k, v) {
  121. break
  122. }
  123. }
  124. }
  125. func (m *DeepCopyMap) dirty() map[interface{}]interface{} {
  126. clean, _ := m.clean.Load().(map[interface{}]interface{})
  127. dirty := make(map[interface{}]interface{}, len(clean)+1)
  128. for k, v := range clean {
  129. dirty[k] = v
  130. }
  131. return dirty
  132. }