Common code for implementing Twitch bots.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
2.5 KiB

package lru
import (
"container/list"
"strings"
)
type sdlruEntry struct {
val string
ts int64
}
// SDLRU is an LRU for strings with a maximum age
type SDLRU struct {
capacity int
list *list.List
lut map[string]*list.Element
}
// NewStringDecayLRU creates a new string LRU with a maximum capacity.
// TODO: decay mechanism?
func NewStringDecayLRU(capacity int) *SDLRU {
return &SDLRU{
capacity: capacity,
list: list.New(),
lut: make(map[string]*list.Element),
}
}
// Delete removes a key from the LRU and returns if the key was in the cache.
func (s *SDLRU) Delete(key string) bool {
e, ok := s.lut[key]
if !ok {
return false
}
s.list.Remove(e)
delete(s.lut, key)
s.capacity++
return true
}
// Add adds the given value and returns true if the value was in the
// cache.
func (s *SDLRU) Add(val string, ts int64) bool {
e := s.lut[val]
if e != nil {
s.list.MoveToFront(e)
return true
}
if s.capacity == 0 {
// Evict once
if last := s.list.Back(); last != nil {
s.list.Remove(last)
delete(s.lut, last.Value.(sdlruEntry).val)
}
} else {
s.capacity--
}
e = s.list.PushFront(sdlruEntry{val: val, ts: ts})
s.lut[val] = e
return false
}
// AddUnless adds/refreshes the value and returns true if the value is not in
// the cache or if it is older than delta.
func (s *SDLRU) AddUnless(val string, ts, delta int64) bool {
e := s.lut[val]
if e != nil {
se := e.Value.(sdlruEntry)
if (ts - se.ts) <= delta {
// Not expired yet
return false
}
se.ts = ts
e.Value = se
s.list.MoveToFront(e)
return true
}
if s.capacity == 0 {
// Evict once
if last := s.list.Back(); last != nil {
s.list.Remove(last)
delete(s.lut, last.Value.(sdlruEntry).val)
}
} else {
s.capacity--
}
e = s.list.PushFront(sdlruEntry{val: val, ts: ts})
s.lut[val] = e
return true
}
// Check checks if the value is in the cache and not older than ts by delta
// seconds.
func (s *SDLRU) Check(val string, ts, delta int64) bool {
e := s.lut[val]
if e == nil {
return false
}
vts := e.Value.(sdlruEntry).ts
return (ts - vts) <= delta
}
// Iter iterates over all values in the cache.
func (s *SDLRU) Iter(f func(string, int64) bool) {
for e := s.list.Front(); e != nil; e = e.Next() {
se := e.Value.(sdlruEntry)
if !f(se.val, se.ts) {
break
}
}
}
// String returns a string representation of the LRU entries for debugging.
func (s *SDLRU) String() string {
var repr []string
for e := s.list.Front(); e != nil; e = e.Next() {
repr = append(repr, e.Value.(sdlruEntry).val)
}
return strings.Join(repr, ",")
}