120 lines
2.1 KiB
Go
120 lines
2.1 KiB
Go
|
package concurrent
|
|||
|
|
|||
|
import (
|
|||
|
"sync"
|
|||
|
|
|||
|
. "gitea.zaclys.com/bvaudour/gob/option"
|
|||
|
)
|
|||
|
|
|||
|
// Map fournit une solution pour ajouter des éléments dans un map de façon concurrente.
|
|||
|
type Map[K comparable, V any] struct {
|
|||
|
data map[K]V
|
|||
|
mtx sync.Mutex
|
|||
|
closed bool
|
|||
|
}
|
|||
|
|
|||
|
func (m *Map[K, V]) checkOpened() {
|
|||
|
if m.closed {
|
|||
|
panic("The map cannot be modified anymore.")
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (m *Map[K, V]) checkClosed() {
|
|||
|
if !m.closed {
|
|||
|
panic("The Map needs to be opened.")
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (m *Map[K, V]) changeState(closed bool) {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
m.closed = closed
|
|||
|
}
|
|||
|
|
|||
|
func (m *Map[K, V]) get() (out map[K]V) {
|
|||
|
out = make(map[K]V)
|
|||
|
for k, v := range m.data {
|
|||
|
out[k] = v
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Clear vide le map.
|
|||
|
// Cette méthode nécessite que le map soit ouvert.
|
|||
|
func (m *Map[K, V]) Clear() {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
m.checkOpened()
|
|||
|
clear(m.data)
|
|||
|
}
|
|||
|
|
|||
|
// Close empêche les modifications du map.
|
|||
|
func (m *Map[K, V]) Close() {
|
|||
|
m.changeState(true)
|
|||
|
}
|
|||
|
|
|||
|
// Open permet les modifications du map.
|
|||
|
func (m *Map[K, V]) Open() {
|
|||
|
m.changeState(false)
|
|||
|
}
|
|||
|
|
|||
|
// Set associe la clé et la valeur données dans le map.
|
|||
|
// Cette méthode nécessite que le map soit ouvert.
|
|||
|
func (m *Map[K, V]) Set(key K, value V) {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
m.checkOpened()
|
|||
|
m.data[key] = value
|
|||
|
}
|
|||
|
|
|||
|
// Get retourne la valeur du map à la clé donnée.
|
|||
|
func (m *Map[K, V]) Get(key K) (value Option[V]) {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
if v, ok := m.data[key]; ok {
|
|||
|
value = Some(v)
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Data retourne le map.
|
|||
|
// Cette méthode nécessite que le map soit fermé.
|
|||
|
func (m *Map[K, V]) Data() map[K]V {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
m.checkClosed()
|
|||
|
|
|||
|
return m.get()
|
|||
|
}
|
|||
|
|
|||
|
// CloseData retourne le map après l’avoir préalablement fermé en écriture.
|
|||
|
func (m *Map[K, V]) CloseData() map[K]V {
|
|||
|
m.mtx.Lock()
|
|||
|
defer m.mtx.Unlock()
|
|||
|
|
|||
|
m.closed = true
|
|||
|
|
|||
|
return m.get()
|
|||
|
}
|
|||
|
|
|||
|
// NewMap retourne un map initialisé avec les valeurs fournies.
|
|||
|
func NewMap[K comparable, V any](elems ...map[K]V) *Map[K, V] {
|
|||
|
out := make(map[K]V)
|
|||
|
for _, m := range elems {
|
|||
|
for k, v := range m {
|
|||
|
out[k] = v
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return &Map[K, V]{
|
|||
|
data: out,
|
|||
|
}
|
|||
|
}
|