Chatterino
LimitedQueue.hpp
Go to the documentation of this file.
1 #pragma once
2 
4 
5 #include <boost/circular_buffer.hpp>
6 #include <boost/optional.hpp>
7 
8 #include <cassert>
9 #include <mutex>
10 #include <shared_mutex>
11 #include <vector>
12 
13 namespace chatterino {
14 
15 template <typename T>
17 {
18 public:
19  LimitedQueue(size_t limit = 1000)
20  : limit_(limit)
21  , buffer_(limit)
22  {
23  }
24 
25 private:
27 
30  [[nodiscard]] size_t limit() const
31  {
32  return this->limit_;
33  }
34 
40  [[nodiscard]] size_t space() const
41  {
42  return this->limit() - this->buffer_.size();
43  }
44 
45 public:
49  [[nodiscard]] bool empty() const
50  {
51  std::shared_lock lock(this->mutex_);
52 
53  return this->buffer_.empty();
54  }
55 
57  // Copies of values are returned so that references aren't invalidated
58 
65  [[nodiscard]] boost::optional<T> get(size_t index) const
66  {
67  std::shared_lock lock(this->mutex_);
68 
69  if (index >= this->buffer_.size())
70  {
71  return boost::none;
72  }
73 
74  return this->buffer_[index];
75  }
76 
82  [[nodiscard]] boost::optional<T> first() const
83  {
84  std::shared_lock lock(this->mutex_);
85 
86  if (this->buffer_.empty())
87  {
88  return boost::none;
89  }
90 
91  return this->buffer_.front();
92  }
93 
99  [[nodiscard]] boost::optional<T> last() const
100  {
101  std::shared_lock lock(this->mutex_);
102 
103  if (this->buffer_.empty())
104  {
105  return boost::none;
106  }
107 
108  return this->buffer_.back();
109  }
110 
112 
113  // Clear the buffer
114  void clear()
115  {
116  std::unique_lock lock(this->mutex_);
117 
118  this->buffer_.clear();
119  }
120 
128  bool pushBack(const T &item, T &deleted)
129  {
130  std::unique_lock lock(this->mutex_);
131 
132  bool full = this->buffer_.full();
133  if (full)
134  {
135  deleted = this->buffer_.front();
136  }
137  this->buffer_.push_back(item);
138  return full;
139  }
140 
147  bool pushBack(const T &item)
148  {
149  std::unique_lock lock(this->mutex_);
150 
151  bool full = this->buffer_.full();
152  this->buffer_.push_back(item);
153  return full;
154  }
155 
166  std::vector<T> pushFront(const std::vector<T> &items)
167  {
168  std::unique_lock lock(this->mutex_);
169 
170  size_t numToPush = std::min(items.size(), this->space());
171  std::vector<T> pushed;
172  pushed.reserve(numToPush);
173 
174  size_t f = items.size() - numToPush;
175  size_t b = items.size() - 1;
176  for (; f < items.size(); ++f, --b)
177  {
178  this->buffer_.push_front(items[b]);
179  pushed.push_back(items[f]);
180  }
181 
182  return pushed;
183  }
184 
193  template <typename Equals = std::equal_to<T>>
194  int replaceItem(const T &needle, const T &replacement)
195  {
196  std::unique_lock lock(this->mutex_);
197 
198  Equals eq;
199  for (int i = 0; i < this->buffer_.size(); ++i)
200  {
201  if (eq(this->buffer_[i], needle))
202  {
203  this->buffer_[i] = replacement;
204  return i;
205  }
206  }
207  return -1;
208  }
209 
217  bool replaceItem(size_t index, const T &replacement)
218  {
219  std::unique_lock lock(this->mutex_);
220 
221  if (index >= this->buffer_.size())
222  {
223  return false;
224  }
225 
226  this->buffer_[index] = replacement;
227  return true;
228  }
229 
238  template <typename Equals = std::equal_to<T>>
239  bool insertBefore(const T &needle, const T &item)
240  {
241  std::unique_lock lock(this->mutex_);
242 
243  Equals eq;
244  for (auto it = this->buffer_.begin(); it != this->buffer_.end(); ++it)
245  {
246  if (eq(*it, needle))
247  {
248  this->buffer_.insert(it, item);
249  return true;
250  }
251  }
252 
253  return false;
254  }
255 
264  template <typename Equals = std::equal_to<T>>
265  bool insertAfter(const T &needle, const T &item)
266  {
267  std::unique_lock lock(this->mutex_);
268 
269  Equals eq;
270  for (auto it = this->buffer_.begin(); it != this->buffer_.end(); ++it)
271  {
272  if (eq(*it, needle))
273  {
274  ++it; // advance to insert after it
275  this->buffer_.insert(it, item);
276  return true;
277  }
278  }
279 
280  return false;
281  }
282 
283  [[nodiscard]] LimitedQueueSnapshot<T> getSnapshot() const
284  {
285  std::shared_lock lock(this->mutex_);
286  return LimitedQueueSnapshot<T>(this->buffer_);
287  }
288 
289  // Actions
290 
302  template <typename Predicate>
303  [[nodiscard]] boost::optional<T> find(Predicate pred) const
304  {
305  std::shared_lock lock(this->mutex_);
306 
307  for (const auto &item : this->buffer_)
308  {
309  if (pred(item))
310  {
311  return item;
312  }
313  }
314 
315  return boost::none;
316  }
317 
329  template <typename Predicate>
330  [[nodiscard]] boost::optional<T> rfind(Predicate pred) const
331  {
332  std::shared_lock lock(this->mutex_);
333 
334  for (auto it = this->buffer_.rbegin(); it != this->buffer_.rend(); ++it)
335  {
336  if (pred(*it))
337  {
338  return *it;
339  }
340  }
341 
342  return boost::none;
343  }
344 
345 private:
346  mutable std::shared_mutex mutex_;
347 
348  const size_t limit_;
349  boost::circular_buffer<T> buffer_;
350 };
351 
352 } // namespace chatterino
bool pushBack(const T &item, T &deleted)
Push an item to the end of the queue.
Definition: LimitedQueue.hpp:128
Definition: LimitedQueue.hpp:16
boost::optional< T > first() const
Get the first item from the queue.
Definition: LimitedQueue.hpp:82
Definition: LimitedQueueSnapshot.hpp:15
Definition: Application.cpp:48
bool insertAfter(const T &needle, const T &item)
Inserts the given item after another item.
Definition: LimitedQueue.hpp:265
bool insertBefore(const T &needle, const T &item)
Inserts the given item before another item.
Definition: LimitedQueue.hpp:239
std::vector< T > pushFront(const std::vector< T > &items)
Push items into beginning of queue.
Definition: LimitedQueue.hpp:166
LimitedQueue(size_t limit=1000)
Definition: LimitedQueue.hpp:19
bool pushBack(const T &item)
Push an item to the end of the queue.
Definition: LimitedQueue.hpp:147
bool replaceItem(size_t index, const T &replacement)
Replace the item at index with the given item.
Definition: LimitedQueue.hpp:217
bool empty() const
Return true if the buffer is empty.
Definition: LimitedQueue.hpp:49
boost::optional< T > rfind(Predicate pred) const
Returns the first item matching a predicate, checking in reverse.
Definition: LimitedQueue.hpp:330
void clear()
Modifiers.
Definition: LimitedQueue.hpp:114
boost::optional< T > find(Predicate pred) const
Returns the first item matching a predicate.
Definition: LimitedQueue.hpp:303
int replaceItem(const T &needle, const T &replacement)
Replace the needle with the given item.
Definition: LimitedQueue.hpp:194
LimitedQueueSnapshot< T > getSnapshot() const
Definition: LimitedQueue.hpp:283
boost::optional< T > last() const
Get the last item from the queue.
Definition: LimitedQueue.hpp:99