You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
2.8 KiB

  1. #pragma once
  2. #include <condition_variable>
  3. #include <mutex>
  4. #include <queue>
  5. #include <utility>
  6. template<typename T>
  7. class BoundedQueue
  8. {
  9. public:
  10. explicit
  11. BoundedQueue(std::size_t max_size_,
  12. bool block_ = true)
  13. : _block(block_),
  14. _max_size(max_size_ ? max_size_ : 1)
  15. {
  16. }
  17. BoundedQueue(const BoundedQueue&) = delete;
  18. BoundedQueue(BoundedQueue&&) = default;
  19. bool
  20. push(const T& item_)
  21. {
  22. {
  23. std::unique_lock<std::mutex> guard(_queue_lock);
  24. _condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
  25. if(_queue.size() == _max_size)
  26. return false;
  27. _queue.push(item_);
  28. }
  29. _condition_pop.notify_one();
  30. return true;
  31. }
  32. bool
  33. push(T&& item_)
  34. {
  35. {
  36. std::unique_lock<std::mutex> guard(_queue_lock);
  37. _condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
  38. if(_queue.size() == _max_size)
  39. return false;
  40. _queue.push(std::move(item_));
  41. }
  42. _condition_pop.notify_one();
  43. return true;
  44. }
  45. template<typename... Args>
  46. bool
  47. emplace(Args&&... args_)
  48. {
  49. {
  50. std::lock_guard<std::mutex> guard(_queue_lock);
  51. _condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
  52. if(_queue.size() == _max_size)
  53. return false;
  54. _queue.emplace(std::forward<Args>(args_)...);
  55. }
  56. _condition_pop.notify_one();
  57. return true;
  58. }
  59. bool
  60. pop(T& item_)
  61. {
  62. {
  63. std::unique_lock<std::mutex> guard(_queue_lock);
  64. _condition_pop.wait(guard, [&]() { return !_queue.empty() || !_block; });
  65. if(_queue.empty())
  66. return false;
  67. item_ = std::move(_queue.front());
  68. _queue.pop();
  69. }
  70. _condition_push.notify_one();
  71. return true;
  72. }
  73. std::size_t
  74. size() const
  75. {
  76. std::lock_guard<std::mutex> guard(_queue_lock);
  77. return _queue.size();
  78. }
  79. std::size_t
  80. capacity() const
  81. {
  82. return _max_size;
  83. }
  84. bool
  85. empty() const
  86. {
  87. std::lock_guard<std::mutex> guard(_queue_lock);
  88. return _queue.empty();
  89. }
  90. bool
  91. full() const
  92. {
  93. std::lock_guard<std::mutex> lock(_queue_lock);
  94. return (_queue.size() == capacity());
  95. }
  96. void
  97. block()
  98. {
  99. std::lock_guard<std::mutex> guard(_queue_lock);
  100. _block = true;
  101. }
  102. void
  103. unblock()
  104. {
  105. {
  106. std::lock_guard<std::mutex> guard(_queue_lock);
  107. _block = false;
  108. }
  109. _condition_push.notify_all();
  110. _condition_pop.notify_all();
  111. }
  112. bool
  113. blocking() const
  114. {
  115. std::lock_guard<std::mutex> guard(_queue_lock);
  116. return _block;
  117. }
  118. private:
  119. mutable std::mutex _queue_lock;
  120. private:
  121. bool _block;
  122. std::queue<T> _queue;
  123. const std::size_t _max_size;
  124. std::condition_variable _condition_push;
  125. std::condition_variable _condition_pop;
  126. };