WPILibC++ 2024.1.1-beta-4
circular_buffer.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <cstddef>
8#include <iterator>
9#include <vector>
10
11namespace wpi {
12
13/**
14 * This is a simple circular buffer so we don't need to "bucket brigade" copy
15 * old values.
16 */
17template <class T>
19 public:
20 explicit circular_buffer(size_t size) : m_data(size, T{}) {}
21
26
27 class iterator {
28 public:
29 using iterator_category = std::forward_iterator_tag;
30 using value_type = T;
31 using difference_type = std::ptrdiff_t;
32 using pointer = T*;
33 using reference = T&;
34
35 iterator(circular_buffer* buffer, size_t index)
36 : m_buffer{buffer}, m_index{index} {}
37
39 ++m_index;
40 return *this;
41 }
43 iterator retval = *this;
44 ++(*this);
45 return retval;
46 }
47 bool operator==(const iterator&) const = default;
48 reference operator*() { return (*m_buffer)[m_index]; }
49
50 private:
51 circular_buffer* m_buffer;
52 size_t m_index;
53 };
54
56 public:
57 using iterator_category = std::forward_iterator_tag;
58 using value_type = T;
59 using difference_type = std::ptrdiff_t;
60 using pointer = T*;
61 using const_reference = const T&;
62
63 const_iterator(const circular_buffer* buffer, size_t index)
64 : m_buffer{buffer}, m_index{index} {}
65
67 ++m_index;
68 return *this;
69 }
71 const_iterator retval = *this;
72 ++(*this);
73 return retval;
74 }
75 bool operator==(const const_iterator&) const = default;
76 const_reference operator*() const { return (*m_buffer)[m_index]; }
77
78 private:
79 const circular_buffer* m_buffer;
80 size_t m_index;
81 };
82
83 iterator begin() { return iterator(this, 0); }
85
86 const_iterator begin() const { return const_iterator(this, 0); }
89 }
90
91 const_iterator cbegin() const { return const_iterator(this, 0); }
94 }
95
96 /**
97 * Returns number of elements in buffer
98 */
99 size_t size() const { return m_length; }
100
101 /**
102 * Returns value at front of buffer
103 */
104 T& front() { return (*this)[0]; }
105
106 /**
107 * Returns value at front of buffer
108 */
109 const T& front() const { return (*this)[0]; }
110
111 /**
112 * Returns value at back of buffer
113 *
114 * If there are no elements in the buffer, calling this function results in
115 * undefined behavior.
116 */
117 T& back() { return m_data[(m_front + m_length - 1) % m_data.size()]; }
118
119 /**
120 * Returns value at back of buffer
121 *
122 * If there are no elements in the buffer, calling this function results in
123 * undefined behavior.
124 */
125 const T& back() const {
126 return m_data[(m_front + m_length - 1) % m_data.size()];
127 }
128
129 /**
130 * Push a new value onto the front of the buffer.
131 *
132 * The value at the back is overwritten if the buffer is full.
133 */
134 void push_front(T value) {
135 if (m_data.size() == 0) {
136 return;
137 }
138
139 m_front = ModuloDec(m_front);
140
141 m_data[m_front] = value;
142
143 if (m_length < m_data.size()) {
144 m_length++;
145 }
146 }
147
148 /**
149 * Push a new value onto the back of the buffer.
150 *
151 * The value at the front is overwritten if the buffer is full.
152 */
153 void push_back(T value) {
154 if (m_data.size() == 0) {
155 return;
156 }
157
158 m_data[(m_front + m_length) % m_data.size()] = value;
159
160 if (m_length < m_data.size()) {
161 m_length++;
162 } else {
163 // Increment front if buffer is full to maintain size
164 m_front = ModuloInc(m_front);
165 }
166 }
167
168 /**
169 * Push a new value onto the front of the buffer that is constructed with the
170 * provided constructor arguments.
171 *
172 * The value at the back is overwritten if the buffer is full.
173 */
174 template <class... Args>
175 void emplace_front(Args&&... args) {
176 if (m_data.size() == 0) {
177 return;
178 }
179
180 m_front = ModuloDec(m_front);
181
182 m_data[m_front] = T{args...};
183
184 if (m_length < m_data.size()) {
185 m_length++;
186 }
187 }
188
189 /**
190 * Push a new value onto the back of the buffer that is constructed with the
191 * provided constructor arguments.
192 *
193 * The value at the front is overwritten if the buffer is full.
194 */
195 template <class... Args>
196 void emplace_back(Args&&... args) {
197 if (m_data.size() == 0) {
198 return;
199 }
200
201 m_data[(m_front + m_length) % m_data.size()] = T{args...};
202
203 if (m_length < m_data.size()) {
204 m_length++;
205 } else {
206 // Increment front if buffer is full to maintain size
207 m_front = ModuloInc(m_front);
208 }
209 }
210
211 /**
212 * Pop value at front of buffer.
213 *
214 * If there are no elements in the buffer, calling this function results in
215 * undefined behavior.
216 */
218 T& temp = m_data[m_front];
219 m_front = ModuloInc(m_front);
220 m_length--;
221 return temp;
222 }
223
224 /**
225 * Pop value at back of buffer.
226 *
227 * If there are no elements in the buffer, calling this function results in
228 * undefined behavior.
229 */
231 m_length--;
232 return m_data[(m_front + m_length) % m_data.size()];
233 }
234
235 /**
236 * Resizes internal buffer to given size.
237 */
238 void resize(size_t size);
239
240 /**
241 * Empties internal buffer.
242 */
243 void reset() {
244 m_front = 0;
245 m_length = 0;
246 }
247
248 /**
249 * @return Element at index starting from front of buffer.
250 */
251 T& operator[](size_t index) {
252 return m_data[(m_front + index) % m_data.size()];
253 }
254
255 /**
256 * @return Element at index starting from front of buffer.
257 */
258 const T& operator[](size_t index) const {
259 return m_data[(m_front + index) % m_data.size()];
260 }
261
262 private:
263 std::vector<T> m_data;
264
265 // Index of element at front of buffer
266 size_t m_front = 0;
267
268 // Number of elements used in buffer
269 size_t m_length = 0;
270
271 /**
272 * Increment an index modulo the size of the buffer.
273 *
274 * @param index Index into the buffer.
275 * @return The incremented index.
276 */
277 size_t ModuloInc(size_t index) { return (index + 1) % m_data.size(); }
278
279 /**
280 * Decrement an index modulo the size of the buffer.
281 *
282 * @param index Index into the buffer.
283 * @return The decremented index.
284 */
285 size_t ModuloDec(size_t index) {
286 if (index == 0) {
287 return m_data.size() - 1;
288 } else {
289 return index - 1;
290 }
291 }
292};
293
294} // namespace wpi
295
Definition: circular_buffer.h:55
std::ptrdiff_t difference_type
Definition: circular_buffer.h:59
const_iterator & operator++()
Definition: circular_buffer.h:66
const_reference operator*() const
Definition: circular_buffer.h:76
T value_type
Definition: circular_buffer.h:58
bool operator==(const const_iterator &) const =default
std::forward_iterator_tag iterator_category
Definition: circular_buffer.h:57
const T & const_reference
Definition: circular_buffer.h:61
const_iterator(const circular_buffer *buffer, size_t index)
Definition: circular_buffer.h:63
T * pointer
Definition: circular_buffer.h:60
const_iterator operator++(int)
Definition: circular_buffer.h:70
Definition: circular_buffer.h:27
iterator & operator++()
Definition: circular_buffer.h:38
bool operator==(const iterator &) const =default
reference operator*()
Definition: circular_buffer.h:48
std::ptrdiff_t difference_type
Definition: circular_buffer.h:31
iterator operator++(int)
Definition: circular_buffer.h:42
T & reference
Definition: circular_buffer.h:33
T * pointer
Definition: circular_buffer.h:32
iterator(circular_buffer *buffer, size_t index)
Definition: circular_buffer.h:35
std::forward_iterator_tag iterator_category
Definition: circular_buffer.h:29
T value_type
Definition: circular_buffer.h:30
This is a simple circular buffer so we don't need to "bucket brigade" copy old values.
Definition: circular_buffer.h:18
size_t size() const
Returns number of elements in buffer.
Definition: circular_buffer.h:99
void emplace_back(Args &&... args)
Push a new value onto the back of the buffer that is constructed with the provided constructor argume...
Definition: circular_buffer.h:196
iterator end()
Definition: circular_buffer.h:84
iterator begin()
Definition: circular_buffer.h:83
T pop_back()
Pop value at back of buffer.
Definition: circular_buffer.h:230
circular_buffer & operator=(const circular_buffer &)=default
void emplace_front(Args &&... args)
Push a new value onto the front of the buffer that is constructed with the provided constructor argum...
Definition: circular_buffer.h:175
circular_buffer & operator=(circular_buffer &&)=default
T & operator[](size_t index)
Definition: circular_buffer.h:251
void push_front(T value)
Push a new value onto the front of the buffer.
Definition: circular_buffer.h:134
circular_buffer(size_t size)
Definition: circular_buffer.h:20
const_iterator cbegin() const
Definition: circular_buffer.h:91
void resize(size_t size)
Resizes internal buffer to given size.
Definition: circular_buffer.inc:15
circular_buffer(const circular_buffer &)=default
circular_buffer(circular_buffer &&)=default
void reset()
Empties internal buffer.
Definition: circular_buffer.h:243
void push_back(T value)
Push a new value onto the back of the buffer.
Definition: circular_buffer.h:153
T pop_front()
Pop value at front of buffer.
Definition: circular_buffer.h:217
const T & operator[](size_t index) const
Definition: circular_buffer.h:258
const T & back() const
Returns value at back of buffer.
Definition: circular_buffer.h:125
const_iterator end() const
Definition: circular_buffer.h:87
const_iterator begin() const
Definition: circular_buffer.h:86
T & front()
Returns value at front of buffer.
Definition: circular_buffer.h:104
const_iterator cend() const
Definition: circular_buffer.h:92
const T & front() const
Returns value at front of buffer.
Definition: circular_buffer.h:109
T & back()
Returns value at back of buffer.
Definition: circular_buffer.h:117
Definition: ntcore_cpp.h:26