github.com/djordje200179/extendedlibrary/datastructures@v1.7.1-0.20240227175559-d09520a92dd4/cols/synccol/wrapper.go (about) 1 package synccol 2 3 import ( 4 "github.com/djordje200179/extendedlibrary/datastructures/cols" 5 "github.com/djordje200179/extendedlibrary/datastructures/iter" 6 "github.com/djordje200179/extendedlibrary/misc/functions/comparison" 7 "github.com/djordje200179/extendedlibrary/misc/functions/predication" 8 "sync" 9 ) 10 11 // Wrapper is a wrapper around a cols.Collection that provides thread-safe access. 12 // Locking is done through read-write mutex. This means that multiple goroutines 13 // can read at the same time, but only one goroutine can write at the same time. 14 type Wrapper[T any] struct { 15 collection cols.Collection[T] 16 17 mutex sync.RWMutex 18 } 19 20 // From creates a new Wrapper around the given cols.Collection. 21 func From[T any](collection cols.Collection[T]) *Wrapper[T] { 22 return &Wrapper[T]{collection, sync.RWMutex{}} 23 } 24 25 // Size returns the number of elements. 26 func (w *Wrapper[T]) Size() int { 27 w.mutex.RLock() 28 defer w.mutex.RUnlock() 29 30 return w.collection.Size() 31 } 32 33 // Get returns the element at the given index. 34 func (w *Wrapper[T]) Get(index int) T { 35 w.mutex.RLock() 36 defer w.mutex.RUnlock() 37 38 return w.collection.Get(index) 39 } 40 41 // GetRef returns a reference to the element at the given index. 42 // Usage of this method is discouraged, as it breaks the thread-safety. 43 // Lock will not be held while the reference is used, so it is possible 44 // that the value of the element changes while the reference is used. 45 func (w *Wrapper[T]) GetRef(index int) *T { 46 w.mutex.RLock() 47 defer w.mutex.RUnlock() 48 49 return w.collection.GetRef(index) 50 } 51 52 // Set sets the value of the element at the given index. 53 func (w *Wrapper[T]) Set(index int, value T) { 54 w.mutex.Lock() 55 defer w.mutex.Unlock() 56 57 w.collection.Set(index, value) 58 } 59 60 // Update calculates and sets the new value of the element at the given index. 61 func (w *Wrapper[T]) Update(index int, updateFunction func(value T) T) { 62 w.mutex.Lock() 63 defer w.mutex.Unlock() 64 65 oldValue := w.collection.Get(index) 66 newValue := updateFunction(oldValue) 67 w.collection.Set(index, newValue) 68 } 69 70 // UpdateRef in-place updates the value of the element at the given index. 71 func (w *Wrapper[T]) UpdateRef(index int, updateFunction func(value *T)) { 72 w.mutex.Lock() 73 defer w.mutex.Unlock() 74 75 oldValue := w.collection.GetRef(index) 76 updateFunction(oldValue) 77 } 78 79 // Prepend prepends the given value to the collection. 80 func (w *Wrapper[T]) Prepend(value T) { 81 w.mutex.Lock() 82 defer w.mutex.Unlock() 83 84 w.collection.Prepend(value) 85 } 86 87 // Append appends the given value to the collection. 88 func (w *Wrapper[T]) Append(value T) { 89 w.mutex.Lock() 90 defer w.mutex.Unlock() 91 92 w.collection.Append(value) 93 } 94 95 // Insert inserts the given value at the given index. 96 func (w *Wrapper[T]) Insert(index int, value T) { 97 w.mutex.Lock() 98 defer w.mutex.Unlock() 99 100 w.collection.Insert(index, value) 101 } 102 103 // Remove removes the element at the given index. 104 func (w *Wrapper[T]) Remove(index int) { 105 w.mutex.Lock() 106 defer w.mutex.Unlock() 107 108 w.collection.Remove(index) 109 } 110 111 // Clear clears the collection. 112 func (w *Wrapper[T]) Clear() { 113 w.mutex.Lock() 114 defer w.mutex.Unlock() 115 116 w.collection.Clear() 117 } 118 119 // Reverse reverses the collection. 120 func (w *Wrapper[T]) Reverse() { 121 w.mutex.Lock() 122 defer w.mutex.Unlock() 123 124 w.collection.Reverse() 125 } 126 127 // Sort sorts the elements using the given comparator. 128 func (w *Wrapper[T]) Sort(comparator comparison.Comparator[T]) { 129 w.mutex.Lock() 130 defer w.mutex.Unlock() 131 132 w.collection.Sort(comparator) 133 } 134 135 // Join joins the collection with the given collection. 136 func (w *Wrapper[T]) Join(other cols.Collection[T]) { 137 w.mutex.Lock() 138 defer w.mutex.Unlock() 139 140 w.collection.Join(other) 141 } 142 143 // Clone returns a copy of a Wrapper with the new 144 // underlying collection that is also cloned. 145 func (w *Wrapper[T]) Clone() cols.Collection[T] { 146 w.mutex.RLock() 147 defer w.mutex.RUnlock() 148 149 clonedCollection := w.collection.Clone() 150 return &Wrapper[T]{clonedCollection, sync.RWMutex{}} 151 } 152 153 // Iterator returns an iter.Iterator over the elements. 154 func (w *Wrapper[T]) Iterator() iter.Iterator[T] { 155 return w.CollectionIterator() 156 } 157 158 // CollectionIterator returns a cols.Iterator over the elements. 159 func (w *Wrapper[T]) CollectionIterator() cols.Iterator[T] { 160 return Iterator[T]{w.collection.CollectionIterator(), &w.mutex} 161 } 162 163 // Stream streams the elements of the collection. 164 func (w *Wrapper[T]) Stream(yield func(T) bool) { 165 w.mutex.RLock() 166 defer w.mutex.RUnlock() 167 168 w.collection.Stream(yield) 169 } 170 171 // RefsStream streams the references to the elements of the collection. 172 func (w *Wrapper[T]) RefsStream(yield func(*T) bool) { 173 w.mutex.Lock() 174 defer w.mutex.Unlock() 175 176 w.collection.RefsStream(yield) 177 } 178 179 // FindIndex returns the index of the first element that satisfies the given predicate. 180 // If no element satisfies the predicate, 0 and false are returned. 181 func (w *Wrapper[T]) FindIndex(predicate predication.Predicate[T]) (int, bool) { 182 w.mutex.RLock() 183 defer w.mutex.RUnlock() 184 185 return w.collection.FindIndex(predicate) 186 } 187 188 // FindRef returns a reference to the first element that satisfies the given predicate. 189 // If no element satisfies the predicate, nil and false are returned. 190 // Lock will not be held while the reference is used, so it is possible 191 // that the value of the element changes while the reference is used. 192 func (w *Wrapper[T]) FindRef(predicate predication.Predicate[T]) (*T, bool) { 193 w.mutex.RLock() 194 defer w.mutex.RUnlock() 195 196 return w.collection.FindRef(predicate) 197 } 198 199 // Transaction executes the given function with the cols.Collection as an argument. 200 // Wrapped cols.Collection will be locked for writing while the function is executed. 201 func (w *Wrapper[T]) Transaction(updateFunction func(collection cols.Collection[T])) { 202 w.mutex.Lock() 203 defer w.mutex.Unlock() 204 205 updateFunction(w.collection) 206 }