github.com/mitranim/gg@v0.1.17/sync.go (about)

     1  package gg
     2  
     3  import (
     4  	"sync"
     5  	"sync/atomic"
     6  )
     7  
     8  /*
     9  Shortcut for mutexes. Usage:
    10  
    11  	defer Lock(someLock).Unlock()
    12  */
    13  func Lock[A sync.Locker](val A) A {
    14  	val.Lock()
    15  	return val
    16  }
    17  
    18  /*
    19  Shortcut for dereferencing a pointer under a lock. Uses `PtrGet`, returning the
    20  zero value of the given type if the pointer is nil.
    21  */
    22  func LockGet[Lock sync.Locker, Val any](lock Lock, ptr *Val) (_ Val) {
    23  	if ptr == nil {
    24  		return
    25  	}
    26  	defer Lock(lock).Unlock()
    27  	return *ptr
    28  }
    29  
    30  // Shortcut for writing to a pointer under a lock.
    31  func LockSet[Lock sync.Locker, Val any](lock Lock, ptr *Val, val Val) {
    32  	if ptr == nil {
    33  		return
    34  	}
    35  	defer Lock(lock).Unlock()
    36  	*ptr = val
    37  }
    38  
    39  /*
    40  Typed version of `atomic.Value`. Currently implemented as a typedef of
    41  `atomic.Value` where the value is internally stored as `any`. Converting
    42  non-interface values to `any` may automatically create a copy on the heap.
    43  Values other than booleans and machine numbers should be stored by pointer to
    44  minimize copying. This may change in the future.
    45  */
    46  type Atom[A any] atomic.Value
    47  
    48  /*
    49  Like `.Load` but returns true if anything was previously stored, and false if
    50  nothing was previously stored.
    51  */
    52  func (self *Atom[A]) Loaded() (A, bool) {
    53  	val := (*atomic.Value)(self).Load()
    54  	return AnyAs[A](val), val != nil
    55  }
    56  
    57  // Typed version of `atomic.Value.Load`.
    58  func (self *Atom[A]) Load() A {
    59  	return AnyAs[A]((*atomic.Value)(self).Load())
    60  }
    61  
    62  // Typed version of `atomic.Value.Store`.
    63  func (self *Atom[A]) Store(val A) {
    64  	(*atomic.Value)(self).Store(val)
    65  }
    66  
    67  // Typed version of `atomic.Value.Swap`.
    68  func (self *Atom[A]) Swap(val A) A {
    69  	return AnyAs[A]((*atomic.Value)(self).Swap(val))
    70  }
    71  
    72  // Typed version of `atomic.Value.CompareAndSwap`.
    73  func (self *Atom[A]) CompareAndSwap(prev, next A) bool {
    74  	return (*atomic.Value)(self).CompareAndSwap(prev, next)
    75  }
    76  
    77  /*
    78  Typed version of `sync.Map`. Currently implemented as a typedef of `sync.Map`
    79  where both keys and valus are internally stored as `any`. Converting
    80  non-interface values to `any` may automatically create a copy on the heap.
    81  Values other than booleans and machine numbers should be stored by pointer to
    82  minimize copying. This may change in the future.
    83  */
    84  type SyncMap[Key comparable, Val any] sync.Map
    85  
    86  // Typed version of `sync.Map.Load`.
    87  func (self *SyncMap[Key, Val]) Load(key Key) (Val, bool) {
    88  	iface, ok := (*sync.Map)(self).Load(key)
    89  	return AnyAs[Val](iface), ok
    90  }
    91  
    92  // Typed version of `sync.Map.LoadOrStore`.
    93  func (self *SyncMap[Key, Val]) LoadOrStore(key Key, val Val) (Val, bool) {
    94  	iface, ok := (*sync.Map)(self).LoadOrStore(key, val)
    95  	return AnyAs[Val](iface), ok
    96  }
    97  
    98  // Typed version of `sync.Map.LoadAndDelete`.
    99  func (self *SyncMap[Key, Val]) LoadAndDelete(key Key) (Val, bool) {
   100  	iface, ok := (*sync.Map)(self).LoadAndDelete(key)
   101  	return AnyAs[Val](iface), ok
   102  }
   103  
   104  // Typed version of `sync.Map.Store`.
   105  func (self *SyncMap[Key, Val]) Store(key Key, val Val) Val {
   106  	(*sync.Map)(self).Store(key, val)
   107  	return val
   108  }
   109  
   110  // Typed version of `sync.Map.Delete`.
   111  func (self *SyncMap[Key, Val]) Delete(key Key) {
   112  	(*sync.Map)(self).Delete(key)
   113  }
   114  
   115  // Typed version of `sync.Map.Range`.
   116  func (self *SyncMap[Key, Val]) Range(fun func(Key, Val) bool) {
   117  	if fun == nil {
   118  		return
   119  	}
   120  	(*sync.Map)(self).Range(func(key, val any) bool {
   121  		return fun(key.(Key), val.(Val))
   122  	})
   123  }
   124  
   125  // Alias of `chan` with additional convenience methods.
   126  type Chan[A any] chan A
   127  
   128  // Closes the channel unless it's nil.
   129  func (self Chan[_]) Close() {
   130  	if self != nil {
   131  		close(self)
   132  	}
   133  }
   134  
   135  // Same as global `ChanInit`.
   136  func (self *Chan[A]) Init() Chan[A] { return ChanInit(self) }
   137  
   138  /*
   139  Idempotently initializes the channel. If the pointer is non-nil and the channel
   140  is nil, creates a new unbuffered channel and assigns it to the pointer. Returns
   141  the resulting channel.
   142  */
   143  func ChanInit[Tar ~chan Val, Val any](ptr *Tar) Tar {
   144  	if ptr == nil {
   145  		return nil
   146  	}
   147  	if *ptr == nil {
   148  		*ptr = make(Tar)
   149  	}
   150  	return *ptr
   151  }
   152  
   153  // Same as global `ChanInitCap`.
   154  func (self *Chan[A]) InitCap(cap int) Chan[A] { return ChanInitCap(self, cap) }
   155  
   156  /*
   157  Idempotently initializes the channel. If the pointer is non-nil and the channel
   158  is nil, creates a new buffered channel with the given capacity and assigns it
   159  to the pointer. Returns the resulting channel.
   160  */
   161  func ChanInitCap[Tar ~chan Val, Val any](ptr *Tar, cap int) Tar {
   162  	if ptr == nil {
   163  		return nil
   164  	}
   165  	if *ptr == nil {
   166  		*ptr = make(Tar, cap)
   167  	}
   168  	return *ptr
   169  }
   170  
   171  // Same as global `SendOpt`.
   172  func (self Chan[A]) SendOpt(val A) { SendOpt(self, val) }
   173  
   174  // Shortcut for sending a value over a channel in a non-blocking fashion.
   175  func SendOpt[Tar ~chan Val, Val any](tar Tar, val Val) {
   176  	select {
   177  	case tar <- val:
   178  	default:
   179  	}
   180  }
   181  
   182  // Same as global `SendZeroOpt`.
   183  func (self Chan[A]) SendZeroOpt() { SendZeroOpt(self) }
   184  
   185  // Shortcut for sending a zero value over a channel in a non-blocking fashion.
   186  func SendZeroOpt[Tar ~chan Val, Val any](tar Tar) {
   187  	select {
   188  	case tar <- Zero[Val]():
   189  	default:
   190  	}
   191  }