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