volatile.go (view raw)
1package volatile
2
3import (
4 "fmt"
5 "time"
6)
7
8type Element[V any] struct {
9 value *V
10 Timestamp time.Time
11}
12
13type Volatile[K comparable, V any] struct {
14 data map[K]Element[V]
15 timeToLive time.Duration
16}
17
18func (v *Volatile[K, V]) clean() (count int) {
19 now := time.Now()
20
21 for key, value := range v.data {
22 if now.Sub(value.Timestamp) > v.timeToLive {
23 delete(v.data, key)
24 count += 1
25 }
26 }
27 return
28}
29
30func (v *Volatile[K, V]) cleanupRoutine(interval time.Duration) {
31 ticker := time.NewTicker(interval)
32 defer ticker.Stop()
33
34 for range ticker.C {
35 v.clean()
36 }
37}
38
39func NewVolatile[K comparable, V any](timeToLive time.Duration, cleanupInterval time.Duration) *Volatile[K, V] {
40 v := &Volatile[K, V]{
41 data: make(map[K]Element[V]),
42 timeToLive: timeToLive,
43 }
44 go v.cleanupRoutine(cleanupInterval)
45 return v
46}
47
48func (v *Volatile[K, V]) Has(key K) (ok bool) {
49 v.clean()
50 _, ok = v.data[key]
51 return
52}
53
54func (v *Volatile[K, V]) Get(key K) (*V, error) {
55 v.clean()
56 element, ok := v.data[key]
57
58 if !ok {
59 return nil, fmt.Errorf("not found")
60 }
61
62 return element.value, nil
63}
64
65func (v *Volatile[K, V]) Remove(key K) (*V, error) {
66 v.clean()
67 value, ok := v.data[key]
68
69 if !ok {
70 return nil, fmt.Errorf("not found")
71 }
72
73 delete(v.data, key)
74 return value.value, nil
75}
76
77func (v *Volatile[K, V]) Set(key K, value *V) {
78 v.data[key] = Element[V]{value: value, Timestamp: time.Now()}
79 v.clean()
80}