emlabcpp
modern opinionated embedded C++ library
static_circular_buffer.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "./iterator.h"
27 #include "./static_storage.h"
28 #include "./view.h"
29 
30 #include <limits>
31 
32 namespace emlabcpp
33 {
34 
35 template < typename T >
36 class static_circular_buffer_iterator;
37 
49 template < typename T, std::size_t N >
51 {
52 
53 public:
54  static constexpr std::size_t max_size = N;
55 
56  // XXX: derive this
57  using index_type = int32_t;
58 
59  static_assert(
61  "static_circular_buffer: N must be less than index_type max value" );
62 
63  using value_type = T;
64  using size_type = uint32_t;
65  using reference = T&;
66  using const_reference = T const&;
69 
70  static_circular_buffer() noexcept = default;
71 
73  {
74  copy_from( other );
75  }
76 
78  {
79  move_from( other );
80  other.clear();
81  }
82 
84  {
85  if ( this == &other )
86  return *this;
87  clear();
88  copy_from( other );
89  return *this;
90  }
91 
93  {
94  if ( this == &other )
95  return *this;
96  clear();
97  move_from( other );
98  other.clear();
99  return *this;
100  }
101 
103 
104  [[nodiscard]] iterator begin()
105  {
106  return iterator{ storage_.data(), storage_.data() + N, storage_.data() + from_ };
107  }
108 
109  [[nodiscard]] const_iterator begin() const
110  {
111  return const_iterator{
112  storage_.data(), storage_.data() + N, storage_.data() + from_ };
113  }
114 
115  [[nodiscard]] std::reverse_iterator< iterator > rbegin()
116  {
117  return std::make_reverse_iterator( end() );
118  };
119 
120  [[nodiscard]] std::reverse_iterator< const_iterator > rbegin() const
121  {
122  return std::make_reverse_iterator( end() );
123  };
124 
125  [[nodiscard]] reference front()
126  {
127  return storage_[static_cast< size_type >( from_ )];
128  }
129 
130  [[nodiscard]] const_reference front() const
131  {
132  return storage_[static_cast< size_type >( from_ )];
133  }
134 
135  [[nodiscard]] T take_front()
136  {
137  T item = std::move( front() );
138  pop_front();
139  return item;
140  }
141 
142  void pop_front()
143  {
144  storage_.delete_item( static_cast< size_type >( from_ ) );
145  from_ = next( from_ );
146  if ( from_ == to_ )
147  from_ = -1;
148  }
149 
151  {
152  for ( size_type i = 0; i < n; i++ )
153  pop_front();
154  }
155 
157 
158  [[nodiscard]] iterator end()
159  {
160  return iterator{ storage_.data(), storage_.data() + N, storage_.data() + to_ };
161  }
162 
163  [[nodiscard]] const_iterator end() const
164  {
165  return const_iterator{
166  storage_.data(), storage_.data() + N, storage_.data() + to_ };
167  }
168 
169  [[nodiscard]] std::reverse_iterator< iterator > rend()
170  {
171  return std::make_reverse_iterator( begin() );
172  };
173 
174  [[nodiscard]] std::reverse_iterator< const_iterator > rend() const
175  {
176  return std::make_reverse_iterator( begin() );
177  };
178 
179  [[nodiscard]] reference back()
180  {
181  return storage_[static_cast< size_type >( prev( to_ ) )];
182  }
183 
184  [[nodiscard]] const_reference back() const
185  {
186  return storage_[static_cast< size_type >( prev( to_ ) )];
187  }
188 
189  void push_back( T item )
190  {
191  emplace_back( std::move( item ) );
192  }
193 
194  template < typename... Args >
195  T& emplace_back( Args&&... args )
196  {
197  T& ref = storage_.emplace_item(
198  static_cast< size_type >( to_ ), std::forward< Args >( args )... );
199  if ( from_ == -1 )
200  from_ = to_;
201  to_ = next( to_ );
202  return ref;
203  }
204 
206 
207  [[nodiscard]] constexpr size_type capacity() const
208  {
209  return N;
210  }
211 
212  [[nodiscard]] size_type size() const
213  {
214  if ( from_ == -1 )
215  return 0;
216  auto t = static_cast< size_type >( to_ );
217  auto f = static_cast< size_type >( from_ );
218  if ( t >= f )
219  return t - f;
220  return t + ( N - f );
221  }
222 
223  [[nodiscard]] bool empty() const
224  {
225  return from_ == -1;
226  }
227 
228  [[nodiscard]] bool full() const
229  {
230  return from_ != -1 && to_ == from_;
231  }
232 
233  void clear()
234  {
235  purge();
236  }
237 
239  {
240  purge();
241  }
242 
243 private:
244  static_storage< T, N > storage_;
245  index_type from_ = -1;
246  index_type to_ = 0;
247 
248  void purge()
249  {
250  while ( !empty() )
251  pop_front();
252  }
253 
254  void copy_from( static_circular_buffer const& other )
255  {
256  from_ = 0;
257  to_ = static_cast< index_type >( other.size() );
258  size_type i = 0;
259  for ( T const& item : other )
260  storage_.emplace_item( i++, item );
261  }
262 
263  void move_from( static_circular_buffer& other ) noexcept
264  {
265  static_assert( std::is_nothrow_move_constructible_v< T > );
266  from_ = 0;
267  to_ = static_cast< index_type >( other.size() );
268  size_type i = 0;
269  for ( T& item : other )
270  storage_.emplace_item( i++, std::move( item ) );
271  }
272 
274  [[nodiscard]] static constexpr index_type next( index_type const i ) noexcept
275  {
276  return static_cast< size_type >( i + 1 ) % N;
277  }
278 
279  [[nodiscard]] static constexpr index_type prev( index_type const i ) noexcept
280  {
281  return i == 0 ? N - 1 : i - 1;
282  }
283 
284  template < typename U >
286 };
287 
288 template < typename T, std::size_t N >
289 [[nodiscard]] auto
291 {
292  return std::lexicographical_compare_three_way( lh.begin(), lh.end(), rh.begin(), rh.end() );
293 }
294 
295 template < typename T, std::size_t N >
296 [[nodiscard]] bool
298 {
299  auto size = lh.size();
300  if ( size != rh.size() )
301  return false;
302 
303  return std::equal( lh.begin(), lh.end(), rh.begin() );
304 }
305 
306 template < typename T, std::size_t N >
307 [[nodiscard]] bool
309 {
310  return !( lh == rh );
311 }
312 
313 #ifdef EMLABCPP_USE_OSTREAM
315 template < typename T, std::size_t N >
316 std::ostream& operator<<( std::ostream& os, static_circular_buffer< T, N > const& cb )
317 {
318  return os << view{ cb };
319 }
320 #endif
321 
322 } // namespace emlabcpp
323 
324 template < typename T >
325 struct std::iterator_traits< emlabcpp::static_circular_buffer_iterator< T > >
326 {
327  using value_type = T;
328  using difference_type = std::make_signed_t< std::size_t >;
329  using pointer = value_type*;
330  using const_pointer = value_type const*;
332  using iterator_category = std::bidirectional_iterator_tag;
333 };
334 
335 namespace emlabcpp
336 {
337 
338 template < typename T >
340  : public generic_iterator< static_circular_buffer_iterator< T > >
341 {
342 public:
343  static constexpr bool is_const = std::is_const_v< T >;
344  using value_type = T;
345  using reference = std::conditional_t< is_const, value_type const&, value_type& >;
346  using const_reference = value_type const&;
348  typename std::iterator_traits< static_circular_buffer_iterator< T > >::difference_type;
349 
350  static_circular_buffer_iterator( T* beg, T* end, T* p ) noexcept
351  : beg_( beg )
352  , end_( end )
353  , p_( p )
354  {
355  }
356 
358  default;
360 
362  operator=( static_circular_buffer_iterator const& ) noexcept = default;
364  operator=( static_circular_buffer_iterator&& ) noexcept = default;
365 
366  reference operator*() noexcept
367  {
368  return *p_;
369  }
370 
371  reference operator*() const noexcept
372  {
373  return *p_;
374  }
375 
377  {
378  p_++;
379  if ( p_ == end_ )
380  p_ = beg_;
381  return *this;
382  }
383 
385  {
386  if ( p_ == beg_ )
387  p_ = end_;
388  return *this;
389  }
390 
391  auto operator<=>( static_circular_buffer_iterator const& other ) const noexcept
392  {
393  return p_ <=> other.p_;
394  }
395 
396  bool operator==( static_circular_buffer_iterator const& other ) const noexcept
397  {
398  return p_ == other.p_;
399  }
400 
401 private:
402  T* beg_;
403  T* end_;
404  T* p_;
405 };
406 
407 } // namespace emlabcpp
Definition: static_circular_buffer.h:341
static constexpr bool is_const
Definition: static_circular_buffer.h:343
static_circular_buffer_iterator(static_circular_buffer_iterator const &) noexcept=default
static_circular_buffer_iterator(T *beg, T *end, T *p) noexcept
Definition: static_circular_buffer.h:350
static_circular_buffer_iterator & operator--() noexcept
Definition: static_circular_buffer.h:384
value_type const & const_reference
Definition: static_circular_buffer.h:346
reference operator*() const noexcept
Definition: static_circular_buffer.h:371
typename std::iterator_traits< static_circular_buffer_iterator< T > >::difference_type difference_type
Definition: static_circular_buffer.h:348
static_circular_buffer_iterator(static_circular_buffer_iterator &&) noexcept=default
bool operator==(static_circular_buffer_iterator const &other) const noexcept
Definition: static_circular_buffer.h:396
static_circular_buffer_iterator & operator++() noexcept
Definition: static_circular_buffer.h:376
std::conditional_t< is_const, value_type const &, value_type & > reference
Definition: static_circular_buffer.h:345
T value_type
Definition: static_circular_buffer.h:344
auto operator<=>(static_circular_buffer_iterator const &other) const noexcept
Definition: static_circular_buffer.h:391
Class implementing circular buffer of any type for up to N elements.
Definition: static_circular_buffer.h:51
const_reference back() const
Definition: static_circular_buffer.h:184
T value_type
Definition: static_circular_buffer.h:63
void pop_front(size_type n)
Definition: static_circular_buffer.h:150
std::reverse_iterator< iterator > rbegin()
Definition: static_circular_buffer.h:115
constexpr size_type capacity() const
other methods
Definition: static_circular_buffer.h:207
size_type size() const
Definition: static_circular_buffer.h:212
T & reference
Definition: static_circular_buffer.h:65
bool empty() const
Definition: static_circular_buffer.h:223
void clear()
Definition: static_circular_buffer.h:233
reference back()
Definition: static_circular_buffer.h:179
static_circular_buffer() noexcept=default
std::reverse_iterator< iterator > rend()
Definition: static_circular_buffer.h:169
static_circular_buffer(static_circular_buffer &&other) noexcept
Definition: static_circular_buffer.h:77
const_iterator begin() const
Definition: static_circular_buffer.h:109
static_circular_buffer & operator=(static_circular_buffer const &other)
Definition: static_circular_buffer.h:83
std::reverse_iterator< const_iterator > rbegin() const
Definition: static_circular_buffer.h:120
uint32_t size_type
Definition: static_circular_buffer.h:64
T take_front()
Definition: static_circular_buffer.h:135
const_iterator end() const
Definition: static_circular_buffer.h:163
T & emplace_back(Args &&... args)
Definition: static_circular_buffer.h:195
iterator end()
methods for handling the back side of the circular buffer
Definition: static_circular_buffer.h:158
void pop_front()
Definition: static_circular_buffer.h:142
T const & const_reference
Definition: static_circular_buffer.h:66
reference front()
Definition: static_circular_buffer.h:125
bool full() const
Definition: static_circular_buffer.h:228
const_reference front() const
Definition: static_circular_buffer.h:130
static constexpr std::size_t max_size
Definition: static_circular_buffer.h:54
void push_back(T item)
Definition: static_circular_buffer.h:189
~static_circular_buffer()
Definition: static_circular_buffer.h:238
static_circular_buffer & operator=(static_circular_buffer &&other) noexcept
Definition: static_circular_buffer.h:92
int32_t index_type
Definition: static_circular_buffer.h:57
std::reverse_iterator< const_iterator > rend() const
Definition: static_circular_buffer.h:174
iterator begin()
methods for handling the front side of the circular buffer
Definition: static_circular_buffer.h:104
MIT License.
Definition: impl.h:31
view(Container &cont) -> view< iterator_of_t< Container > >
The container deduction guide uses iterator_of_t.
constexpr bool equal(LhContainer &&lh, RhContainer &&rh, BinaryPredicateCallable &&f=std::equal_to< void >{})
Returns true if containers 'lh' and 'rh' has same size and calls to predicate f - f(lh[i],...
Definition: algorithm.h:356
Args const & args
Definition: min_max.h:83
constexpr Derived max(vec_point_base< Derived, N > const &a, vec_point_base< Derived, N > const &b)
Definition: vec_point_base.h:229
auto operator<=>(static_circular_buffer< T, N > const &lh, static_circular_buffer< T, N > const &rh)
Definition: static_circular_buffer.h:290
constexpr bool operator!=(pose const &x, pose const &y)
negation of operator== between poses
Definition: pose.h:99
std::ostream & operator<<(std::ostream &os, string_buffer< N > const &sb)
Definition: string_buffer.h:112
UnaryCallable && f
Definition: algorithm.h:161
N
Definition: static_storage.h:97
constexpr bool operator==(pose const &x, pose const &y)
compares poses on their position and orientation
Definition: pose.h:93
generic_iterator simplifies custom iterator implementation using CRTP.
Definition: iterator.h:62
Continuous data container that can contain N of uninitialized elements.
Definition: static_storage.h:37
constexpr T & emplace_item(size_type const i, Args &&... args) noexcept(std::is_nothrow_constructible_v< T, Args... >)
Constructs an item at position i with arguments args...
Definition: static_storage.h:61
std::bidirectional_iterator_tag iterator_category
Definition: static_circular_buffer.h:332
std::make_signed_t< std::size_t > difference_type
Definition: static_circular_buffer.h:328
value_type * pointer
Definition: static_circular_buffer.h:329
value_type & reference
Definition: static_circular_buffer.h:331
value_type const * const_pointer
Definition: static_circular_buffer.h:330