-
Notifications
You must be signed in to change notification settings - Fork 1
/
slice.go
95 lines (82 loc) · 1.92 KB
/
slice.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
package freesync
import (
"sync"
"sync/atomic"
"github.com/wencan/freesync/lockfree"
)
// Slice 并发安全的Slice结构。
type Slice struct {
// mux 锁。
mu sync.Mutex
// store 实质存储数据。内部结构为*lockfree.Slice。
// slice增长时,需要加锁。
store atomic.Value
}
// Append 在末尾追加一个元素。返回下标。
func (slice *Slice) Append(p interface{}) int {
store, _ := slice.store.Load().(*lockfree.Slice)
if store != nil {
if index, ok := store.Append(p); ok {
return index
}
}
slice.mu.Lock()
defer slice.mu.Unlock()
if store == nil {
// 初始化
store, _ = slice.store.Load().(*lockfree.Slice)
if store == nil {
store = &lockfree.Slice{}
slice.store.Store(store)
}
} else {
previous := store
store = slice.store.Load().(*lockfree.Slice)
if store != previous {
if index, ok := store.Append(p); ok {
return index
}
}
}
// 增加容量后再append
newStore, _ := store.Grow()
index, ok := newStore.Append(p)
if !ok {
panic("impossibility")
}
slice.store.Store(newStore)
return index
}
// Load 取得下标位置上的值。
func (slice *Slice) Load(index int) interface{} {
store, _ := slice.store.Load().(*lockfree.Slice)
if store == nil {
panic("empty slice")
}
return store.Load(index)
}
// Range 遍历。
func (slice *Slice) Range(f func(index int, p interface{}) (stopIteration bool)) {
store, _ := slice.store.Load().(*lockfree.Slice)
if store == nil {
return
}
store.Range(f)
}
// Length 长度。
func (slice *Slice) Length() int {
var length int
slice.Range(func(index int, p interface{}) (stopIteration bool) {
length++
return false
})
return length
}
// UpdateAt 更新下标位置上的值,返回旧值。
func (slice *Slice) UpdateAt(index int, p interface{}) (old interface{}) {
store, _ := slice.store.Load().(*lockfree.Slice)
if store == nil {
panic("empty slice")
}
return store.UpdateAt(index, p)
}