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}