WPILibC++ 2023.4.3-108-ge5452e3
static_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 <array>
8#include <cstddef>
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, size_t N>
18 public:
19 static_assert(N > 0, "Circular buffer size cannot be zero.");
20
21 class iterator {
22 public:
23 using iterator_category = std::forward_iterator_tag;
24 using value_type = T;
25 using difference_type = std::ptrdiff_t;
26 using pointer = T*;
27 using reference = T&;
28
30 : m_buffer(buffer), m_index(index) {}
31
33 ++m_index;
34 return *this;
35 }
37 iterator retval = *this;
38 ++(*this);
39 return retval;
40 }
41 bool operator==(const iterator&) const = default;
42 reference operator*() { return (*m_buffer)[m_index]; }
43
44 private:
45 static_circular_buffer* m_buffer;
46 size_t m_index;
47 };
48
50 public:
51 using iterator_category = std::forward_iterator_tag;
52 using value_type = T;
53 using difference_type = std::ptrdiff_t;
54 using pointer = T*;
55 using const_reference = const T&;
56
58 : m_buffer(buffer), m_index(index) {}
59
61 ++m_index;
62 return *this;
63 }
65 const_iterator retval = *this;
66 ++(*this);
67 return retval;
68 }
69 bool operator==(const const_iterator&) const = default;
70 const_reference operator*() const { return (*m_buffer)[m_index]; }
71
72 private:
73 const static_circular_buffer* m_buffer;
74 size_t m_index;
75 };
76
77 /**
78 * Returns begin iterator.
79 */
80 iterator begin() { return iterator(this, 0); }
81
82 /**
83 * Returns end iterator.
84 */
87 }
88
89 /**
90 * Returns begin iterator.
91 */
92 const_iterator begin() const { return const_iterator(this, 0); }
93
94 /**
95 * Returns end iterator.
96 */
99 }
100
101 /**
102 * Returns begin iterator.
103 */
104 const_iterator cbegin() const { return const_iterator(this, 0); }
105
106 /**
107 * Returns end iterator.
108 */
111 }
112
113 /**
114 * Returns number of elements in buffer
115 */
116 size_t size() const { return m_length; }
117
118 /**
119 * Returns value at front of buffer
120 */
121 T& front() { return (*this)[0]; }
122
123 /**
124 * Returns value at front of buffer
125 */
126 const T& front() const { return (*this)[0]; }
127
128 /**
129 * Returns value at back of buffer
130 *
131 * If there are no elements in the buffer, calling this function results in
132 * undefined behavior.
133 */
134 T& back() { return m_data[(m_front + m_length - 1) % N]; }
135
136 /**
137 * Returns value at back of buffer
138 *
139 * If there are no elements in the buffer, calling this function results in
140 * undefined behavior.
141 */
142 const T& back() const { return m_data[(m_front + m_length - 1) % N]; }
143
144 /**
145 * Push a new value onto the front of the buffer.
146 *
147 * The value at the back is overwritten if the buffer is full.
148 */
150 m_front = ModuloDec(m_front);
151
152 m_data[m_front] = value;
153
154 if (m_length < N) {
155 m_length++;
156 }
157 }
158
159 /**
160 * Push a new value onto the back of the buffer.
161 *
162 * The value at the front is overwritten if the buffer is full.
163 */
164 void push_back(T value) {
165 m_data[(m_front + m_length) % N] = value;
166
167 if (m_length < N) {
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 m_front = ModuloDec(m_front);
184
185 m_data[m_front] = T{args...};
186
187 if (m_length < N) {
188 m_length++;
189 }
190 }
191
192 /**
193 * Push a new value onto the back of the buffer that is constructed with the
194 * provided constructor arguments.
195 *
196 * The value at the front is overwritten if the buffer is full.
197 */
198 template <class... Args>
199 void emplace_back(Args&&... args) {
200 m_data[(m_front + m_length) % N] = T{args...};
201
202 if (m_length < N) {
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) % N];
232 }
233
234 /**
235 * Empties internal buffer.
236 */
237 void reset() {
238 m_front = 0;
239 m_length = 0;
240 }
241
242 /**
243 * @return Element at index starting from front of buffer.
244 */
245 T& operator[](size_t index) { return m_data[(m_front + index) % N]; }
246
247 /**
248 * @return Element at index starting from front of buffer.
249 */
250 const T& operator[](size_t index) const {
251 return m_data[(m_front + index) % N];
252 }
253
254 private:
255 std::array<T, N> m_data;
256
257 // Index of element at front of buffer
258 size_t m_front = 0;
259
260 // Number of elements used in buffer
261 size_t m_length = 0;
262
263 /**
264 * Increment an index modulo the length of the buffer.
265 *
266 * @return The result of the modulo operation.
267 */
268 size_t ModuloInc(size_t index) { return (index + 1) % N; }
269
270 /**
271 * Decrement an index modulo the length of the buffer.
272 *
273 * @return The result of the modulo operation.
274 */
275 size_t ModuloDec(size_t index) {
276 if (index == 0) {
277 return N - 1;
278 } else {
279 return index - 1;
280 }
281 }
282};
283
284} // namespace wpi
\rst A contiguous memory buffer with an optional growing ability.
Definition: core.h:862
Definition: core.h:1240
Definition: static_circular_buffer.h:49
std::forward_iterator_tag iterator_category
Definition: static_circular_buffer.h:51
const_iterator(const static_circular_buffer *buffer, size_t index)
Definition: static_circular_buffer.h:57
bool operator==(const const_iterator &) const =default
const_iterator operator++(int)
Definition: static_circular_buffer.h:64
const_iterator & operator++()
Definition: static_circular_buffer.h:60
const_reference operator*() const
Definition: static_circular_buffer.h:70
const T & const_reference
Definition: static_circular_buffer.h:55
T * pointer
Definition: static_circular_buffer.h:54
T value_type
Definition: static_circular_buffer.h:52
std::ptrdiff_t difference_type
Definition: static_circular_buffer.h:53
Definition: static_circular_buffer.h:21
iterator operator++(int)
Definition: static_circular_buffer.h:36
T value_type
Definition: static_circular_buffer.h:24
reference operator*()
Definition: static_circular_buffer.h:42
std::ptrdiff_t difference_type
Definition: static_circular_buffer.h:25
bool operator==(const iterator &) const =default
T & reference
Definition: static_circular_buffer.h:27
iterator & operator++()
Definition: static_circular_buffer.h:32
iterator(static_circular_buffer *buffer, size_t index)
Definition: static_circular_buffer.h:29
T * pointer
Definition: static_circular_buffer.h:26
std::forward_iterator_tag iterator_category
Definition: static_circular_buffer.h:23
This is a simple circular buffer so we don't need to "bucket brigade" copy old values.
Definition: static_circular_buffer.h:17
const T & back() const
Returns value at back of buffer.
Definition: static_circular_buffer.h:142
T & operator[](size_t index)
Definition: static_circular_buffer.h:245
iterator end()
Returns end iterator.
Definition: static_circular_buffer.h:85
void emplace_back(Args &&... args)
Push a new value onto the back of the buffer that is constructed with the provided constructor argume...
Definition: static_circular_buffer.h:199
void push_front(T value)
Push a new value onto the front of the buffer.
Definition: static_circular_buffer.h:149
void reset()
Empties internal buffer.
Definition: static_circular_buffer.h:237
T & back()
Returns value at back of buffer.
Definition: static_circular_buffer.h:134
T pop_back()
Pop value at back of buffer.
Definition: static_circular_buffer.h:229
T pop_front()
Pop value at front of buffer.
Definition: static_circular_buffer.h:216
void push_back(T value)
Push a new value onto the back of the buffer.
Definition: static_circular_buffer.h:164
const_iterator end() const
Returns end iterator.
Definition: static_circular_buffer.h:97
const T & operator[](size_t index) const
Definition: static_circular_buffer.h:250
const_iterator begin() const
Returns begin iterator.
Definition: static_circular_buffer.h:92
const_iterator cbegin() const
Returns begin iterator.
Definition: static_circular_buffer.h:104
const T & front() const
Returns value at front of buffer.
Definition: static_circular_buffer.h:126
void emplace_front(Args &&... args)
Push a new value onto the front of the buffer that is constructed with the provided constructor argum...
Definition: static_circular_buffer.h:182
iterator begin()
Returns begin iterator.
Definition: static_circular_buffer.h:80
const_iterator cend() const
Returns end iterator.
Definition: static_circular_buffer.h:109
size_t size() const
Returns number of elements in buffer.
Definition: static_circular_buffer.h:116
T & front()
Returns value at front of buffer.
Definition: static_circular_buffer.h:121
Definition: AprilTagFieldLayout.h:18