aboutsummaryrefslogtreecommitdiff
path: root/src/gnunet/util/map.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnunet/util/map.go')
-rw-r--r--src/gnunet/util/map.go151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/gnunet/util/map.go b/src/gnunet/util/map.go
new file mode 100644
index 0000000..adfcc0e
--- /dev/null
+++ b/src/gnunet/util/map.go
@@ -0,0 +1,151 @@
1// This file is part of gnunet-go, a GNUnet-implementation in Golang.
2// Copyright (C) 2019-2022 Bernd Fix >Y<
3//
4// gnunet-go is free software: you can redistribute it and/or modify it
5// under the terms of the GNU Affero General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// gnunet-go is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//
17// SPDX-License-Identifier: AGPL3.0-or-later
18
19package util
20
21import (
22 "math/rand"
23 "sync"
24)
25
26//----------------------------------------------------------------------
27// Thread-safe map implementation
28//----------------------------------------------------------------------
29
30// Map keys to values
31type Map[K comparable, V any] struct {
32 sync.RWMutex
33
34 list map[K]V
35 inProcess bool
36}
37
38// NewMap allocates a new mapping.
39func NewMap[K comparable, V any]() *Map[K, V] {
40 return &Map[K, V]{
41 list: make(map[K]V),
42 inProcess: false,
43 }
44}
45
46//----------------------------------------------------------------------
47
48// Process a function in the locked map context. Calls
49// to other map functions in 'f' will skip their locks.
50func (m *Map[K, V]) Process(f func() error, readonly bool) error {
51 // handle locking
52 m.lock(readonly)
53 m.inProcess = true
54 defer func() {
55 m.inProcess = false
56 m.unlock(readonly)
57 }()
58 // function call in unlocked environment
59 return f()
60}
61
62// Process a ranged function in the locked map context. Calls
63// to other map functions in 'f' will skip their locks.
64func (m *Map[K, V]) ProcessRange(f func(key K, value V) error, readonly bool) error {
65 // handle locking
66 m.lock(readonly)
67 m.inProcess = true
68 defer func() {
69 m.inProcess = false
70 m.unlock(readonly)
71 }()
72 // range over map and call function.
73 for key, value := range m.list {
74 if err := f(key, value); err != nil {
75 return err
76 }
77 }
78 return nil
79}
80
81//----------------------------------------------------------------------
82
83// Size returns the number of entries in the map.
84func (m *Map[K, V]) Size() int {
85 return len(m.list)
86}
87
88// Put value into map under given key.
89func (m *Map[K, V]) Put(key K, value V) {
90 m.lock(false)
91 defer m.unlock(false)
92 m.list[key] = value
93}
94
95// Get value with iven key from map.
96func (m *Map[K, V]) Get(key K) (value V, ok bool) {
97 m.lock(true)
98 defer m.unlock(true)
99 value, ok = m.list[key]
100 return
101}
102
103// GetRandom returns a random map entry.
104func (m *Map[K, V]) GetRandom() (key K, value V, ok bool) {
105 m.lock(true)
106 defer m.unlock(true)
107
108 ok = false
109 if size := m.Size(); size > 0 {
110 idx := rand.Intn(size)
111 for key, value = range m.list {
112 if idx == 0 {
113 ok = true
114 return
115 }
116 idx--
117 }
118 }
119 return
120}
121
122// Delete key/value pair from map.
123func (m *Map[K, V]) Delete(key K) {
124 m.lock(false)
125 defer m.unlock(false)
126 delete(m.list, key)
127}
128
129//----------------------------------------------------------------------
130
131// lock with given mode (if not in processing function)
132func (m *Map[K, V]) lock(readonly bool) {
133 if !m.inProcess {
134 if readonly {
135 m.RLock()
136 } else {
137 m.Lock()
138 }
139 }
140}
141
142// lock with given mode (if not in processing function)
143func (m *Map[K, V]) unlock(readonly bool) {
144 if !m.inProcess {
145 if readonly {
146 m.RUnlock()
147 } else {
148 m.Unlock()
149 }
150 }
151}