slices.go

  1package csync
  2
  3import (
  4	"iter"
  5	"slices"
  6	"sync"
  7)
  8
  9// LazySlice is a thread-safe lazy-loaded slice.
 10type LazySlice[K any] struct {
 11	inner []K
 12	wg    sync.WaitGroup
 13}
 14
 15// NewLazySlice creates a new slice and runs the [load] function in a goroutine
 16// to populate it.
 17func NewLazySlice[K any](load func() []K) *LazySlice[K] {
 18	s := &LazySlice[K]{}
 19	s.wg.Add(1)
 20	go func() {
 21		s.inner = load()
 22		s.wg.Done()
 23	}()
 24	return s
 25}
 26
 27// Seq returns an iterator that yields elements from the slice.
 28func (s *LazySlice[K]) Seq() iter.Seq[K] {
 29	s.wg.Wait()
 30	return func(yield func(K) bool) {
 31		for _, v := range s.inner {
 32			if !yield(v) {
 33				return
 34			}
 35		}
 36	}
 37}
 38
 39func (s *LazySlice[K]) Seq2() iter.Seq2[int, K] {
 40	s.wg.Wait()
 41	return func(yield func(int, K) bool) {
 42		for i, v := range s.inner {
 43			if !yield(i, v) {
 44				return
 45			}
 46		}
 47	}
 48}
 49
 50func (s *LazySlice[K]) Set(index int, item K) bool {
 51	s.wg.Wait()
 52	if index < 0 || index >= len(s.inner) {
 53		return false
 54	}
 55	s.inner[index] = item
 56	return true
 57}
 58
 59func (s *LazySlice[K]) Append(item K) bool {
 60	s.wg.Wait()
 61	s.inner = append(s.inner, item)
 62	return true
 63}
 64
 65// Slice is a thread-safe slice implementation that provides concurrent access.
 66type Slice[T any] struct {
 67	inner []T
 68	mu    sync.RWMutex
 69}
 70
 71// NewSlice creates a new thread-safe slice.
 72func NewSlice[T any]() *Slice[T] {
 73	return &Slice[T]{
 74		inner: make([]T, 0),
 75	}
 76}
 77
 78// NewSliceFrom creates a new thread-safe slice from an existing slice.
 79func NewSliceFrom[T any](s []T) *Slice[T] {
 80	inner := make([]T, len(s))
 81	copy(inner, s)
 82	return &Slice[T]{
 83		inner: inner,
 84	}
 85}
 86
 87// Append adds an element to the end of the slice.
 88func (s *Slice[T]) Append(items ...T) {
 89	s.mu.Lock()
 90	defer s.mu.Unlock()
 91	s.inner = append(s.inner, items...)
 92}
 93
 94// Prepend adds an element to the beginning of the slice.
 95func (s *Slice[T]) Prepend(item T) {
 96	s.mu.Lock()
 97	defer s.mu.Unlock()
 98	s.inner = append([]T{item}, s.inner...)
 99}
100
101// Delete removes the element at the specified index.
102func (s *Slice[T]) Delete(index int) bool {
103	s.mu.Lock()
104	defer s.mu.Unlock()
105	if index < 0 || index >= len(s.inner) {
106		return false
107	}
108	s.inner = slices.Delete(s.inner, index, index+1)
109	return true
110}
111
112// Get returns the element at the specified index.
113func (s *Slice[T]) Get(index int) (T, bool) {
114	s.mu.RLock()
115	defer s.mu.RUnlock()
116	var zero T
117	if index < 0 || index >= len(s.inner) {
118		return zero, false
119	}
120	return s.inner[index], true
121}
122
123// Set updates the element at the specified index.
124func (s *Slice[T]) Set(index int, item T) bool {
125	s.mu.Lock()
126	defer s.mu.Unlock()
127	if index < 0 || index >= len(s.inner) {
128		return false
129	}
130	s.inner[index] = item
131	return true
132}
133
134// Len returns the number of elements in the slice.
135func (s *Slice[T]) Len() int {
136	s.mu.RLock()
137	defer s.mu.RUnlock()
138	return len(s.inner)
139}
140
141// Slice returns a copy of the underlying slice.
142func (s *Slice[T]) Slice() []T {
143	s.mu.RLock()
144	defer s.mu.RUnlock()
145	result := make([]T, len(s.inner))
146	copy(result, s.inner)
147	return result
148}
149
150// SetSlice replaces the entire slice with a new one.
151func (s *Slice[T]) SetSlice(items []T) {
152	s.mu.Lock()
153	defer s.mu.Unlock()
154	s.inner = make([]T, len(items))
155	copy(s.inner, items)
156}
157
158// Clear removes all elements from the slice.
159func (s *Slice[T]) Clear() {
160	s.mu.Lock()
161	defer s.mu.Unlock()
162	s.inner = s.inner[:0]
163}
164
165// Seq returns an iterator that yields elements from the slice.
166func (s *Slice[T]) Seq() iter.Seq[T] {
167	return func(yield func(T) bool) {
168		for _, v := range s.Seq2() {
169			if !yield(v) {
170				return
171			}
172		}
173	}
174}
175
176// Seq2 returns an iterator that yields index-value pairs from the slice.
177func (s *Slice[T]) Seq2() iter.Seq2[int, T] {
178	s.mu.RLock()
179	items := make([]T, len(s.inner))
180	copy(items, s.inner)
181	s.mu.RUnlock()
182	return func(yield func(int, T) bool) {
183		for i, v := range items {
184			if !yield(i, v) {
185				return
186			}
187		}
188	}
189}