CirBuffer.h 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #pragma once
  2. #ifndef CIRCULAR_BUFFER_HPP_
  3. #define CIRCULAR_BUFFER_HPP_
  4. #include <array>
  5. #include <mutex>
  6. #include <optional>
  7. template<class T, size_t TElemCount>
  8. class circular_buffer
  9. {
  10. public:
  11. explicit circular_buffer() = default;
  12. void put(T item) noexcept
  13. {
  14. std::lock_guard<std::recursive_mutex> lock(mutex_);
  15. buf_[head_] = item;
  16. if (full_)
  17. {
  18. tail_ = (tail_ + 1) % TElemCount;
  19. }
  20. head_ = (head_ + 1) % TElemCount;
  21. full_ = head_ == tail_;
  22. }
  23. std::optional<T> get() const noexcept
  24. {
  25. std::lock_guard<std::recursive_mutex> lock(mutex_);
  26. if (empty())
  27. {
  28. return std::nullopt;
  29. }
  30. // Read data and advance the tail (we now have a free space)
  31. auto val = buf_[tail_];
  32. full_ = false;
  33. tail_ = (tail_ + 1) % TElemCount;
  34. return val;
  35. }
  36. void reset() noexcept
  37. {
  38. std::lock_guard<std::recursive_mutex> lock(mutex_);
  39. head_ = tail_;
  40. full_ = false;
  41. }
  42. bool empty() const noexcept
  43. {
  44. // Can have a race condition in a multi-threaded application
  45. std::lock_guard<std::recursive_mutex> lock(mutex_);
  46. // if head and tail are equal, we are empty
  47. return (!full_ && (head_ == tail_));
  48. }
  49. bool full() const noexcept
  50. {
  51. // If tail is ahead the head by 1, we are full
  52. return full_;
  53. }
  54. size_t capacity() const noexcept
  55. {
  56. return TElemCount;
  57. }
  58. size_t size() const noexcept
  59. {
  60. // A lock is needed in size ot prevent a race condition, because head_, tail_, and full_
  61. // can be updated between executing lines within this function in a multi-threaded
  62. // application
  63. std::lock_guard<std::recursive_mutex> lock(mutex_);
  64. size_t size = TElemCount;
  65. if (!full_)
  66. {
  67. if (head_ >= tail_)
  68. {
  69. size = head_ - tail_;
  70. }
  71. else
  72. {
  73. size = TElemCount + head_ - tail_;
  74. }
  75. }
  76. return size;
  77. }
  78. private:
  79. mutable std::recursive_mutex mutex_;
  80. mutable std::array<T, TElemCount> buf_;
  81. mutable size_t head_ = 0;
  82. mutable size_t tail_ = 0;
  83. mutable bool full_ = 0;
  84. };
  85. #endif