M5Utility 0.0.2 git rev:5c1a751
Loading...
Searching...
No Matches
circular_buffer.hpp
Go to the documentation of this file.
1/*
2 * Spdx-FileCopyrightText: 2024 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UTILITY_CONTAINER_CIRCULAR_BUFFER_HPP
11#define M5_UTILITY_CONTAINER_CIRCULAR_BUFFER_HPP
12
13#include <cstddef>
14#include <vector>
15#include <iterator>
16#include <cassert>
17#if __cplusplus >= 201703L
18#pragma message "Using std::optional"
19#include <optional>
20#else
21#pragma message "Using m5::stl::optional"
22#include "../stl/optional.hpp"
23#endif
24
25namespace m5 {
26namespace container {
27
33template <typename T>
35public:
36 using value_type = T;
37 using size_type = size_t;
38 using reference = T&;
39 using const_reference = const T&;
40#if __cplusplus >= 201703L
41 using return_type = std::optional<value_type>;
42#else
44#endif
45 class iterator;
46 class const_iterator;
47 using reverse_iterator = std::reverse_iterator<iterator>;
48 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
49
52 CircularBuffer() = delete;
53 explicit CircularBuffer(const size_t n)
54 {
55 assert(n != 0 && "Illegal size");
56 _cap = n;
57 _buf.resize(n);
58 }
59 CircularBuffer(const size_type n, const_reference value) : CircularBuffer(n)
60 {
61 assign(n, value);
62 }
63 template <class InputIter>
64 CircularBuffer(const size_type n, InputIter first, InputIter last) : CircularBuffer(n)
65 {
66 assign(first, last);
67 }
68 CircularBuffer(const size_type n, std::initializer_list<T> il) : CircularBuffer(n, il.begin(), il.end())
69 {
70 }
71
72 CircularBuffer(const CircularBuffer&) = default;
73
74 CircularBuffer(CircularBuffer&&) noexcept = default;
76
79
88 template <class InputIterator>
89 void assign(InputIterator first, InputIterator last)
90 {
91 clear();
92 size_type sz = last - first;
93 if (sz > _cap) {
94 first += (sz - _cap);
95 }
96 auto n = std::min(_cap, sz);
97 while (n--) {
98 push_back(*first++);
99 }
100 }
107 void assign(size_type n, const_reference v)
108 {
109 clear();
110 n = std::min(_cap, n);
111 while (n--) {
112 push_back(v);
113 }
114 }
119 inline void assign(std::initializer_list<T> il)
120 {
121 assign(il.begin(), il.end());
122 }
124
127
131 inline return_type front() const
132 {
133#if __cplusplus >= 201703L
134 return !empty() ? std::make_optional(_buf[_tail]) : std::nullopt;
135#else
136 return !empty() ? m5::stl::make_optional(_buf[_tail]) : m5::stl::nullopt;
137#endif
138 }
143 inline return_type back() const
144 {
145#if __cplusplus >= 201703L
146 return !empty() ? std::make_optional(_buf[(_head - 1 + _cap) % _cap]) : std::nullopt;
147#else
148 return !empty() ? m5::stl::make_optional(_buf[(_head - 1 + _cap) % _cap]) : m5::stl::nullopt;
149#endif
150 }
155 inline const_reference operator[](size_type i) const&
156 {
157 assert(size() > 0 && "container empty");
158 assert(i < size() && "index overflow");
159 return _buf[(_tail + i) % _cap];
160 }
165 inline return_type at(size_type i) const
166 {
167#if __cplusplus >= 201703L
168 return (!empty() && i < size()) ? std::make_optional(_buf[(_tail + i) % _cap]) : std::nullopt;
169#else
170 return (!empty() && i < size()) ? m5::stl::make_optional(_buf[(_tail + i) % _cap]) : m5::stl::nullopt;
171#endif
172 }
179 size_t read(value_type* outbuf, const size_t num)
180 {
181 size_t sz = std::min(num, size());
182 if (sz == 0) {
183 return sz;
184 }
185 auto tail = _tail;
186 auto src = &_buf[tail];
187 size_t elms = std::min(_cap - tail, sz);
188
189 std::copy(src, src + elms, outbuf);
190 tail = (tail + elms) % _cap;
191 size_t ret = elms;
192
193 if (elms < sz) {
194 outbuf += elms;
195 src = &_buf[tail];
196 elms = sz - elms;
197
198 std::copy(src, src + elms, outbuf);
199 ret += elms;
200 }
201 return ret;
202 }
204
207
211 inline bool empty() const
212 {
213 return !full() && (_head == _tail);
214 }
219 inline bool full() const
220 {
221 return _full;
222 }
226 inline size_type size() const
227 {
228 return full() ? _cap : (_head >= _tail ? _head - _tail : _cap + _head - _tail);
229 }
234 inline size_type capacity() const
235 {
236 return _cap;
237 }
239
242
243 void clear()
244 {
245 _full = false;
246 _head = _tail = 0U;
247 }
249 void push_front(const value_type& v)
250 {
251 _tail = (_tail - 1 + _cap) % _cap;
252 _buf[_tail] = v;
253 if (_full) {
254 _head = (_head - 1 + _cap) % _cap;
255 }
256 _full = (_head == _tail);
257 }
259 void push_back(const value_type& v)
260 {
261 _buf[_head] = v;
262 _head = (_head + 1) % _cap;
263 if (_full) {
264 _tail = (_tail + 1) % _cap;
265 }
266 _full = (_head == _tail);
267 }
269 inline void pop_front()
270 {
271 if (!empty()) {
272 _tail = (_tail + 1) % _cap;
273 _full = false;
274 }
275 }
277 inline void pop_back()
278 {
279 if (!empty()) {
280 _head = (_head - 1 + _cap) % _cap;
281 _full = false;
282 }
283 }
285
288
292 void fill(const value_type& v)
293 {
294 clear();
295 std::fill(_buf.begin(), _buf.end(), v);
296 _full = true;
297 }
303 {
304 if (this != &o) {
305 std::swap(_buf, o._buf);
306 std::swap(_cap, o._cap);
307 std::swap(_head, o._head);
308 std::swap(_tail, o._tail);
309 std::swap(_full, o._full);
310 }
311 }
313
315 class iterator {
316 public:
317 using iterator_category = std::bidirectional_iterator_tag;
318 using difference_type = std::ptrdiff_t;
319 using value_type = CircularBuffer::value_type;
320 using pointer = CircularBuffer::value_type*;
321 using reference = CircularBuffer::reference;
322
323 iterator() : _buffer(nullptr), _pos(0)
324 {
325 }
326 iterator(CircularBuffer* buf, size_t pos) : _buffer(buf), _pos(pos)
327 {
328 }
329
330 inline reference operator*() const
331 {
332 return _buffer->_buf[_pos % _buffer->capacity()];
333 }
334 inline pointer operator->() const
335 {
336 return &(_buffer->_buf[_pos % _buffer->capacity()]);
337 }
338 inline iterator& operator++()
339 {
340 ++_pos;
341 return *this;
342 }
343 inline iterator& operator--()
344 {
345 --_pos;
346 return *this;
347 }
348 inline iterator operator++(int)
349 {
350 iterator tmp = *this;
351 ++(*this);
352 return tmp;
353 }
354 inline iterator operator--(int)
355 {
356 iterator tmp = *this;
357 --(*this);
358 return tmp;
359 }
360
361 friend inline bool operator==(const iterator& a, const iterator& b)
362 {
363 return a._buffer == b._buffer && a._pos == b._pos;
364 }
365 friend inline bool operator!=(const iterator& a, const iterator& b)
366 {
367 return !(a == b);
368 }
369
370 private:
371 CircularBuffer* _buffer;
372 size_t _pos;
373 };
374
375 class const_iterator {
376 public:
377 using iterator_category = std::bidirectional_iterator_tag;
378 using difference_type = std::ptrdiff_t;
379 using value_type = CircularBuffer::value_type;
380 using pointer = const CircularBuffer::value_type*;
381 using reference = CircularBuffer::const_reference;
382
383 const_iterator() : _buffer(nullptr), _pos(0)
384 {
385 }
386 const_iterator(const CircularBuffer* buf, size_t pos) : _buffer(buf), _pos(pos)
387 {
388 }
389
390 inline reference operator*() const
391 {
392 return _buffer->_buf[_pos % _buffer->capacity()];
393 }
394 inline pointer operator->() const
395 {
396 return &(_buffer->_buf[_pos % _buffer->capacity()]);
397 }
398 inline const_iterator& operator++()
399 {
400 ++_pos;
401 return *this;
402 }
403 inline const_iterator& operator--()
404 {
405 --_pos;
406 return *this;
407 }
408 inline const_iterator operator++(int)
409 {
410 const_iterator tmp = *this;
411 ++(*this);
412 return tmp;
413 }
414 inline const_iterator operator--(int)
415 {
416 const_iterator tmp = *this;
417 --(*this);
418 return tmp;
419 }
420
421 friend inline bool operator==(const const_iterator& a, const const_iterator& b)
422 {
423 return a._buffer == b._buffer && a._pos == b._pos;
424 }
425 friend inline bool operator!=(const const_iterator& a, const const_iterator& b)
426 {
427 return !(a == b);
428 }
429
430 private:
431 const CircularBuffer* _buffer;
432 size_t _pos;
433 };
435
439 inline iterator begin() noexcept
440 {
441 return iterator(this, _tail);
442 }
443 inline iterator end() noexcept
444 {
445 return iterator(this, _tail + size());
446 }
447 inline const_iterator cbegin() const noexcept
448 {
449 return const_iterator(this, _tail);
450 }
451 inline const_iterator cend() const noexcept
452 {
453 return const_iterator(this, _tail + size());
454 }
455 inline reverse_iterator rbegin() noexcept
456 {
457 return std::reverse_iterator<iterator>(end());
458 }
459 inline reverse_iterator rend() noexcept
460 {
461 return std::reverse_iterator<iterator>(begin());
462 }
463 inline const_reverse_iterator crbegin() const noexcept
464 {
465 return std::reverse_iterator<const_iterator>(cend());
466 }
467 inline const_reverse_iterator crend() const noexcept
468 {
469 return std::reverse_iterator<const_iterator>(cbegin());
470 }
472
473private:
474 std::vector<T> _buf{};
475 size_t _cap{}, _head{}, _tail{};
476 bool _full{};
477};
478
485template <typename T, size_t N>
487public:
488 using value_type = T;
489 using size_type = size_t;
490 using reference = T&;
491 using const_reference = const T&;
492#if __cplusplus >= 201703L
493 using return_type = std::optional<value_type>;
494#else
496#endif
497
499 {
500 }
501 FixedCircularBuffer(const size_type n, const_reference value) : CircularBuffer<T>(N)
502 {
504 }
505 template <class InputIter>
506 FixedCircularBuffer(InputIter first, InputIter last) : CircularBuffer<T>(N, first, last)
507 {
508 }
509 FixedCircularBuffer(std::initializer_list<T> il) : CircularBuffer<T>(N, il)
510 {
511 }
512
515
516 FixedCircularBuffer& operator=(const FixedCircularBuffer&) = default;
517
518 FixedCircularBuffer& operator=(FixedCircularBuffer&&) noexcept = default;
519};
520
521} // namespace container
522} // namespace m5
523
524namespace std {
530template <typename T>
535} // namespace std
536
537#endif
Type CircularBuffer giving size in constructor.
Definition circular_buffer.hpp:34
void clear()
Clears the contents.
Definition circular_buffer.hpp:243
void push_front(const value_type &v)
Adds an element to the top.
Definition circular_buffer.hpp:249
void assign(std::initializer_list< T > il)
assigns values to the container
Definition circular_buffer.hpp:119
bool empty() const
checks whether the container is empty
Definition circular_buffer.hpp:211
void assign(size_type n, const_reference v)
assigns values to the container
Definition circular_buffer.hpp:107
void swap(CircularBuffer &o)
Swaps the contents.
Definition circular_buffer.hpp:302
void push_back(const value_type &v)
Adds an element to the end.
Definition circular_buffer.hpp:259
return_type front() const
Access the first element.
Definition circular_buffer.hpp:131
return_type at(size_type i) const
Access specified element with bounds checking.
Definition circular_buffer.hpp:165
return_type back() const
Access the last element.
Definition circular_buffer.hpp:143
const_reference operator[](size_type i) const &
Access specified element.
Definition circular_buffer.hpp:155
CircularBuffer & operator=(CircularBuffer &&)=default
Move.
CircularBuffer & operator=(const CircularBuffer &)=default
Copy.
void swap(m5::container::CircularBuffer< T > &a, m5::container::CircularBuffer< T > &b)
Specializes the std::swap algorithm.
Definition circular_buffer.hpp:531
void fill(const value_type &v)
Assigns the value to all elements in the container.
Definition circular_buffer.hpp:292
void pop_front()
removes the top element
Definition circular_buffer.hpp:269
void pop_back()
removes the end element
Definition circular_buffer.hpp:277
bool full() const
checks whether the container is full
Definition circular_buffer.hpp:219
void assign(InputIterator first, InputIterator last)
Replaces the contents with copies of those in the range [first, last)
Definition circular_buffer.hpp:89
size_type size() const
returns the number of elements
Definition circular_buffer.hpp:226
size_t read(value_type *outbuf, const size_t num)
Read from buffer.
Definition circular_buffer.hpp:179
size_type capacity() const
Returns the number of elements that can be held in currently storage.
Definition circular_buffer.hpp:234
Type CircularBuffer giving size in template parameter.
Definition circular_buffer.hpp:486
Definition optional.hpp:679
Container classes.
Top level namespace of M5.
Definition bit_segment.hpp:17