circular_q.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. // circular q view of std::vector.
  4. #pragma once
  5. #include <vector>
  6. #include <cassert>
  7. namespace spdlog {
  8. namespace details {
  9. template<typename T>
  10. class circular_q
  11. {
  12. size_t max_items_ = 0;
  13. typename std::vector<T>::size_type head_ = 0;
  14. typename std::vector<T>::size_type tail_ = 0;
  15. size_t overrun_counter_ = 0;
  16. std::vector<T> v_;
  17. public:
  18. using value_type = T;
  19. // empty ctor - create a disabled queue with no elements allocated at all
  20. circular_q() = default;
  21. explicit circular_q(size_t max_items)
  22. : max_items_(max_items + 1) // one item is reserved as marker for full q
  23. , v_(max_items_)
  24. {}
  25. circular_q(const circular_q &) = default;
  26. circular_q &operator=(const circular_q &) = default;
  27. // move cannot be default,
  28. // since we need to reset head_, tail_, etc to zero in the moved object
  29. circular_q(circular_q &&other) SPDLOG_NOEXCEPT
  30. {
  31. copy_moveable(std::move(other));
  32. }
  33. circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT
  34. {
  35. copy_moveable(std::move(other));
  36. return *this;
  37. }
  38. // push back, overrun (oldest) item if no room left
  39. void push_back(T &&item)
  40. {
  41. if (max_items_ > 0)
  42. {
  43. v_[tail_] = std::move(item);
  44. tail_ = (tail_ + 1) % max_items_;
  45. if (tail_ == head_) // overrun last item if full
  46. {
  47. head_ = (head_ + 1) % max_items_;
  48. ++overrun_counter_;
  49. }
  50. }
  51. }
  52. // Return reference to the front item.
  53. // If there are no elements in the container, the behavior is undefined.
  54. const T &front() const
  55. {
  56. return v_[head_];
  57. }
  58. T &front()
  59. {
  60. return v_[head_];
  61. }
  62. // Return number of elements actually stored
  63. size_t size() const
  64. {
  65. if (tail_ >= head_)
  66. {
  67. return tail_ - head_;
  68. }
  69. else
  70. {
  71. return max_items_ - (head_ - tail_);
  72. }
  73. }
  74. // Return const reference to item by index.
  75. // If index is out of range 0…size()-1, the behavior is undefined.
  76. const T &at(size_t i) const
  77. {
  78. assert(i < size());
  79. return v_[(head_ + i) % max_items_];
  80. }
  81. // Pop item from front.
  82. // If there are no elements in the container, the behavior is undefined.
  83. void pop_front()
  84. {
  85. head_ = (head_ + 1) % max_items_;
  86. }
  87. bool empty() const
  88. {
  89. return tail_ == head_;
  90. }
  91. bool full() const
  92. {
  93. // head is ahead of the tail by 1
  94. if (max_items_ > 0)
  95. {
  96. return ((tail_ + 1) % max_items_) == head_;
  97. }
  98. return false;
  99. }
  100. size_t overrun_counter() const
  101. {
  102. return overrun_counter_;
  103. }
  104. void reset_overrun_counter()
  105. {
  106. overrun_counter_ = 0;
  107. }
  108. private:
  109. // copy from other&& and reset it to disabled state
  110. void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT
  111. {
  112. max_items_ = other.max_items_;
  113. head_ = other.head_;
  114. tail_ = other.tail_;
  115. overrun_counter_ = other.overrun_counter_;
  116. v_ = std::move(other.v_);
  117. // put &&other in disabled, but valid state
  118. other.max_items_ = 0;
  119. other.head_ = other.tail_ = 0;
  120. other.overrun_counter_ = 0;
  121. }
  122. };
  123. } // namespace details
  124. } // namespace spdlog