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