-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathstack.h
129 lines (102 loc) · 3.03 KB
/
stack.h
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
// Copyright (c) 2014, the scalloc Project Authors. All rights reserved.
// Please see the AUTHORS file for details. Use of this source code is governed
// by a BSD license that can be found in the LICENSE file.
#ifndef SCALLOC_STACK_INL_H_
#define SCALLOC_STACK_INL_H_
#include <stdint.h>
#include <stdio.h>
#include <atomic>
#include "atomic_value.h"
#include "globals.h"
#include "log.h"
namespace scalloc {
// Treiber stack
//
// Note: The implementation stores the next pointers in the memory provided, and
// thus needs blocks of at least sizeof(TaggedValue).
template<int PAD = 64>
class Stack {
public:
always_inline Stack() : top_(TaggedValue<void*>(nullptr, 0)) { }
always_inline void Push(void* p);
always_inline void PushRange(void* p_start, void* p_end);
always_inline void* Pop();
always_inline void PopAll(void** elements, int32_t* len);
always_inline int_fast32_t Length();
always_inline void SetTop(void* p);
always_inline bool Empty() {
return top_.load() == TaggedValue<void*>(NULL, 0);
}
always_inline int32_t PushReturnTag(void* p);
private:
typedef TaggedValue<void*> TopPtr;
AtomicTaggedValue<void*> top_;
int8_t pad_[
(PAD == 0) ? 0 : PAD - (sizeof(top_) % PAD)];
};
template<int PAD>
void Stack<PAD>::SetTop(void* p) {
top_.store(TopPtr(p, 0));
}
template<int PAD>
int32_t Stack<PAD>::PushReturnTag(void* p) {
TopPtr top_old;
do {
top_old = top_.load();
*(reinterpret_cast<void**>(p)) = top_old.value();
} while (!top_.swap(top_old, TopPtr(p, top_old.tag() + 1)));
return top_old.tag() + 1;
}
template<int PAD>
void Stack<PAD>::Push(void* p) {
LOG(kTrace, "push %p", p);
TopPtr top_old;
do {
top_old = top_.load();
*(reinterpret_cast<void**>(p)) = top_old.value();
} while (!top_.swap(top_old, TopPtr(p, top_old.tag() + 1)));
}
template<int PAD>
void Stack<PAD>::PushRange(void* p_start, void* p_end) {
TopPtr top_old;
do {
top_old = top_.load();
*(reinterpret_cast<void**>(p_end)) = top_old.value();
} while (!top_.swap(top_old, TopPtr(p_start, top_old.tag() + 1)));
}
template<int PAD>
void* Stack<PAD>::Pop() {
TopPtr top_old;
do {
top_old = top_.load();
if (top_old.value() == NULL) {
return NULL;
}
} while (!top_.swap(
top_old, TopPtr(*(reinterpret_cast<void**>(top_old.value())),
top_old.tag() + 1)));
LOG(kTrace, "pop %p", top_old.value());
return top_old.value();
}
// Returns the length of the list returned iff there have not been any pop()
// operations in between.
template<int PAD>
void Stack<PAD>::PopAll(void** elements, int32_t* len) {
TopPtr top_old;
do {
top_old = top_.load();
if (top_old.value() == NULL) {
break;
}
} while (!top_.swap(top_old, TopPtr(NULL, 0)));
*elements = top_old.value();
*len = top_old.tag();
}
// Returns the length of the list returned iff there have not been any pop()
// operations in between.
template<int PAD>
int_fast32_t Stack<PAD>::Length() {
return top_.load().tag();
}
} // namespace scalloc
#endif // SCALLOC_STACK_INL_H_