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

     1  package gg
     2  
     3  import (
     4  	r "reflect"
     5  	"sync"
     6  )
     7  
     8  // Type-inferring shortcut for creating a `Cache` of the given type.
     9  func CacheOf[
    10  	Key comparable,
    11  	Val any,
    12  	Ptr Initer1Ptr[Val, Key],
    13  ]() *Cache[Key, Val, Ptr] {
    14  	return new(Cache[Key, Val, Ptr])
    15  }
    16  
    17  // Concurrency-safe cache. See the method reference.
    18  type Cache[
    19  	Key comparable,
    20  	Val any,
    21  	Ptr Initer1Ptr[Val, Key],
    22  ] struct {
    23  	Map  map[Key]Ptr
    24  	Lock sync.RWMutex
    25  }
    26  
    27  /*
    28  Shortcut for using `.Ptr` and dereferencing the result. May be invalid if the
    29  resulting value is non-copyable, for example when it contains a mutex.
    30  */
    31  func (self *Cache[Key, Val, Ptr]) Get(key Key) Val { return *self.Ptr(key) }
    32  
    33  /*
    34  Returns the cached value for the given key. If the value did not previously
    35  exist, idempotently initializes it by calling `.Init` (by pointer) and caches
    36  the result. For any given key, the value is initialized exactly once, even if
    37  multiple goroutines are trying to access it simultaneously.
    38  */
    39  func (self *Cache[Key, Val, Ptr]) Ptr(key Key) Ptr {
    40  	ptr := self.get(key)
    41  	if ptr != nil {
    42  		return ptr
    43  	}
    44  
    45  	defer Lock(&self.Lock).Unlock()
    46  
    47  	ptr = self.Map[key]
    48  	if ptr != nil {
    49  		return ptr
    50  	}
    51  
    52  	ptr = new(Val)
    53  	ptr.Init(key)
    54  	MapInit(&self.Map)[key] = ptr
    55  	return ptr
    56  }
    57  
    58  func (self *Cache[Key, _, Ptr]) get(key Key) Ptr {
    59  	defer Lock(self.Lock.RLocker()).Unlock()
    60  	return self.Map[key]
    61  }
    62  
    63  // Deletes the value for the given key.
    64  func (self *Cache[Key, _, _]) Del(key Key) {
    65  	defer Lock(&self.Lock).Unlock()
    66  	delete(self.Map, key)
    67  }
    68  
    69  // Type-inferring shortcut for creating a `TypeCache` of the given type.
    70  func TypeCacheOf[Val any, Ptr Initer1Ptr[Val, r.Type]]() *TypeCache[Val, Ptr] {
    71  	return new(TypeCache[Val, Ptr])
    72  }
    73  
    74  /*
    75  Tool for storing information derived from `reflect.Type` that can be generated
    76  once and then cached. Used internally. All methods are concurrency-safe.
    77  */
    78  type TypeCache[Val any, Ptr Initer1Ptr[Val, r.Type]] struct {
    79  	Map  map[r.Type]Ptr
    80  	Lock sync.RWMutex
    81  }
    82  
    83  /*
    84  Shortcut for using `.Ptr` and dereferencing the result. May be invalid if the
    85  resulting value is non-copyable, for example when it contains a mutex.
    86  */
    87  func (self *TypeCache[Val, Ptr]) Get(key r.Type) Val { return *self.Ptr(key) }
    88  
    89  /*
    90  Returns the cached value for the given key. If the value did not previously
    91  exist, idempotently initializes it by calling `.Init` (by pointer) and caches
    92  the result. For any given key, the value is initialized exactly once, even if
    93  multiple goroutines are trying to access it simultaneously.
    94  */
    95  func (self *TypeCache[Val, Ptr]) Ptr(key r.Type) Ptr {
    96  	ptr := self.get(key)
    97  	if ptr != nil {
    98  		return ptr
    99  	}
   100  
   101  	defer Lock(&self.Lock).Unlock()
   102  
   103  	ptr = self.Map[key]
   104  	if ptr != nil {
   105  		return ptr
   106  	}
   107  
   108  	ptr = new(Val)
   109  	ptr.Init(key)
   110  
   111  	if self.Map == nil {
   112  		self.Map = map[r.Type]Ptr{}
   113  	}
   114  	self.Map[key] = ptr
   115  
   116  	return ptr
   117  }
   118  
   119  func (self *TypeCache[Val, Ptr]) get(key r.Type) Ptr {
   120  	defer Lock(self.Lock.RLocker()).Unlock()
   121  	return self.Map[key]
   122  }