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 }