-
Notifications
You must be signed in to change notification settings - Fork 0
/
context_imut.go
134 lines (99 loc) · 2.67 KB
/
context_imut.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
package immap
import (
"context"
"reflect"
)
const (
// DELETED is a delete marker used by ConImutMap.
CDELETED = "marked as deleted"
)
// NewConImutMapper returns a new instance of implementing ConImutMapper interface.
func NewContextImutMapper(ctx context.Context) (ContextImutMapper, context.CancelFunc) {
canCtx, terminate := context.WithCancel(ctx)
iPack := &ConImutMap{canCtx, make(chan *mapPack, 1)}
go iPack.runLoop()
return iPack, terminate
}
func (imap *ConImutMap) runLoop() {
mapList := make([]ContextMapper, 0)
bookMap, _ := NewcontextMapper(imap.Context)
var lastInd, lastMapInd int
var iPoint int
var tMap ContextMapper
var ok bool
for {
select {
case <-imap.Done():
return
case opMsg := <-imap.cChan:
startSlice, exists := bookMap.Exists(opMsg.key)
iList := []int{}
if !exists {
lastInd = -1
} else {
iList, ok = startSlice.([]int)
if !ok {
panic("Value of bookMap needs to be a []int")
}
lastInd = iList[len(iList)-1]
}
switch opMsg.op {
case ADD_KEY:
expand := false
if len(mapList) > 0 {
lastMapInd = len(mapList) - 1
} else {
expand = true
}
lastInd = lastInd + 1
if expand || lastInd > lastMapInd {
tMap, _ = NewcontextMapper(imap.Context)
mapList = append(mapList, tMap)
iPoint = len(mapList) - 1
} else {
iPoint = lastInd
}
lpage := mapList[iPoint]
lpage.Add(opMsg.key, opMsg.value)
_, exists := bookMap.Exists(opMsg.key)
if exists {
bookMap.Add(opMsg.key, append(iList, lastInd))
} else {
bookMap.Add(opMsg.key, append([]int(nil), lastInd))
}
opMsg.ret <- retPack{nil, lpage}
case CHECK_KEY:
intMap := mapList[lastInd]
value, _ := intMap.Exists(opMsg.key)
if value == CDELETED {
panic("CDELETED value should not be here")
}
opMsg.ret <- retPack{value, intMap}
}
}
}
}
// Add method allows one to add new keys.
// Returns a reference to ContextMapper
func (imap *ConImutMap) Add(key, value interface{}) ContextMapper {
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).(ContextMapper)
}
// Exists method allows to check and return the key.
// Also, returns a reference to ContextMapper.
func (imap *ConImutMap) Exists(key interface{}) (interface{}, bool, ContextMapper) {
iPack := &mapPack{CHECK_KEY, key, nil, make(chan retPack, 1)}
imap.cChan <- iPack
val := <-iPack.ret
tmap := (val.mapRef).(ContextMapper)
_, exists := tmap.Exists(key)
return val.value, exists, tmap
}