-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlist_insert.go
69 lines (62 loc) · 2.07 KB
/
list_insert.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
package linkedlist
// Weak operations implemnt general logic of linkedlist but support two major invariants:
// - no intermediate state allocations
// - no structural changes recovery
//
// That operations are used by general linkedlist operations and by any algorithm build on
// concurrent linked list abstraction.
//
// All operations has same form of calling:
// - pair of consequtive nodes on which operation performs
// - preallocated State instance
// Insert adds given node just after another
func Insert(start, new Node) (Node, bool) {
curNode, update, inserted := start, &State{}, false
for !inserted {
cur := LoadState(curNode)
curNode, inserted = WeakInsert(curNode, cur.Next, update, new)
}
return curNode, true
}
// WeakInsert trys to insert node in between of two given nodes. It completes concurrent
// deletition of the right node if it has been detected and trys to proced if possible.
//
// In case of concurent structural modification detected:
// - left node removed
// - a new node inserted between left and right
// operation terminates and returns
//
// Function always returns leftmost node from {left, new, right} tuple and boolean
// flag indicates was insertion complete or no. In case if left node detected to be
// removed first alive predecessor of it will be returned
func WeakInsert(left, right Node, update *State, new Node) (Node, bool) {
update.Flags = NONE
update.Back = nil
update.Next = new
cur, newState := LoadState(left), *new.State()
for {
// Prepare new node and insert it
newState.Next = cur.Next
if UpdateState(left, cur.Next, NONE, update) {
// DEBUG:
// fmt.Printf("Inserted: %s -> %s\n", curNode, cur.Next)
return left, true
}
// Check why insertion fails:
// - left flags change, we could recover only from freeze
// - left if not point to right anymore
cur = LoadState(left)
if cur.Next != right {
return left, false
}
if cur.IsFreezed() {
CompleteDelete(left, right)
continue
}
// start node got new child
for cur.IsRemoved() {
left, cur = cur.Back, LoadState(cur.Back)
}
return left, false
}
}