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