summaryrefslogtreecommitdiff
path: root/libgo/go/sync/map_reference_test.go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-09-14 17:11:35 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-09-14 17:11:35 +0000
commite104cab8d4ab9422a0ca55bb24c00c9fea9a5d4d (patch)
tree8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/sync/map_reference_test.go
parent4a85c0b16ef3722655012f596b7e3e7e272eeb56 (diff)
downloadgcc-e104cab8d4ab9422a0ca55bb24c00c9fea9a5d4d.tar.gz
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@252767 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/sync/map_reference_test.go')
-rw-r--r--libgo/go/sync/map_reference_test.go151
1 files changed, 151 insertions, 0 deletions
diff --git a/libgo/go/sync/map_reference_test.go b/libgo/go/sync/map_reference_test.go
new file mode 100644
index 00000000000..9f27b07c329
--- /dev/null
+++ b/libgo/go/sync/map_reference_test.go
@@ -0,0 +1,151 @@
+// 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
+}