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, } }