-
Notifications
You must be signed in to change notification settings - Fork 0
/
buffer.h
135 lines (117 loc) · 3.19 KB
/
buffer.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
130
131
132
133
134
135
#ifndef SIK_UDP_BUFFER_H
#define SIK_UDP_BUFFER_H
#include <memory>
#include <array>
/**
* Cyclic buffer with specified size.
* @tparam T type of element.
* @tparam buffer_size maximum buffer size.
*/
template<typename T, std::size_t buffer_size>
class Buffer {
static_assert(buffer_size > 0,
"Buffer buffer_size must be greater than zero");
private:
/// Elements in the buffer.
std::array<T, buffer_size> data;
/// Starting index.
std::size_t start = 0u;
/// Number of items in the buffer.
std::size_t length = 0u;
/**
* Increases the starting index by one.
*/
void increase_index() noexcept {
start = (start + 1) % buffer_size;
}
/**
* Returns the mapping of abstract buffer index to the actual index in the
* data array.
* @param index index in the buffer.
* @return index in the data array.
*/
inline std::size_t get_index(std::size_t index) const noexcept {
return (start + index) % buffer_size;
}
public:
Buffer() = default;
Buffer(const Buffer &) = delete;
/**
* Access the buffer item.
* @param index index in the buffer.
* @return item at the index
*/
T &operator[](const std::size_t index) {
if (index >= length) {
throw std::out_of_range("index out of range");
}
return data[get_index(index)];
}
/**
* @return number of elements in the buffer.
*/
std::size_t size() const noexcept {
return length;
}
/**
* Inserts new item at the end of the buffer.
* If the buffer is full removes the first item.
* @param item item to insert.
*/
void push(T item) noexcept {
if (length == buffer_size) {
increase_index();
} else {
length++;
}
data[get_index(length - 1)] = std::move(item);
}
/**
* Returns the first item in the buffer and removes it from the data array.
* @return first item in the buffer.
* @throws std::out_of_range if the buffer is empty.
*/
T pop() {
if (length == 0) {
throw std::out_of_range("buffer is empty");
}
T item = std::move((*this)[0]);
increase_index();
length--;
return std::move(item);
}
/**
* Buffer iterator. Helper class for range based loop to work.
*/
class iterator {
private:
Buffer<T, buffer_size> *buffer;
std::size_t index;
public:
iterator(Buffer<T, buffer_size> *buffer, std::size_t index)
: buffer(buffer), index(index) {}
iterator operator++() noexcept {
index++;
return iterator(buffer, index);
}
bool operator!=(const iterator &other) const noexcept {
return index != other.index;
}
const T &operator*() {
return (*buffer)[index];
}
};
/**
* @return iterator to the buffer first item.
*/
iterator begin() {
return iterator(this, 0);
}
/**
* @return iterator to the buffer last item.
*/
iterator end() {
return iterator(this, length);
}
};
#endif //SIK_UDP_BUFFER_H