on 94de6bc help sign in
crush/internal/csync/slices.go
145 lines 3.0 kB history raw
1package csync
3import (
4 "iter"
5 "slices"
6 "sync"
7)
9// LazySlice is a thread-safe lazy-loaded slice.
10type LazySlice[K any] struct {
11 inner []K
12 wg sync.WaitGroup
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
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 }
37// Slice is a thread-safe slice implementation that provides concurrent access.
38type Slice[T any] struct {
39 inner []T
40 mu sync.RWMutex
43// NewSlice creates a new thread-safe slice.
44func NewSlice[T any]() *Slice[T] {
45 return &Slice[T]{
46 inner: make([]T, 0),
47 }
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 }
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...)
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...)
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
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
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
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)
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)
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 }
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 }