github.com/kelleygo/clashcore@v1.0.2/common/arc/arc.go (about) 1 package arc 2 3 import ( 4 "sync" 5 "time" 6 7 list "github.com/bahlo/generic-list-go" 8 "github.com/samber/lo" 9 ) 10 11 //modify from https://github.com/alexanderGugel/arc 12 13 // Option is part of Functional Options Pattern 14 type Option[K comparable, V any] func(*ARC[K, V]) 15 16 func WithSize[K comparable, V any](maxSize int) Option[K, V] { 17 return func(a *ARC[K, V]) { 18 a.c = maxSize 19 } 20 } 21 22 type ARC[K comparable, V any] struct { 23 p int 24 c int 25 t1 *list.List[*entry[K, V]] 26 b1 *list.List[*entry[K, V]] 27 t2 *list.List[*entry[K, V]] 28 b2 *list.List[*entry[K, V]] 29 mutex sync.Mutex 30 len int 31 cache map[K]*entry[K, V] 32 } 33 34 // New returns a new Adaptive Replacement Cache (ARC). 35 func New[K comparable, V any](options ...Option[K, V]) *ARC[K, V] { 36 arc := &ARC[K, V]{ 37 p: 0, 38 t1: list.New[*entry[K, V]](), 39 b1: list.New[*entry[K, V]](), 40 t2: list.New[*entry[K, V]](), 41 b2: list.New[*entry[K, V]](), 42 len: 0, 43 cache: make(map[K]*entry[K, V]), 44 } 45 46 for _, option := range options { 47 option(arc) 48 } 49 return arc 50 } 51 52 // Set inserts a new key-value pair into the cache. 53 // This optimizes future access to this entry (side effect). 54 func (a *ARC[K, V]) Set(key K, value V) { 55 a.mutex.Lock() 56 defer a.mutex.Unlock() 57 58 a.set(key, value) 59 } 60 61 func (a *ARC[K, V]) set(key K, value V) { 62 a.setWithExpire(key, value, time.Unix(0, 0)) 63 } 64 65 // SetWithExpire stores any representation of a response for a given key and given expires. 66 // The expires time will round to second. 67 func (a *ARC[K, V]) SetWithExpire(key K, value V, expires time.Time) { 68 a.mutex.Lock() 69 defer a.mutex.Unlock() 70 71 a.setWithExpire(key, value, expires) 72 } 73 74 func (a *ARC[K, V]) setWithExpire(key K, value V, expires time.Time) { 75 ent, ok := a.cache[key] 76 if !ok { 77 a.len++ 78 ent := &entry[K, V]{key: key, value: value, ghost: false, expires: expires.Unix()} 79 a.req(ent) 80 a.cache[key] = ent 81 return 82 } 83 84 if ent.ghost { 85 a.len++ 86 } 87 88 ent.value = value 89 ent.ghost = false 90 ent.expires = expires.Unix() 91 a.req(ent) 92 } 93 94 // Get retrieves a previously via Set inserted entry. 95 // This optimizes future access to this entry (side effect). 96 func (a *ARC[K, V]) Get(key K) (value V, ok bool) { 97 a.mutex.Lock() 98 defer a.mutex.Unlock() 99 100 ent, ok := a.get(key) 101 if !ok { 102 return lo.Empty[V](), false 103 } 104 return ent.value, true 105 } 106 107 func (a *ARC[K, V]) get(key K) (e *entry[K, V], ok bool) { 108 ent, ok := a.cache[key] 109 if !ok { 110 return ent, false 111 } 112 a.req(ent) 113 return ent, !ent.ghost 114 } 115 116 // GetWithExpire returns any representation of a cached response, 117 // a time.Time Give expected expires, 118 // and a bool set to true if the key was found. 119 // This method will NOT update the expires. 120 func (a *ARC[K, V]) GetWithExpire(key K) (V, time.Time, bool) { 121 a.mutex.Lock() 122 defer a.mutex.Unlock() 123 124 ent, ok := a.get(key) 125 if !ok { 126 return lo.Empty[V](), time.Time{}, false 127 } 128 129 return ent.value, time.Unix(ent.expires, 0), true 130 } 131 132 // Len determines the number of currently cached entries. 133 // This method is side-effect free in the sense that it does not attempt to optimize random cache access. 134 func (a *ARC[K, V]) Len() int { 135 a.mutex.Lock() 136 defer a.mutex.Unlock() 137 138 return a.len 139 } 140 141 func (a *ARC[K, V]) req(ent *entry[K, V]) { 142 switch { 143 case ent.ll == a.t1 || ent.ll == a.t2: 144 // Case I 145 ent.setMRU(a.t2) 146 case ent.ll == a.b1: 147 // Case II 148 // Cache Miss in t1 and t2 149 150 // Adaptation 151 var d int 152 if a.b1.Len() >= a.b2.Len() { 153 d = 1 154 } else { 155 d = a.b2.Len() / a.b1.Len() 156 } 157 a.p = min(a.p+d, a.c) 158 159 a.replace(ent) 160 ent.setMRU(a.t2) 161 case ent.ll == a.b2: 162 // Case III 163 // Cache Miss in t1 and t2 164 165 // Adaptation 166 var d int 167 if a.b2.Len() >= a.b1.Len() { 168 d = 1 169 } else { 170 d = a.b1.Len() / a.b2.Len() 171 } 172 a.p = max(a.p-d, 0) 173 174 a.replace(ent) 175 ent.setMRU(a.t2) 176 case ent.ll == nil && a.t1.Len()+a.b1.Len() == a.c: 177 // Case IV A 178 if a.t1.Len() < a.c { 179 a.delLRU(a.b1) 180 a.replace(ent) 181 } else { 182 a.delLRU(a.t1) 183 } 184 ent.setMRU(a.t1) 185 case ent.ll == nil && a.t1.Len()+a.b1.Len() < a.c: 186 // Case IV B 187 if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c { 188 if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c { 189 a.delLRU(a.b2) 190 } 191 a.replace(ent) 192 } 193 ent.setMRU(a.t1) 194 case ent.ll == nil: 195 // Case IV, not A nor B 196 ent.setMRU(a.t1) 197 } 198 } 199 200 func (a *ARC[K, V]) delLRU(list *list.List[*entry[K, V]]) { 201 lru := list.Back() 202 list.Remove(lru) 203 a.len-- 204 delete(a.cache, lru.Value.key) 205 } 206 207 func (a *ARC[K, V]) replace(ent *entry[K, V]) { 208 if a.t1.Len() > 0 && ((a.t1.Len() > a.p) || (ent.ll == a.b2 && a.t1.Len() == a.p)) { 209 lru := a.t1.Back().Value 210 lru.value = lo.Empty[V]() 211 lru.ghost = true 212 a.len-- 213 lru.setMRU(a.b1) 214 } else { 215 lru := a.t2.Back().Value 216 lru.value = lo.Empty[V]() 217 lru.ghost = true 218 a.len-- 219 lru.setMRU(a.b2) 220 } 221 } 222 223 func min(a, b int) int { 224 if a < b { 225 return a 226 } 227 return b 228 } 229 230 func max(a int, b int) int { 231 if a < b { 232 return b 233 } 234 return a 235 }