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  }