forked from zond/gotomic
-
Notifications
You must be signed in to change notification settings - Fork 1
/
list.go
160 lines (141 loc) · 3.61 KB
/
list.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package gotomic
import (
"fmt"
"sync/atomic"
"unsafe"
)
type ListIterator func(e entry) bool
type element struct {
// The next element in the list.
unsafe.Pointer
entry entry
}
type hit struct {
left *element
element *element
right *element
}
type Thing interface{}
var list_head = "LIST_HEAD"
func (self *element) next() *element {
next := atomic.LoadPointer(&self.Pointer)
if next == nil {
return nil
}
nextElement := (*element)(next)
return nextElement
}
func (self *element) each(i ListIterator) bool {
n := self
for n != nil {
if i(n.entry) {
return true
}
n = n.next()
}
return false
}
func (self *element) String() string {
return fmt.Sprint(self.ToSlice())
}
func (self *element) Describe() string {
if self == nil {
return fmt.Sprint(nil)
}
return fmt.Sprintf("%#v -> %v", self, self.next().Describe())
}
func (self *element) add(e entry) (rval bool) {
alloc := &element{}
for {
// If we succeed in adding before our perceived next, just return true.
if self.addBefore(e, alloc, self.next()) {
rval = true
break
}
}
return
}
func (self *element) addBefore(e entry, allocatedElement, before *element) bool {
if self.next() != before {
return false
}
allocatedElement.entry = e
allocatedElement.Pointer = unsafe.Pointer(before)
return atomic.CompareAndSwapPointer(&self.Pointer, unsafe.Pointer(before), unsafe.Pointer(allocatedElement))
}
// /*
// inject c into self either before the first matching value (c.Compare(value) == 0), before the first value
// it should be before (c.Compare(value) < 0) or after the first value it should be after (c.Compare(value) > 0).
// */
// func (self *element) inject(e entry) {
// alloc := &element{}
// for {
// hit := self.search(e)
// if hit.left != nil {
// if hit.element != nil {
// if hit.left.addBefore(e, alloc, hit.element) {
// break
// }
// } else {
// if hit.left.addBefore(e, alloc, hit.right) {
// break
// }
// }
// } else if hit.element != nil {
// if hit.element.addBefore(e, alloc, hit.right) {
// break
// }
// } else {
// panic(fmt.Errorf("Unable to inject %v properly into %v, it ought to be first but was injected into the first element of the list!", e, self))
// }
// }
// }
func (self *element) ToSlice() []Thing {
rval := make([]Thing, 0)
current := self
for current != nil {
rval = append(rval, current.entry)
current = current.next()
}
return rval
}
// search without thread-local *hit
func (self *element) search(e entry) *hit {
tmp := &hit{nil, self, nil}
return self.search_local(e, tmp)
}
// search for e in self. Will stop searching when finding nil or an
// element that should be after e (e.Compare(element) < 0). Will
// return a hit containing the last elementRef and element before a
// match (if no match, the last elementRef and element before it stops
// searching), the elementRef and element for the match (if a match)
// and the last elementRef and element after the match (if no match,
// the first elementRef and element, or nil/nil if at the end of the
// list).
func (self *element) search_local(e entry, hh *hit) (rval *hit) {
rval = hh
for {
if rval.element == nil {
return
}
rval.right = rval.element.next()
var cmp int = e.Compare(&(rval.element.entry))
if cmp < 0 {
rval.right = rval.element
rval.element = nil
return
} else if cmp == 0 {
return
}
rval.left = rval.element
rval.element = rval.left.next()
rval.right = nil
}
panic(fmt.Sprint("Unable to search for ", e, " in ", self))
}
func ReusableHit() *hit {
return &hit{nil, nil, nil}
}
func (self *element) doRemove() bool {
return false
}