diff options
Diffstat (limited to 'src/gnunet/util/map.go')
-rw-r--r-- | src/gnunet/util/map.go | 151 |
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 | |||
19 | package util | ||
20 | |||
21 | import ( | ||
22 | "math/rand" | ||
23 | "sync" | ||
24 | ) | ||
25 | |||
26 | //---------------------------------------------------------------------- | ||
27 | // Thread-safe map implementation | ||
28 | //---------------------------------------------------------------------- | ||
29 | |||
30 | // Map keys to values | ||
31 | type 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. | ||
39 | func 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. | ||
50 | func (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. | ||
64 | func (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. | ||
84 | func (m *Map[K, V]) Size() int { | ||
85 | return len(m.list) | ||
86 | } | ||
87 | |||
88 | // Put value into map under given key. | ||
89 | func (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. | ||
96 | func (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. | ||
104 | func (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. | ||
123 | func (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) | ||
132 | func (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) | ||
143 | func (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 | } | ||