139 lines
2.7 KiB
Go
139 lines
2.7 KiB
Go
|
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,
|
|||
|
}
|
|||
|
}
|