-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimmut.go
132 lines (103 loc) · 2.76 KB
/
immut.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
package immap
import (
"context"
"reflect"
)
const (
// DELETED is a delete marker used by ImutMap.
DELETED = "marked as deleted"
)
// NewImutMapper returns a new instance of implementing ImutMapper interface.
func NewImutMapper(ctx context.Context) (ImutMapper, context.CancelFunc) {
canCtx, terminate := context.WithCancel(ctx)
iPack := &ImutMap{canCtx, make(chan *mapPack, 1)}
go iPack.runLoop()
return iPack, terminate
}
// RunLoop is the ImutMapper's map requests processing loop.
func (imap *ImutMap) runLoop() {
mapList := make([]IntfMap, 0)
bookMap := make(map[interface{}][]int)
var lastInd, lastMapInd int
var iPoint int
for {
select {
case <-imap.Done():
return
case opMsg := <-imap.cChan:
startSlice, exists := bookMap[opMsg.key]
if !exists {
lastInd = -1
} else {
lastInd = startSlice[len(startSlice)-1]
}
switch opMsg.op {
case ADD_KEY:
expand := false
if len(mapList) > 0 {
lastMapInd = len(mapList) - 1
} else {
expand = true
}
lastInd = lastInd + 1
if lastInd > lastMapInd || expand {
mapList = append(mapList, make(IntfMap))
iPoint = len(mapList) - 1
} else {
iPoint = lastInd
}
lpage := mapList[iPoint]
lpage[opMsg.key] = opMsg.value
bookMap[opMsg.key] = append(bookMap[opMsg.key], lastInd)
opMsg.ret <- retPack{nil, lpage}
case CHECK_KEY:
intMap := mapList[lastInd]
value, _ := intMap[opMsg.key]
if value == DELETED {
panic("DELETED value should not be here")
}
opMsg.ret <- retPack{value, intMap}
case DEL_KEY:
intMap := mapList[lastInd]
value, exists := intMap[opMsg.key]
if exists {
if value == DELETED {
panic("DELETED value should not be here")
} else {
intMap[opMsg.key] = DELETED
bookMap[opMsg.key] = bookMap[opMsg.key][:len(bookMap[opMsg.key])-1]
}
}
}
}
}
}
// Add method allows one to add new keys.
// Returns a reference to IntfMap
func (imap *ImutMap) Add(key, value interface{}) IntfMap {
if key == nil {
panic("nil key")
}
if !reflect.TypeOf(key).Comparable() {
panic("key is not comparable")
}
iPack := &mapPack{ADD_KEY, key, value, make(chan retPack, 1)}
imap.cChan <- iPack
pack := <-iPack.ret
return (pack.mapRef).(IntfMap)
}
// Exists method allows to check and return the key.
// Also, returns a reference to IntfMap.
func (imap *ImutMap) Exists(key interface{}) (interface{}, bool, IntfMap) {
iPack := &mapPack{CHECK_KEY, key, nil, make(chan retPack, 1)}
imap.cChan <- iPack
val := <-iPack.ret
tmap := (val.mapRef).(IntfMap)
_, exists := tmap[key]
return val.value, exists, tmap
}
// Delete method allows to delete keys.
func (imap *ImutMap) Delete(key interface{}) {
iPack := &mapPack{DEL_KEY, key, nil, nil}
imap.cChan <- iPack
}