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