baudvine::RingBuf
STL-like ring buffer in C++11
ringbuf.h
Go to the documentation of this file.
1 // Copyright © 2021 Dominic van Berkel <dominic@baudvine.net>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
40 #pragma once
41 
42 #include <algorithm>
43 #include <cassert>
44 #include <cstddef>
45 #include <iterator>
46 #include <memory>
47 #include <stdexcept>
48 #include <tuple>
49 #include <type_traits>
50 
52 namespace baudvine {
53 namespace detail {
54 namespace ringbuf {
55 
57 template <typename Allocator>
58 void MoveAllocator(Allocator& lhs,
59  Allocator& rhs,
60  std::true_type /*propagate*/) {
61  // Swap instead of move-assign because data_ & co are also swapped, and the
62  // moved-from ringbuf will need to be able to clean that up.
63  std::swap(lhs, rhs);
64 }
65 
67 template <typename Allocator>
68 void MoveAllocator(Allocator& /*lhs*/,
69  Allocator& /*rhs*/,
70  std::false_type /*propagate*/) noexcept {}
71 
73 template <typename Allocator>
74 void MoveAllocator(Allocator& lhs, Allocator& rhs) {
75  using AllocTraits = std::allocator_traits<Allocator>;
76  using Propagate =
77  typename AllocTraits::propagate_on_container_move_assignment;
78  MoveAllocator(lhs, rhs, Propagate{});
79 }
80 
82 template <typename Allocator>
83 void SwapAllocator(Allocator& lhs,
84  Allocator& rhs,
85  std::true_type /*propagate*/) {
86  std::swap(lhs, rhs);
87 }
88 
90 template <typename Allocator>
91 void SwapAllocator(Allocator& /*lhs*/,
92  Allocator& /*rhs*/,
93  std::false_type /*propagate*/) {}
94 
96 template <typename Allocator>
97 void SwapAllocator(Allocator& lhs, Allocator& rhs) {
98  using AllocTraits = std::allocator_traits<Allocator>;
99  using Propagate = typename AllocTraits::propagate_on_container_swap;
100  SwapAllocator(lhs, rhs, Propagate{});
101 }
102 
104 template <typename Allocator>
105 void CopyAllocator(Allocator& lhs,
106  const Allocator& rhs,
107  std::true_type /*propagate*/) {
108  lhs = rhs;
109 }
110 
112 template <typename Allocator>
113 void CopyAllocator(Allocator& /*lhs*/,
114  const Allocator& /*rhs*/,
115  std::false_type /*propagate*/) {}
116 
118 template <typename Allocator>
119 void CopyAllocator(Allocator& lhs, const Allocator& rhs) {
120  using AllocTraits = std::allocator_traits<Allocator>;
121  using Propagate =
122  typename AllocTraits::propagate_on_container_copy_assignment;
123  CopyAllocator(lhs, rhs, Propagate{});
124 }
125 
136 template <std::size_t Capacity>
137 constexpr std::size_t RingWrap(const std::size_t ring_index) {
138  // This is a bit faster than `return ring_index % Capacity` (~40% reduction in
139  // Speed.PushBackOverFull test)
140  return (ring_index <= Capacity) ? ring_index : ring_index - Capacity - 1;
141 }
142 
153 template <typename Ptr, typename AllocTraits, std::size_t Capacity>
154 class Iterator {
155  public:
156  using difference_type = typename AllocTraits::difference_type;
157  using size_type = typename AllocTraits::difference_type;
158  using value_type = typename AllocTraits::value_type;
159  using pointer = Ptr;
160  using reference = decltype(*pointer{});
161  using iterator_category = std::random_access_iterator_tag;
162 
163  constexpr Iterator() noexcept = default;
172  Iterator(pointer data,
173  const size_type ring_offset,
174  const size_type ring_index)
175  : data_(data), ring_offset_(ring_offset), ring_index_(ring_index) {}
176 
182  operator Iterator<typename AllocTraits::const_pointer,
183  AllocTraits,
184  Capacity>() const {
186  data_, ring_offset_, ring_index_);
187  }
188 
189  reference operator*() const {
190  return data_[RingWrap<Capacity>(ring_offset_ + ring_index_)];
191  }
192 
193  pointer operator->() const noexcept { return &**this; }
194 
195  Iterator operator++(int) noexcept {
196  Iterator copy(*this);
197  operator++();
198  return copy;
199  }
200 
201  Iterator& operator++() noexcept {
202  ++ring_index_;
203  return *this;
204  }
205 
206  Iterator operator--(int) noexcept {
207  Iterator copy(*this);
208  operator--();
209  return copy;
210  }
211 
212  Iterator& operator--() noexcept {
213  --ring_index_;
214  return *this;
215  }
216 
217  Iterator& operator+=(difference_type n) noexcept {
218  ring_index_ += n;
219  return *this;
220  }
221 
222  Iterator operator+(difference_type n) const noexcept {
223  return Iterator(data_, ring_offset_, ring_index_ + n);
224  }
225 
226  Iterator& operator-=(difference_type n) noexcept {
227  ring_index_ -= n;
228  return *this;
229  }
230 
231  Iterator operator-(difference_type n) const noexcept {
232  return Iterator(data_, ring_offset_, ring_index_ - n);
233  }
234 
235  reference operator[](difference_type n) const { return *(*this + n); }
236 
237  friend difference_type operator-(const Iterator& lhs,
238  const Iterator& rhs) noexcept {
239  return lhs.ring_index_ > rhs.ring_index_
240  ? lhs.ring_index_ - rhs.ring_index_
241  : -(rhs.ring_index_ - lhs.ring_index_);
242  }
243 
244  friend Iterator operator+(difference_type lhs, const Iterator& rhs) noexcept {
245  return rhs + lhs;
246  }
247 
248  friend bool operator<(const Iterator& lhs, const Iterator& rhs) noexcept {
249  // Comparison via std::tie uses std::tuple::operator<, which compares its
250  // elements lexicographically.
251  return std::tie(lhs.data_, lhs.ring_offset_, lhs.ring_index_) <
252  std::tie(rhs.data_, rhs.ring_offset_, rhs.ring_index_);
253  }
254 
255  friend bool operator>(const Iterator& lhs, const Iterator& rhs) noexcept {
256  return rhs < lhs;
257  }
258 
259  friend bool operator<=(const Iterator& lhs, const Iterator& rhs) noexcept {
260  return !(rhs < lhs);
261  }
262 
263  friend bool operator>=(const Iterator& lhs, const Iterator& rhs) noexcept {
264  return !(lhs < rhs);
265  }
266 
267  friend bool operator==(const Iterator& lhs, const Iterator& rhs) noexcept {
268  return &*lhs == &*rhs;
269  }
270 
271  friend bool operator!=(const Iterator& lhs, const Iterator& rhs) noexcept {
272  return !(lhs == rhs);
273  }
274 
275  template <typename P, typename A, std::size_t C, typename OutputIt>
276  // https://github.com/llvm/llvm-project/issues/47430
277  // NOLINTNEXTLINE(readability-redundant-declaration)
278  friend OutputIt copy(const Iterator<P, A, C>& begin,
279  const Iterator<P, A, C>& end,
280  OutputIt out);
281 
282  private:
283  pointer data_{};
284 
285  // Keeping both ring_offset_ and ring_index_ around is a little redundant,
286  // algorithmically, but it makes it much easier to express iterator-mutating
287  // operations.
288 
289  // Physical index of begin().
290  size_type ring_offset_{};
291  // Logical index of this iterator.
292  size_type ring_index_{};
293 };
294 
299 template <typename Ptr,
300  typename AllocTraits,
301  std::size_t Capacity,
302  typename OutputIt>
303 OutputIt copy(const Iterator<Ptr, AllocTraits, Capacity>& begin,
304  const Iterator<Ptr, AllocTraits, Capacity>& end,
305  OutputIt out) {
306  assert(begin <= end);
307 
308  if (begin == end) {
309  // Empty range, pass
310  } else if (&*end > &*begin) {
311  // Fully contiguous range.
312  out = std::copy(&*begin, &*end, out);
313  } else {
314  // Copy in two sections.
315  out = std::copy(&*begin, &begin.data_[Capacity + 1], out);
316  out = std::copy(end.data_, &*end, out);
317  }
318 
319  return out;
320 }
321 } // namespace ringbuf
322 } // namespace detail
323 
334 template <typename Elem,
335  std::size_t Capacity,
336  typename Allocator = std::allocator<Elem>>
337 class RingBuf {
338  public:
339  using allocator_type = Allocator;
340  using alloc_traits = std::allocator_traits<allocator_type>;
341  using value_type = Elem;
342  using pointer = typename alloc_traits::pointer;
343  using const_pointer = typename alloc_traits::const_pointer;
344  using reference = decltype(*pointer{});
345  using const_reference = decltype(*const_pointer{});
347  using const_iterator =
349  using reverse_iterator = std::reverse_iterator<iterator>;
350  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
351  using difference_type = typename alloc_traits::difference_type;
352  using size_type = typename alloc_traits::size_type;
353  using unsigned_difference =
354  typename std::make_unsigned<difference_type>::type;
355 
356  using self = RingBuf<Elem, Capacity>;
357 
358  private:
359  // The allocator is used to allocate memory, and to construct and destroy
360  // elements.
361  allocator_type alloc_{};
362 
363  // The start of the dynamically allocated backing array.
364  pointer data_{nullptr};
365  // The next position to write to for push_back().
366  size_type next_{0U};
367 
368  // Start of the ring buffer in data_.
369  size_type ring_offset_{0U};
370  // The number of elements in the ring buffer (distance between begin() and
371  // end()).
372  size_type size_{0U};
373 
374  constexpr static size_type Decrement(const size_type index) {
375  return index > 0 ? index - 1 : Capacity;
376  }
377 
378  constexpr static size_type Increment(const size_type index) {
379  return index < (Capacity) ? index + 1 : 0;
380  }
381 
382  // Swap everything but the allocator - caller has to figure that out
383  // separately.
384  void Swap(RingBuf& other) noexcept {
385  std::swap(data_, other.data_);
386  std::swap(next_, other.next_);
387  std::swap(ring_offset_, other.ring_offset_);
388  std::swap(size_, other.size_);
389  }
390 
391  // Move things after pop_front.
392  void ShrinkFront() noexcept {
393  ring_offset_ = Increment(ring_offset_);
394  // Precondition: size != 0 (when it is, pop_front returns early.)
395  size_--;
396  }
397 
398  // Move things around before pop_back destroys the last entry.
399  void ShrinkBack() noexcept {
400  next_ = Decrement(next_);
401  // Precondition: size != 0 (when it is, pop_back returns early.)
402  size_--;
403  }
404 
405  // Move things around before emplace_front constructs its new entry.
406  void GrowFront() noexcept {
407  // Move ring_offset_ down, and possibly around
408  ring_offset_ = Decrement(ring_offset_);
409  // Precondition: size != Capacity (when it is, emplace_front pop_backs
410  // first.)
411  size_++;
412  }
413 
414  // Move things around after emplace_back.
415  void GrowBack() noexcept {
416  next_ = Increment(next_);
417  // Precondition: size != Capacity (when it is, emplace_back pop_fronts
418  // first)
419  size_++;
420  }
421 
422  iterator UnConstIterator(const_iterator it) const {
423  return iterator(data_, ring_offset_, it - begin());
424  }
425 
426  reference UncheckedAt(size_type index) { return (*this)[index]; }
427 
428  public:
436  RingBuf() : RingBuf(allocator_type{}){};
446  explicit RingBuf(const allocator_type& allocator)
447  : alloc_(allocator),
448  data_(alloc_traits::allocate(alloc_, Capacity + 1)) {}
449 
456  clear();
457  alloc_traits::deallocate(alloc_, data_, Capacity + 1);
458  }
466  RingBuf(const RingBuf& other)
467  : RingBuf(
468  other,
469  alloc_traits::select_on_container_copy_construction(other.alloc_)) {
470  }
479  RingBuf(const RingBuf& other, const allocator_type& allocator)
480  : RingBuf(allocator) {
481  clear();
482 
483  for (const auto& value : other) {
484  push_back(value);
485  }
486  }
492  RingBuf(RingBuf&& other) noexcept : RingBuf(std::move(other.alloc_)) {
493  Swap(other);
494  }
504  RingBuf(RingBuf&& other, const allocator_type& allocator)
505  : RingBuf(allocator) {
506  if (other.alloc_ == allocator) {
507  Swap(other);
508  } else {
509  for (auto& element : other) {
510  emplace_back(std::move(element));
511  }
512  }
513  }
514 
523  RingBuf& operator=(const RingBuf& other) {
524  clear();
525 
526  detail::ringbuf::CopyAllocator(alloc_, other.alloc_);
527 
528  for (const auto& value : other) {
529  push_back(value);
530  }
531  return *this;
532  }
542  RingBuf& operator=(RingBuf&& other) noexcept(
543  alloc_traits::propagate_on_container_move_assignment::value ||
544  std::is_nothrow_move_constructible<value_type>::value) {
545  if (alloc_traits::propagate_on_container_move_assignment::value ||
546  alloc_ == other.alloc_) {
547  // We're either getting the other's allocator or they're already the same,
548  // so swap data in one go.
549  detail::ringbuf::MoveAllocator(alloc_, other.alloc_);
550  Swap(other);
551  } else {
552  // Different allocators and can't swap them, so move elementwise.
553  clear();
554  for (auto& element : other) {
555  emplace_back(std::move(element));
556  }
557  }
558 
559  return *this;
560  }
561 
565  allocator_type get_allocator() const { return alloc_; }
566 
571  reference front() { return at(0); }
576  const_reference front() const { return at(0); }
581  reference back() { return at(size() - 1); }
586  const_reference back() const { return at(size() - 1); }
587 
596  const_reference operator[](const size_type index) const {
597  return data_[detail::ringbuf::RingWrap<Capacity>(ring_offset_ + index)];
598  }
607  reference operator[](const size_type index) {
608  return data_[detail::ringbuf::RingWrap<Capacity>(ring_offset_ + index)];
609  }
618  const_reference at(const size_type index) const {
619  if (index >= size()) {
620  throw std::out_of_range("RingBuf::at: index >= Size");
621  }
622  return (*this)[index];
623  }
632  reference at(const size_type index) {
633  if (index >= size()) {
634  throw std::out_of_range("RingBuf::at: index >= Size");
635  }
636  return (*this)[index];
637  }
638 
642  iterator begin() noexcept { return iterator(&data_[0], ring_offset_, 0); }
646  iterator end() noexcept { return iterator(&data_[0], ring_offset_, size()); }
650  const_iterator begin() const noexcept {
651  return const_iterator(&data_[0], ring_offset_, 0);
652  }
656  const_iterator end() const noexcept {
657  return const_iterator(&data_[0], ring_offset_, size());
658  }
662  const_iterator cbegin() const noexcept {
663  return const_cast<self const&>(*this).begin();
664  }
668  const_iterator cend() const noexcept {
669  return const_cast<self const&>(*this).end();
670  }
674  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
678  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
682  const_reverse_iterator rbegin() const noexcept {
683  return const_reverse_iterator(end());
684  }
688  const_reverse_iterator rend() const noexcept {
689  return const_reverse_iterator(begin());
690  }
694  const_reverse_iterator crbegin() const noexcept {
695  return const_cast<self const&>(*this).rbegin();
696  }
700  const_reverse_iterator crend() const noexcept {
701  return const_cast<self const&>(*this).rend();
702  }
703 
707  bool empty() const noexcept { return size() == 0; }
711  size_type size() const noexcept { return size_; }
715  constexpr size_type max_size() const noexcept { return Capacity; }
716 
723  void push_front(const_reference value) { emplace_front(value); }
730  void push_front(value_type&& value) { emplace_front(std::move(value)); }
738  template <typename... Args>
739  reference emplace_front(Args&&... args) {
740  if (max_size() == 0) {
741  // A buffer of size zero is conceptually sound, so let's support it.
742  return UncheckedAt(0);
743  }
744 
745  alloc_traits::construct(alloc_, &data_[Decrement(ring_offset_)],
746  std::forward<Args>(args)...);
747 
748  // If required, make room for next time.
749  if (size() == max_size()) {
750  pop_back();
751  }
752  GrowFront();
753  return UncheckedAt(0);
754  }
755 
761  void push_back(const_reference value) { emplace_back(value); }
767  void push_back(value_type&& value) { emplace_back(std::move(value)); }
775  template <typename... Args>
776  reference emplace_back(Args&&... args) {
777  if (max_size() == 0) {
778  // A buffer of size zero is conceptually sound, so let's support it.
779  return UncheckedAt(0);
780  }
781 
782  alloc_traits::construct(alloc_, &data_[next_], std::forward<Args>(args)...);
783 
784  // If required, make room for next time.
785  if (size() == max_size()) {
786  pop_front();
787  }
788  GrowBack();
789  return UncheckedAt(size() - 1);
790  }
791 
796  void pop_front() noexcept {
797  if (size() == 0) {
798  return;
799  }
800 
801  alloc_traits::destroy(alloc_, &data_[ring_offset_]);
802  ShrinkFront();
803  }
808  void pop_back() noexcept {
809  if (size() == 0) {
810  return;
811  }
812 
813  ShrinkBack();
814  alloc_traits::destroy(alloc_, &data_[next_]);
815  }
822  void clear() noexcept(noexcept(pop_front())) {
823  // It might be fractionally more efficient to iterate through begin..end and
824  // allocator::destroy each one, but this is a lot nicer to read.
825  while (!empty()) {
826  pop_front();
827  }
828  }
829 
837  noexcept(pop_front()) && std::is_nothrow_move_assignable<Elem>::value) {
838  if (from == to) {
839  return UnConstIterator(to);
840  }
841 
842  const iterator first = UnConstIterator(from);
843  const iterator last = UnConstIterator(to);
844 
845  const auto leading = first - begin();
846  const auto trailing = end() - last;
847  if (leading > trailing) {
848  // Move from back towards first
849  for (auto i = 0; i < trailing; i++) {
850  first[i] = std::move(last[i]);
851  }
852  const auto to_pop = last - first;
853  for (auto i = 0; i < to_pop; i++) {
854  pop_back();
855  }
856  } else {
857  // Move from front towards last
858  for (auto i = -1; i >= -leading; i--) {
859  last[i] = std::move(first[i]);
860  }
861  const auto to_pop = last - first;
862  for (auto i = 0; i < to_pop; i++) {
863  pop_front();
864  }
865  }
866 
867  return end() - trailing;
868  }
869 
876  iterator erase(const_iterator pos) noexcept(noexcept(erase(pos, pos + 1))) {
877  return erase(pos, pos + 1);
878  }
879 
885  void swap(RingBuf& other) noexcept {
886  detail::ringbuf::SwapAllocator(alloc_, other.alloc_);
887  Swap(other);
888  }
889 
895  friend bool operator<(const RingBuf& lhs, const RingBuf& rhs) {
896  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
897  rhs.end());
898  }
904  friend bool operator>(const RingBuf& lhs, const RingBuf& rhs) {
905  return rhs < lhs;
906  }
912  friend bool operator==(const RingBuf& lhs, const RingBuf& rhs) {
913  if (lhs.size() != rhs.size()) {
914  return false;
915  }
916 
917  return std::equal(lhs.begin(), lhs.end(), rhs.begin());
918  }
924  friend bool operator>=(const RingBuf& lhs, const RingBuf& rhs) {
925  return !(lhs < rhs);
926  }
932  friend bool operator<=(const RingBuf& lhs, const RingBuf& rhs) {
933  return !(lhs > rhs);
934  }
940  friend bool operator!=(const RingBuf& lhs, const RingBuf& rhs) {
941  return !(lhs == rhs);
942  }
943 };
944 
963 template <typename Ptr,
964  typename AllocTraits,
965  std::size_t Capacity,
966  typename OutputIt>
967 OutputIt copy(
970  OutputIt out) {
971  return detail::ringbuf::copy(begin, end, out);
972 }
973 
974 } // namespace baudvine
baudvine::RingBuf::rbegin
reverse_iterator rbegin() noexcept
Get a reverse iterator pointing to the last element.
Definition: ringbuf.h:674
baudvine::RingBuf::erase
iterator erase(const_iterator pos) noexcept(noexcept(erase(pos, pos+1)))
Erase an element.
Definition: ringbuf.h:876
baudvine::RingBuf::push_back
void push_back(value_type &&value)
Push a new element into the ring buffer, popping the front if necessary.
Definition: ringbuf.h:767
baudvine::RingBuf::RingBuf
RingBuf(RingBuf &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition: ringbuf.h:504
baudvine::RingBuf::back
reference back()
Returns he last element in the ring buffer.
Definition: ringbuf.h:581
baudvine::RingBuf::emplace_front
reference emplace_front(Args &&... args)
Construct a new element in-place before the front of the ring buffer, popping the back if necessary.
Definition: ringbuf.h:739
baudvine::RingBuf::crend
const_reverse_iterator crend() const noexcept
Get a const reverse iterator pointing to one before the first element.
Definition: ringbuf.h:700
baudvine::RingBuf::pop_back
void pop_back() noexcept
Pop an element off the back, destroying the last element in the ring buffer.
Definition: ringbuf.h:808
baudvine::RingBuf::operator>=
friend bool operator>=(const RingBuf &lhs, const RingBuf &rhs)
Elementwise comparison of two ring buffers.
Definition: ringbuf.h:924
baudvine::RingBuf::emplace_back
reference emplace_back(Args &&... args)
Construct a new element in-place at the end of the ring buffer, popping the front if necessary.
Definition: ringbuf.h:776
baudvine::RingBuf::rbegin
const_reverse_iterator rbegin() const noexcept
Get a const reverse iterator pointing to the last element.
Definition: ringbuf.h:682
baudvine::RingBuf::max_size
constexpr size_type max_size() const noexcept
Get the maximum number of elements in this ring buffer (Capacity).
Definition: ringbuf.h:715
baudvine::RingBuf::operator=
RingBuf & operator=(const RingBuf &other)
Copy a RingBuf into this one.
Definition: ringbuf.h:523
baudvine::RingBuf::operator=
RingBuf & operator=(RingBuf &&other) noexcept(alloc_traits::propagate_on_container_move_assignment::value||std::is_nothrow_move_constructible< value_type >::value)
Move a RingBuf into this one.
Definition: ringbuf.h:542
baudvine::copy
OutputIt copy(const detail::ringbuf::Iterator< Ptr, AllocTraits, Capacity > &begin, const detail::ringbuf::Iterator< Ptr, AllocTraits, Capacity > &end, OutputIt out)
Copy the elements in the range [begin, end) to a destination range starting at out.
Definition: ringbuf.h:967
baudvine::RingBuf::rend
reverse_iterator rend() noexcept
Get a reverse iterator pointing to one before the first element.
Definition: ringbuf.h:678
baudvine::RingBuf::RingBuf
RingBuf()
Construct a new ring buffer object with a default-constructed allocator, and allocate the required me...
Definition: ringbuf.h:436
baudvine::RingBuf::empty
bool empty() const noexcept
Get whether the ring buffer is empty (size() == 0)
Definition: ringbuf.h:707
baudvine::RingBuf::front
reference front()
Returns the first element in the ring buffer.
Definition: ringbuf.h:571
baudvine::RingBuf::begin
const_iterator begin() const noexcept
Get a const iterator pointing to the first element.
Definition: ringbuf.h:650
baudvine::RingBuf::back
const_reference back() const
Returns he last element in the ring buffer.
Definition: ringbuf.h:586
baudvine::RingBuf::operator[]
reference operator[](const size_type index)
Retrieve an element from the ring buffer without range checking.
Definition: ringbuf.h:607
baudvine::RingBuf::RingBuf
RingBuf(const allocator_type &allocator)
Construct a new ring buffer object with the provided allocator, and allocate the required memory.
Definition: ringbuf.h:446
baudvine::RingBuf::at
reference at(const size_type index)
Retrieve an element from the ring buffer with range checking.
Definition: ringbuf.h:632
baudvine::RingBuf::swap
void swap(RingBuf &other) noexcept
Swap this ring buffer with another using std::swap.
Definition: ringbuf.h:885
baudvine::RingBuf::operator[]
const_reference operator[](const size_type index) const
Retrieve an element from the ring buffer without range checking.
Definition: ringbuf.h:596
baudvine::RingBuf::push_front
void push_front(value_type &&value)
Push a new element at the front of the ring buffer, popping the back if necessary.
Definition: ringbuf.h:730
baudvine::RingBuf::cend
const_iterator cend() const noexcept
Get a const iterator pointing to one past the last element.
Definition: ringbuf.h:668
baudvine::RingBuf::RingBuf
RingBuf(RingBuf &&other) noexcept
Construct a new RingBuf object out of another, using bulk move assignment.
Definition: ringbuf.h:492
baudvine::RingBuf::operator!=
friend bool operator!=(const RingBuf &lhs, const RingBuf &rhs)
Elementwise comparison of two ring buffers.
Definition: ringbuf.h:940
baudvine::RingBuf::begin
iterator begin() noexcept
Get an iterator pointing to the first element.
Definition: ringbuf.h:642
baudvine::RingBuf::RingBuf
RingBuf(const RingBuf &other)
Construct a new RingBuf object out of another, using elementwise copy assignment.
Definition: ringbuf.h:466
baudvine::RingBuf::operator>
friend bool operator>(const RingBuf &lhs, const RingBuf &rhs)
Elementwise lexicographical comparison of two ring buffers.
Definition: ringbuf.h:904
baudvine::RingBuf::operator<=
friend bool operator<=(const RingBuf &lhs, const RingBuf &rhs)
Elementwise comparison of two ring buffers.
Definition: ringbuf.h:932
baudvine::RingBuf::get_allocator
allocator_type get_allocator() const
Get a copy of the allocator used by this RingBuf.
Definition: ringbuf.h:565
baudvine::RingBuf::push_front
void push_front(const_reference value)
Push a new element at the front of the ring buffer, popping the back if necessary.
Definition: ringbuf.h:723
baudvine::RingBuf::operator==
friend bool operator==(const RingBuf &lhs, const RingBuf &rhs)
Elementwise comparison of two ring buffers.
Definition: ringbuf.h:912
baudvine::RingBuf
An STL-like ring buffer with dynamic allocation and compile-time capacity limits.
Definition: ringbuf.h:337
baudvine::RingBuf::clear
void clear() noexcept(noexcept(pop_front()))
Remove all elements from the ring buffer, destroying each one starting at the front.
Definition: ringbuf.h:822
baudvine::RingBuf::push_back
void push_back(const_reference value)
Push a new element into the ring buffer, popping the front if necessary.
Definition: ringbuf.h:761
baudvine::RingBuf::rend
const_reverse_iterator rend() const noexcept
Get a const reverse iterator pointing to one before the first element.
Definition: ringbuf.h:688
baudvine::RingBuf::at
const_reference at(const size_type index) const
Retrieve an element from the ring buffer with range checking.
Definition: ringbuf.h:618
baudvine::RingBuf::cbegin
const_iterator cbegin() const noexcept
Get a const iterator pointing to the first element.
Definition: ringbuf.h:662
baudvine::RingBuf::crbegin
const_reverse_iterator crbegin() const noexcept
Get a const reverse iterator pointing to the last element.
Definition: ringbuf.h:694
baudvine
The baudvine "project".
Definition: deque_ringbuf.h:24
baudvine::RingBuf::size
size_type size() const noexcept
Get the number of elements in the ring buffer.
Definition: ringbuf.h:711
baudvine::RingBuf::front
const_reference front() const
Returns the first element in the ring buffer.
Definition: ringbuf.h:576
baudvine::RingBuf::operator<
friend bool operator<(const RingBuf &lhs, const RingBuf &rhs)
Elementwise lexicographical comparison of two ring buffers.
Definition: ringbuf.h:895
baudvine::detail::ringbuf::Iterator::Iterator
Iterator(pointer data, const size_type ring_offset, const size_type ring_index)
Construct a new iterator object.
Definition: ringbuf.h:172
baudvine::RingBuf::end
const_iterator end() const noexcept
Get a const iterator pointing to one past the last element.
Definition: ringbuf.h:656
baudvine::RingBuf::pop_front
void pop_front() noexcept
Pop an element off the front, destroying the first element in the ring buffer.
Definition: ringbuf.h:796
baudvine::RingBuf::end
iterator end() noexcept
Get an iterator pointing to one past the last element.
Definition: ringbuf.h:646
baudvine::RingBuf::RingBuf
RingBuf(const RingBuf &other, const allocator_type &allocator)
Allocator-extended copy constructor.
Definition: ringbuf.h:479
baudvine::detail::ringbuf::Iterator
An iterator into RingBuf.
Definition: ringbuf.h:154
baudvine::RingBuf::erase
iterator erase(const_iterator from, const_iterator to) noexcept(noexcept(pop_front()) &&std::is_nothrow_move_assignable< Elem >::value)
Erase elements in the range [first, last).
Definition: ringbuf.h:836
baudvine::RingBuf::~RingBuf
~RingBuf()
Destroy the ring buffer object.
Definition: ringbuf.h:455