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.Go(func() {
20 s.inner = load()
21 })
22 return s
23}
24
25// Seq returns an iterator that yields elements from the slice.
26func (s *LazySlice[K]) Seq() iter.Seq[K] {
27 s.wg.Wait()
28 return func(yield func(K) bool) {
29 for _, v := range s.inner {
30 if !yield(v) {
31 return
32 }
33 }
34 }
35}
36
37// Slice is a thread-safe slice implementation that provides concurrent access.
38type Slice[T any] struct {
39 inner []T
40 mu sync.RWMutex
41}
42
43// NewSlice creates a new thread-safe slice.
44func NewSlice[T any]() *Slice[T] {
45 return &Slice[T]{
46 inner: make([]T, 0),
47 }
48}
49
50// NewSliceFrom creates a new thread-safe slice from an existing slice.
51func NewSliceFrom[T any](s []T) *Slice[T] {
52 inner := make([]T, len(s))
53 copy(inner, s)
54 return &Slice[T]{
55 inner: inner,
56 }
57}
58
59// Append adds an element to the end of the slice.
60func (s *Slice[T]) Append(items ...T) {
61 s.mu.Lock()
62 defer s.mu.Unlock()
63 s.inner = append(s.inner, items...)
64}
65
66// Prepend adds an element to the beginning of the slice.
67func (s *Slice[T]) Prepend(item T) {
68 s.mu.Lock()
69 defer s.mu.Unlock()
70 s.inner = append([]T{item}, s.inner...)
71}
72
73// Delete removes the element at the specified index.
74func (s *Slice[T]) Delete(index int) bool {
75 s.mu.Lock()
76 defer s.mu.Unlock()
77 if index < 0 || index >= len(s.inner) {
78 return false
79 }
80 s.inner = slices.Delete(s.inner, index, index+1)
81 return true
82}
83
84// Get returns the element at the specified index.
85func (s *Slice[T]) Get(index int) (T, bool) {
86 s.mu.RLock()
87 defer s.mu.RUnlock()
88 var zero T
89 if index < 0 || index >= len(s.inner) {
90 return zero, false
91 }
92 return s.inner[index], true
93}
94
95// Set updates the element at the specified index.
96func (s *Slice[T]) Set(index int, item T) bool {
97 s.mu.Lock()
98 defer s.mu.Unlock()
99 if index < 0 || index >= len(s.inner) {
100 return false
101 }
102 s.inner[index] = item
103 return true
104}
105
106// Len returns the number of elements in the slice.
107func (s *Slice[T]) Len() int {
108 s.mu.RLock()
109 defer s.mu.RUnlock()
110 return len(s.inner)
111}
112
113// SetSlice replaces the entire slice with a new one.
114func (s *Slice[T]) SetSlice(items []T) {
115 s.mu.Lock()
116 defer s.mu.Unlock()
117 s.inner = make([]T, len(items))
118 copy(s.inner, items)
119}
120
121// Seq returns an iterator that yields elements from the slice.
122func (s *Slice[T]) Seq() iter.Seq[T] {
123 return func(yield func(T) bool) {
124 for _, v := range s.Seq2() {
125 if !yield(v) {
126 return
127 }
128 }
129 }
130}
131
132// Seq2 returns an iterator that yields index-value pairs from the slice.
133func (s *Slice[T]) Seq2() iter.Seq2[int, T] {
134 s.mu.RLock()
135 items := make([]T, len(s.inner))
136 copy(items, s.inner)
137 s.mu.RUnlock()
138 return func(yield func(int, T) bool) {
139 for i, v := range items {
140 if !yield(i, v) {
141 return
142 }
143 }
144 }
145}