diff --git a/collection/concurrent/map.go b/collection/concurrent/map.go new file mode 100644 index 0000000..6cb6d10 --- /dev/null +++ b/collection/concurrent/map.go @@ -0,0 +1,119 @@ +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, + } +} diff --git a/collection/concurrent/slice.go b/collection/concurrent/slice.go new file mode 100644 index 0000000..a155346 --- /dev/null +++ b/collection/concurrent/slice.go @@ -0,0 +1,138 @@ +package concurrent + +import ( + "sync" + + . "gitea.zaclys.com/bvaudour/gob/option" +) + +// Slice fournit une solution pour ajouter des éléments dans un slice de façon concurrente. +type Slice[T any] struct { + data []T + mtx sync.Mutex + closed bool +} + +func (sl *Slice[T]) checkOpened() { + if sl.closed { + panic("The slice cannot be modified anymore.") + } +} + +func (sl *Slice[T]) checkClosed() { + if !sl.closed { + panic("The slice needs to be opened.") + } +} + +func (sl *Slice[T]) changeState(closed bool) { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.closed = closed +} + +func (sl *Slice[T]) get() (out []T) { + out = make([]T, len(sl.data)) + copy(out, sl.data) + + return +} + +func (sl *Slice[T]) checkIdx(i int) bool { + return i >= 0 && i < len(sl.data) +} + +// Insert ajoute les entrées fournies en début de slice. +// Cette méthode nécessite que le slice soit ouvert. +func (sl *Slice[T]) Insert(elems ...T) { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.checkOpened() + sl.data = append(elems, sl.data...) +} + +// Insert ajoute les entrées fournies en fin de slice. +// Cette méthode nécessite que le slice soit ouvert. +func (sl *Slice[T]) Append(elems ...T) { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.checkOpened() + sl.data = append(sl.data, elems...) +} + +// Clear vide le slice. +// Cette méthode nécessite que le slice soit ouvert. +func (sl *Slice[T]) Clear() { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.checkOpened() + sl.data = []T{} +} + +// Close empêche les modifications du slice. +func (sl *Slice[T]) Close() { + sl.changeState(true) +} + +// Open permet les modifications du slice. +func (sl *Slice[T]) Open() { + sl.changeState(false) +} + +// Set modifie l’entrée du slice à l’index donné et retourne vrai si l’entrée a été modifiée. +// Cette méthode nécessite que le slice soit ouvert. +func (sl *Slice[T]) Set(index int, value T) (ok bool) { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.checkOpened() + if ok = sl.checkIdx(index); ok { + sl.data[index] = value + } + + return +} + +// Get retourne la valeur du slice à l’index donné. +func (sl *Slice[T]) Get(index int) (value Option[T]) { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + if sl.checkIdx(index) { + value = Some(sl.data[index]) + } + + return +} + +// Data retourne le slice. +// Cette méthode nécessite que le slice soit fermé. +func (sl *Slice[T]) Data() []T { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.checkClosed() + + return sl.get() +} + +// CloseData retourne le slice après l’avoir préalablement fermé en écriture. +func (sl *Slice[T]) CloseData() []T { + sl.mtx.Lock() + defer sl.mtx.Unlock() + + sl.closed = true + + return sl.get() +} + +// NewSlice retourne un slice initialisé avec les valeurs fournies. +func NewSlice[T any](elems ...T) *Slice[T] { + return &Slice[T]{ + data: elems, + } +} diff --git a/test/main.go b/test/main.go new file mode 100644 index 0000000..fdc951c --- /dev/null +++ b/test/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "fmt" +) + +func main() { + a := []int{1, 2, 3} + fmt.Println(a) + clear(a) + fmt.Println(a) +} diff --git a/test/test b/test/test new file mode 100755 index 0000000..919e7c5 Binary files /dev/null and b/test/test differ