1package csync
2
3import (
4 "iter"
5 "sync"
6)
7
8// LazySlice is a thread-safe lazy-loaded slice.
9type LazySlice[K any] struct {
10 inner []K
11 wg sync.WaitGroup
12}
13
14// NewLazySlice creates a new slice and runs the [load] function in a goroutine
15// to populate it.
16func NewLazySlice[K any](load func() []K) *LazySlice[K] {
17 s := &LazySlice[K]{}
18 s.wg.Go(func() {
19 s.inner = load()
20 })
21 return s
22}
23
24// Seq returns an iterator that yields elements from the slice.
25func (s *LazySlice[K]) Seq() iter.Seq[K] {
26 s.wg.Wait()
27 return func(yield func(K) bool) {
28 for _, v := range s.inner {
29 if !yield(v) {
30 return
31 }
32 }
33 }
34}
35
36// Slice is a thread-safe slice implementation that provides concurrent access.
37type Slice[T any] struct {
38 inner []T
39 mu sync.RWMutex
40}
41
42// NewSlice creates a new thread-safe slice.
43func NewSlice[T any]() *Slice[T] {
44 return &Slice[T]{
45 inner: make([]T, 0),
46 }
47}
48
49// NewSliceFrom creates a new thread-safe slice from an existing slice.
50func NewSliceFrom[T any](s []T) *Slice[T] {
51 inner := make([]T, len(s))
52 copy(inner, s)
53 return &Slice[T]{
54 inner: inner,
55 }
56}
57
58// Append adds an element to the end of the slice.
59func (s *Slice[T]) Append(items ...T) {
60 s.mu.Lock()
61 defer s.mu.Unlock()
62 s.inner = append(s.inner, items...)
63}
64
65// Get returns the element at the specified index.
66func (s *Slice[T]) Get(index int) (T, bool) {
67 s.mu.RLock()
68 defer s.mu.RUnlock()
69 var zero T
70 if index < 0 || index >= len(s.inner) {
71 return zero, false
72 }
73 return s.inner[index], true
74}
75
76// Len returns the number of elements in the slice.
77func (s *Slice[T]) Len() int {
78 s.mu.RLock()
79 defer s.mu.RUnlock()
80 return len(s.inner)
81}
82
83// SetSlice replaces the entire slice with a new one.
84func (s *Slice[T]) SetSlice(items []T) {
85 s.mu.Lock()
86 defer s.mu.Unlock()
87 s.inner = make([]T, len(items))
88 copy(s.inner, items)
89}
90
91// Seq returns an iterator that yields elements from the slice.
92func (s *Slice[T]) Seq() iter.Seq[T] {
93 return func(yield func(T) bool) {
94 for _, v := range s.Seq2() {
95 if !yield(v) {
96 return
97 }
98 }
99 }
100}
101
102// Seq2 returns an iterator that yields index-value pairs from the slice.
103func (s *Slice[T]) Seq2() iter.Seq2[int, T] {
104 items := s.Copy()
105 return func(yield func(int, T) bool) {
106 for i, v := range items {
107 if !yield(i, v) {
108 return
109 }
110 }
111 }
112}
113
114// Copy returns a copy of the inner slice.
115func (s *Slice[T]) Copy() []T {
116 s.mu.RLock()
117 defer s.mu.RUnlock()
118 items := make([]T, len(s.inner))
119 copy(items, s.inner)
120 return items
121}