-
Notifications
You must be signed in to change notification settings - Fork 49
/
sets.go
142 lines (114 loc) · 3.01 KB
/
sets.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
141
142
package geoindex
import (
"time"
)
// A set interface.
type set interface {
Add(id string, value interface{})
Get(id string) (value interface{}, ok bool)
Remove(id string)
Values() []interface{}
Size() int
Clone() set
}
// A set that contains values.
type basicSet map[string]interface{}
func newSet() set {
return basicSet(make(map[string]interface{}))
}
// Clone creates a copy of the set where the values in clone set point to the same underlying reference as the original set
func (set basicSet) Clone() set {
clone := basicSet(make(map[string]interface{}))
for k, v := range set {
clone[k] = v
}
return clone
}
func (set basicSet) Add(id string, value interface{}) {
set[id] = value
}
func (set basicSet) Remove(id string) {
delete(set, id)
}
func (set basicSet) Values() []interface{} {
result := make([]interface{}, 0, len(set))
for _, point := range set {
result = append(result, point)
}
return result
}
func (set basicSet) Get(id string) (value interface{}, ok bool) {
value, ok = set[id]
return
}
func (set basicSet) Size() int {
return len(set)
}
// An expiring set that removes the points after X minutes.
type expiringSet struct {
values set
insertionOrder *queue
expiration Minutes
onExpire func(id string, value interface{})
lastInserted map[string]time.Time
}
type timestampedValue struct {
id string
value interface{}
timestamp time.Time
}
// Clone panics - We currently do not allow cloning of an expiry set
func (set *expiringSet) Clone() set {
panic("Cannot clone an expiry set")
}
func newExpiringSet(expiration Minutes) *expiringSet {
return &expiringSet{newSet(), newQueue(1), expiration, nil, make(map[string]time.Time)}
}
func (set *expiringSet) hasExpired(time time.Time) bool {
currentTime := getNow()
return int(currentTime.Sub(time).Minutes()) > int(set.expiration)
}
func (set *expiringSet) expire() {
for !set.insertionOrder.IsEmpty() {
lastInserted := set.insertionOrder.Peek().(*timestampedValue)
if set.hasExpired(lastInserted.timestamp) {
set.insertionOrder.Pop()
if set.hasExpired(set.lastInserted[lastInserted.id]) {
set.values.Remove(lastInserted.id)
if set.onExpire != nil {
set.onExpire(lastInserted.id, lastInserted.value)
}
}
} else {
break
}
}
}
func (set *expiringSet) Add(id string, value interface{}) {
set.expire()
set.values.Add(id, value)
insertionTime := getNow()
set.lastInserted[id] = insertionTime
set.insertionOrder.Push(×tampedValue{id, value, insertionTime})
}
func (set *expiringSet) Remove(id string) {
set.expire()
set.values.Remove(id)
delete(set.lastInserted, id)
}
func (set *expiringSet) Get(id string) (value interface{}, ok bool) {
set.expire()
value, ok = set.values.Get(id)
return
}
func (set *expiringSet) Size() int {
set.expire()
return set.values.Size()
}
func (set *expiringSet) Values() []interface{} {
set.expire()
return set.values.Values()
}
func (set *expiringSet) OnExpire(onExpire func(id string, value interface{})) {
set.onExpire = onExpire
}