-
Notifications
You must be signed in to change notification settings - Fork 13
/
store.go
140 lines (125 loc) · 3.31 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//go:generate ../../scripts/mockery_generate.sh Store
package store
import (
"github.com/dashpay/tenderdash/libs/ds"
sync "github.com/sasha-s/go-deadlock"
)
type (
Store[K comparable, V any] interface {
Get(key K) (V, bool)
GetAndDelete(key K) (V, bool)
Put(key K, data V)
Delete(key K)
Update(key K, updates ...UpdateFunc[K, V])
Query(spec QueryFunc[K, V], limit int) []V
All() []V
Len() int
IsZero() bool
}
// QueryFunc is a function type for a specification function
QueryFunc[K comparable, V any] func(key K, data V) bool
// UpdateFunc is a function type for an item update functions
UpdateFunc[K comparable, V any] func(key K, item *V)
// InMemStore in-memory peer store
InMemStore[K comparable, T any] struct {
mtx sync.RWMutex
items *ds.OrderedMap[K, T]
}
)
// NewInMemStore creates a new in-memory peer store
func NewInMemStore[K comparable, V any]() *InMemStore[K, V] {
mem := &InMemStore[K, V]{
items: ds.NewOrderedMap[K, V](),
}
return mem
}
// Get returns peer's data and true if the peer is found otherwise empty structure and false
func (p *InMemStore[K, T]) Get(key K) (T, bool) {
p.mtx.RLock()
defer p.mtx.RUnlock()
return p.items.Get(key)
}
// GetAndDelete combines Get operation and Delete in one call
func (p *InMemStore[K, T]) GetAndDelete(key K) (T, bool) {
p.mtx.Lock()
defer p.mtx.Unlock()
val, found := p.items.Get(key)
if found {
p.items.Delete(key)
return val, true
}
var zero T
return zero, found
}
// Put adds the peer data to the store if the peer does not exist, otherwise update the current value
func (p *InMemStore[K, T]) Put(key K, data T) {
p.mtx.Lock()
defer p.mtx.Unlock()
p.items.Put(key, data)
}
// Delete removes the peer data from the store
func (p *InMemStore[K, T]) Delete(key K) {
p.mtx.Lock()
defer p.mtx.Unlock()
p.items.Delete(key)
}
// Update applies update functions to the peer if it exists
func (p *InMemStore[K, T]) Update(key K, updates ...UpdateFunc[K, T]) {
p.mtx.Lock()
defer p.mtx.Unlock()
val, found := p.items.Get(key)
if !found {
return
}
for _, update := range updates {
update(key, &val)
}
p.items.Put(key, val)
}
// Query finds and returns the copy of values by specification conditions
func (p *InMemStore[K, T]) Query(spec QueryFunc[K, T], limit int) []T {
p.mtx.RLock()
defer p.mtx.RUnlock()
return p.query(spec, limit)
}
// All returns all stored values in the store
func (p *InMemStore[K, T]) All() []T {
p.mtx.RLock()
defer p.mtx.RUnlock()
return p.items.Values()
}
// Len returns the count of all stored values
func (p *InMemStore[K, T]) Len() int {
p.mtx.RLock()
defer p.mtx.RUnlock()
return p.items.Len()
}
// IsZero returns true if the store doesn't have a peer yet otherwise false
func (p *InMemStore[K, T]) IsZero() bool {
return p.Len() == 0
}
func (p *InMemStore[K, T]) query(spec QueryFunc[K, T], limit int) []T {
var res []T
keys := p.items.Keys()
vals := p.items.Values()
for i := 0; i < len(keys); i++ {
if spec(keys[i], vals[i]) {
res = append(res, vals[i])
if limit > 0 && limit == len(res) {
return res
}
}
}
return res
}
// AndX combines multiple specification functions into one
func AndX[K comparable, V any](specs ...QueryFunc[K, V]) QueryFunc[K, V] {
return func(k K, v V) bool {
for _, spec := range specs {
if !spec(k, v) {
return false
}
}
return true
}
}