-
Notifications
You must be signed in to change notification settings - Fork 0
/
SingleThreadRingBuffer.h
96 lines (86 loc) · 2.13 KB
/
SingleThreadRingBuffer.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
#include <cassert>
#include <cstdlib>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
template <typename T>
class SingleThreadRingBuffer {
private:
const size_t capacity_;
T* const records_;
size_t readIndex_;
size_t writeIndex_;
public:
explicit SingleThreadRingBuffer(size_t numRecords)
: capacity_(numRecords),
records_(static_cast<T*>(std::malloc(sizeof(T) * (capacity_ + 1)))),
readIndex_(0),
writeIndex_(0) {
assert(capacity_ >= 2);
if (!records_) {
throw std::bad_alloc();
}
}
~SingleThreadRingBuffer() {
if (!std::is_trivially_destructible_v<T>) {
size_t readIndex = readIndex_;
const size_t endIndex = writeIndex_;
while (readIndex != endIndex) {
records_[readIndex].~T();
if (++readIndex == capacity_) {
readIndex = 0;
}
}
}
std::free(records_);
}
bool empty() const { return readIndex_ == writeIndex_; }
bool full() const {
auto nextWriteIndex = writeIndex_ + 1;
if (nextWriteIndex == capacity_) {
nextWriteIndex = 0;
}
if (nextWriteIndex != readIndex_) {
return false;
}
return true;
}
size_t size() const {
auto estimate = writeIndex_ - readIndex_;
if (estimate < 0) {
estimate += capacity_;
}
return estimate;
}
bool push(const T& record) {
auto nextWriteIndex = writeIndex_ + 1;
// Wrap around if we reached the end of the queue
if (nextWriteIndex == capacity_) {
nextWriteIndex = 0;
}
// If writeIndex is one element behind readIndex the queue is full
if (nextWriteIndex != readIndex_) {
records_[writeIndex_] = record;
writeIndex_ = nextWriteIndex;
return true;
}
return false;
}
void pop() {
assert(readIndex_ != writeIndex_);
records_[readIndex_].~T();
auto nextRecord = readIndex_ + 1;
// Wrap around if queue is full
if (nextRecord == capacity_) {
nextRecord = 0;
}
readIndex_ = nextRecord;
}
T* front() {
if (readIndex_ == writeIndex_) {
return nullptr;
}
return &records_[readIndex_];
}
};