WPILibC++ 2027.0.0-alpha-3
Loading...
Searching...
No Matches
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 constexpr explicit circular_buffer(size_t size) : m_data(size, T{}) {}
28
29 constexpr circular_buffer(const circular_buffer&) = default;
30 constexpr circular_buffer& operator=(const circular_buffer&) = default;
31 constexpr circular_buffer(circular_buffer&&) = default;
32 constexpr circular_buffer& operator=(circular_buffer&&) = default;
33
34 class iterator {
35 public:
36 using iterator_category = std::bidirectional_iterator_tag;
37 using value_type = T;
38 using difference_type = std::ptrdiff_t;
39 using pointer = T*;
40 using reference = T&;
41
42 constexpr iterator(circular_buffer* buffer, size_t index)
43 : m_buffer{buffer}, m_index{index} {}
44
45 constexpr iterator& operator++() {
46 ++m_index;
47 return *this;
48 }
49 constexpr iterator operator++(int) {
50 iterator retval = *this;
51 ++(*this);
52 return retval;
53 }
54 constexpr iterator& operator--() {
55 --m_index;
56 return *this;
57 }
58 constexpr iterator operator--(int) {
59 iterator retval = *this;
60 --(*this);
61 return retval;
62 }
63 constexpr bool operator==(const iterator&) const = default;
64 constexpr reference operator*() { return (*m_buffer)[m_index]; }
65
66 private:
67 circular_buffer* m_buffer;
68 size_t m_index;
69 };
70
72 public:
73 using iterator_category = std::bidirectional_iterator_tag;
74 using value_type = T;
75 using difference_type = std::ptrdiff_t;
76 using pointer = T*;
77 using const_reference = const T&;
78
79 constexpr const_iterator(const circular_buffer* buffer, size_t index)
80 : m_buffer{buffer}, m_index{index} {}
81
83 ++m_index;
84 return *this;
85 }
86 constexpr const_iterator operator++(int) {
87 const_iterator retval = *this;
88 ++(*this);
89 return retval;
90 }
92 --m_index;
93 return *this;
94 }
95 constexpr const_iterator operator--(int) {
96 const_iterator retval = *this;
97 --(*this);
98 return retval;
99 }
100 constexpr bool operator==(const const_iterator&) const = default;
101 constexpr const_reference operator*() const { return (*m_buffer)[m_index]; }
102
103 private:
104 const circular_buffer* m_buffer;
105 size_t m_index;
106 };
107
108 using reverse_iterator = std::reverse_iterator<iterator>;
109 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
110
111 /**
112 * Returns begin iterator.
113 */
114 constexpr iterator begin() { return iterator(this, 0); }
115
116 /**
117 * Returns end iterator.
118 */
119 constexpr iterator end() {
121 }
122
123 /**
124 * Returns const begin iterator.
125 */
126 constexpr const_iterator begin() const { return const_iterator(this, 0); }
127
128 /**
129 * Returns const end iterator.
130 */
131 constexpr const_iterator end() const {
133 }
134
135 /**
136 * Returns const begin iterator.
137 */
138 constexpr const_iterator cbegin() const { return const_iterator(this, 0); }
139
140 /**
141 * Returns const end iterator.
142 */
143 constexpr const_iterator cend() const {
145 }
146
147 /**
148 * Returns reverse begin iterator.
149 */
150 constexpr reverse_iterator rbegin() { return reverse_iterator(end()); }
151
152 /**
153 * Returns reverse end iterator.
154 */
155 constexpr reverse_iterator rend() { return reverse_iterator(begin()); }
156
157 /**
158 * Returns const reverse begin iterator.
159 */
160 constexpr const_reverse_iterator rbegin() const {
161 return const_reverse_iterator(end());
162 }
163
164 /**
165 * Returns const reverse end iterator.
166 */
167 constexpr const_reverse_iterator rend() const {
169 }
170
171 /**
172 * Returns const reverse begin iterator.
173 */
174 constexpr const_reverse_iterator crbegin() const {
176 }
177
178 /**
179 * Returns const reverse end iterator.
180 */
181 constexpr const_reverse_iterator crend() const {
183 }
184
185 /**
186 * Returns number of elements in buffer
187 */
188 constexpr size_t size() const { return m_length; }
189
190 /**
191 * Returns value at front of buffer
192 */
193 constexpr T& front() { return (*this)[0]; }
194
195 /**
196 * Returns value at front of buffer
197 */
198 constexpr const T& front() const { return (*this)[0]; }
199
200 /**
201 * Returns value at back of buffer
202 *
203 * If there are no elements in the buffer, calling this function results in
204 * undefined behavior.
205 */
206 constexpr T& back() {
207 return m_data[(m_front + m_length - 1) % m_data.size()];
208 }
209
210 /**
211 * Returns value at back of buffer
212 *
213 * If there are no elements in the buffer, calling this function results in
214 * undefined behavior.
215 */
216 constexpr const T& back() const {
217 return m_data[(m_front + m_length - 1) % m_data.size()];
218 }
219
220 /**
221 * Push a new value onto the front of the buffer.
222 *
223 * The value at the back is overwritten if the buffer is full.
224 */
225 constexpr void push_front(T value) {
226 if (m_data.size() == 0) {
227 return;
228 }
229
230 m_front = ModuloDec(m_front);
231
232 m_data[m_front] = value;
233
234 if (m_length < m_data.size()) {
235 m_length++;
236 }
237 }
238
239 /**
240 * Push a new value onto the back of the buffer.
241 *
242 * The value at the front is overwritten if the buffer is full.
243 */
244 constexpr void push_back(T value) {
245 if (m_data.size() == 0) {
246 return;
247 }
248
249 m_data[(m_front + m_length) % m_data.size()] = value;
250
251 if (m_length < m_data.size()) {
252 m_length++;
253 } else {
254 // Increment front if buffer is full to maintain size
255 m_front = ModuloInc(m_front);
256 }
257 }
258
259 /**
260 * Push a new value onto the front of the buffer that is constructed with the
261 * provided constructor arguments.
262 *
263 * The value at the back is overwritten if the buffer is full.
264 */
265 template <class... Args>
266 constexpr void emplace_front(Args&&... args) {
267 if (m_data.size() == 0) {
268 return;
269 }
270
271 m_front = ModuloDec(m_front);
272
273 m_data[m_front] = T{args...};
274
275 if (m_length < m_data.size()) {
276 m_length++;
277 }
278 }
279
280 /**
281 * Push a new value onto the back of the buffer that is constructed with the
282 * provided constructor arguments.
283 *
284 * The value at the front is overwritten if the buffer is full.
285 */
286 template <class... Args>
287 constexpr void emplace_back(Args&&... args) {
288 if (m_data.size() == 0) {
289 return;
290 }
291
292 m_data[(m_front + m_length) % m_data.size()] = T{args...};
293
294 if (m_length < m_data.size()) {
295 m_length++;
296 } else {
297 // Increment front if buffer is full to maintain size
298 m_front = ModuloInc(m_front);
299 }
300 }
301
302 /**
303 * Pop value at front of buffer.
304 *
305 * If there are no elements in the buffer, calling this function results in
306 * undefined behavior.
307 */
308 constexpr T pop_front() {
309 T& temp = m_data[m_front];
310 m_front = ModuloInc(m_front);
311 m_length--;
312 return temp;
313 }
314
315 /**
316 * Pop value at back of buffer.
317 *
318 * If there are no elements in the buffer, calling this function results in
319 * undefined behavior.
320 */
321 constexpr T pop_back() {
322 m_length--;
323 return m_data[(m_front + m_length) % m_data.size()];
324 }
325
326 /**
327 * Resizes internal buffer to given size.
328 */
329 constexpr void resize(size_t size) {
330 if (size > m_data.size()) {
331 // Find end of buffer
332 size_t insertLocation = (m_front + m_length) % m_data.size();
333
334 // If insertion location precedes front of buffer, push front index back
335 if (insertLocation <= m_front) {
336 m_front += size - m_data.size();
337 }
338
339 // Add elements to end of buffer
340 m_data.insert(m_data.begin() + insertLocation, size - m_data.size(), 0);
341 } else if (size < m_data.size()) {
342 /* 1) Shift element block start at "front" left as many blocks as were
343 * removed up to but not exceeding buffer[0]
344 * 2) Shrink buffer, which will remove even more elements automatically if
345 * necessary
346 */
347 size_t elemsToRemove = m_data.size() - size;
348 auto frontIter = m_data.begin() + m_front;
349 if (m_front < elemsToRemove) {
350 /* Remove elements from end of buffer before shifting start of element
351 * block. Doing so saves a few copies.
352 */
353 m_data.erase(frontIter + size, m_data.end());
354
355 // Shift start of element block to left
356 m_data.erase(m_data.begin(), frontIter);
357
358 // Update metadata
359 m_front = 0;
360 } else {
361 // Shift start of element block to left
362 m_data.erase(frontIter - elemsToRemove, frontIter);
363
364 // Update metadata
365 m_front -= elemsToRemove;
366 }
367
368 /* Length only changes during a shrink if all unused spaces have been
369 * removed. Length decreases as used spaces are removed to meet the
370 * required size.
371 */
372 if (m_length > size) {
373 m_length = size;
374 }
375 }
376 }
377
378 /**
379 * Empties internal buffer.
380 */
381 constexpr void reset() {
382 m_front = 0;
383 m_length = 0;
384 }
385
386 /**
387 * @return Element at index starting from front of buffer.
388 */
389 constexpr T& operator[](size_t index) {
390 return m_data[(m_front + index) % m_data.size()];
391 }
392
393 /**
394 * @return Element at index starting from front of buffer.
395 */
396 constexpr const T& operator[](size_t index) const {
397 return m_data[(m_front + index) % m_data.size()];
398 }
399
400 private:
401 std::vector<T> m_data;
402
403 // Index of element at front of buffer
404 size_t m_front = 0;
405
406 // Number of elements used in buffer
407 size_t m_length = 0;
408
409 /**
410 * Increment an index modulo the size of the buffer.
411 *
412 * @param index Index into the buffer.
413 * @return The incremented index.
414 */
415 constexpr size_t ModuloInc(size_t index) {
416 return (index + 1) % m_data.size();
417 }
418
419 /**
420 * Decrement an index modulo the size of the buffer.
421 *
422 * @param index Index into the buffer.
423 * @return The decremented index.
424 */
425 constexpr size_t ModuloDec(size_t index) {
426 if (index == 0) {
427 return m_data.size() - 1;
428 } else {
429 return index - 1;
430 }
431 }
432};
433
434} // namespace wpi
Definition circular_buffer.h:71
constexpr const_iterator & operator++()
Definition circular_buffer.h:82
constexpr const_iterator(const circular_buffer *buffer, size_t index)
Definition circular_buffer.h:79
std::ptrdiff_t difference_type
Definition circular_buffer.h:75
constexpr const_iterator & operator--()
Definition circular_buffer.h:91
constexpr const_iterator operator--(int)
Definition circular_buffer.h:95
T value_type
Definition circular_buffer.h:74
const T & const_reference
Definition circular_buffer.h:77
constexpr const_iterator operator++(int)
Definition circular_buffer.h:86
T * pointer
Definition circular_buffer.h:76
constexpr bool operator==(const const_iterator &) const =default
constexpr const_reference operator*() const
Definition circular_buffer.h:101
std::bidirectional_iterator_tag iterator_category
Definition circular_buffer.h:73
Definition circular_buffer.h:34
constexpr bool operator==(const iterator &) const =default
constexpr iterator operator++(int)
Definition circular_buffer.h:49
constexpr reference operator*()
Definition circular_buffer.h:64
std::ptrdiff_t difference_type
Definition circular_buffer.h:38
std::bidirectional_iterator_tag iterator_category
Definition circular_buffer.h:36
constexpr iterator & operator++()
Definition circular_buffer.h:45
T & reference
Definition circular_buffer.h:40
constexpr iterator operator--(int)
Definition circular_buffer.h:58
T * pointer
Definition circular_buffer.h:39
constexpr iterator & operator--()
Definition circular_buffer.h:54
constexpr iterator(circular_buffer *buffer, size_t index)
Definition circular_buffer.h:42
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
constexpr T & operator[](size_t index)
Definition circular_buffer.h:389
constexpr const_iterator cend() const
Returns const end iterator.
Definition circular_buffer.h:143
constexpr const T & operator[](size_t index) const
Definition circular_buffer.h:396
constexpr T pop_front()
Pop value at front of buffer.
Definition circular_buffer.h:308
constexpr T & back()
Returns value at back of buffer.
Definition circular_buffer.h:206
std::reverse_iterator< iterator > reverse_iterator
Definition circular_buffer.h:108
constexpr const_reverse_iterator rend() const
Returns const reverse end iterator.
Definition circular_buffer.h:167
constexpr const T & back() const
Returns value at back of buffer.
Definition circular_buffer.h:216
constexpr circular_buffer & operator=(const circular_buffer &)=default
constexpr void reset()
Empties internal buffer.
Definition circular_buffer.h:381
constexpr 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:287
constexpr const_iterator end() const
Returns const end iterator.
Definition circular_buffer.h:131
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition circular_buffer.h:109
constexpr 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:266
constexpr reverse_iterator rend()
Returns reverse end iterator.
Definition circular_buffer.h:155
constexpr const_reverse_iterator crbegin() const
Returns const reverse begin iterator.
Definition circular_buffer.h:174
constexpr const_iterator cbegin() const
Returns const begin iterator.
Definition circular_buffer.h:138
constexpr T & front()
Returns value at front of buffer.
Definition circular_buffer.h:193
constexpr reverse_iterator rbegin()
Returns reverse begin iterator.
Definition circular_buffer.h:150
constexpr T pop_back()
Pop value at back of buffer.
Definition circular_buffer.h:321
constexpr circular_buffer(circular_buffer &&)=default
constexpr iterator end()
Returns end iterator.
Definition circular_buffer.h:119
constexpr void push_front(T value)
Push a new value onto the front of the buffer.
Definition circular_buffer.h:225
constexpr iterator begin()
Returns begin iterator.
Definition circular_buffer.h:114
constexpr const_iterator begin() const
Returns const begin iterator.
Definition circular_buffer.h:126
constexpr const_reverse_iterator crend() const
Returns const reverse end iterator.
Definition circular_buffer.h:181
constexpr circular_buffer(size_t size)
Constructs a circular buffer.
Definition circular_buffer.h:27
constexpr void resize(size_t size)
Resizes internal buffer to given size.
Definition circular_buffer.h:329
constexpr circular_buffer & operator=(circular_buffer &&)=default
constexpr void push_back(T value)
Push a new value onto the back of the buffer.
Definition circular_buffer.h:244
constexpr size_t size() const
Returns number of elements in buffer.
Definition circular_buffer.h:188
constexpr const T & front() const
Returns value at front of buffer.
Definition circular_buffer.h:198
constexpr const_reverse_iterator rbegin() const
Returns const reverse begin iterator.
Definition circular_buffer.h:160
constexpr circular_buffer(const circular_buffer &)=default
Definition ntcore_cpp.h:26