Rewrite & optimize LimitedQueue (#3798)
* Use circular buffer for LimitedQueue * Reduce copying of snapshot * Small optimizations * Remove unneeded lock statements * Add LimitedQueue tests * Fix includes for limited queue benchmark * Update CHANGELOG.md * Use correct boost version iterators * Use a shared_mutex to clarify reads and writes * Update `find`/`rfind` to return the result as a boost::optional * Use `[[nodiscard]]` where applicable * Update comments * Add a couple more doc comments * Replace size with get get is a safe (locked & checked) version of at * Use std::vector in LimitedQueueSnapshot * Update LimitedQueue benchmarks * Add mutex guard to buffer accessors We do not know whether T is an atomic type or not so we can't safely say that we can copy the value at a certain address of the buffer. See https://stackoverflow.com/a/2252478 * Update doc comments, add first/last getters * Make limit_ const * Omit `else` if the if-case always returns * Title case category comments * Remove `at` * Fix `get` comment * Privatize/comment/lock property accessors - `limit` is now private - `space` is now private - `full` has been removed - `empty` now locks * Remove `front` function * Remove `back` method * Add comment to `first` * Add comment to `last` Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -1,60 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename T>
|
||||
class LimitedQueue;
|
||||
|
||||
template <typename T>
|
||||
class LimitedQueueSnapshot
|
||||
{
|
||||
private:
|
||||
friend class LimitedQueue<T>;
|
||||
|
||||
LimitedQueueSnapshot(const boost::circular_buffer<T> &buf)
|
||||
: buffer_(buf.begin(), buf.end())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
LimitedQueueSnapshot() = default;
|
||||
|
||||
LimitedQueueSnapshot(
|
||||
std::shared_ptr<std::vector<std::shared_ptr<std::vector<T>>>> chunks,
|
||||
size_t length, size_t firstChunkOffset, size_t lastChunkEnd)
|
||||
: chunks_(chunks)
|
||||
, length_(length)
|
||||
, firstChunkOffset_(firstChunkOffset)
|
||||
, lastChunkEnd_(lastChunkEnd)
|
||||
size_t size() const
|
||||
{
|
||||
return this->buffer_.size();
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
const T &operator[](size_t index) const
|
||||
{
|
||||
return this->length_;
|
||||
return this->buffer_[index];
|
||||
}
|
||||
|
||||
T const &operator[](std::size_t index) const
|
||||
auto begin() const
|
||||
{
|
||||
index += this->firstChunkOffset_;
|
||||
return this->buffer_.begin();
|
||||
}
|
||||
|
||||
size_t x = 0;
|
||||
auto end() const
|
||||
{
|
||||
return this->buffer_.end();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < this->chunks_->size(); i++)
|
||||
{
|
||||
auto &chunk = this->chunks_->at(i);
|
||||
auto rbegin() const
|
||||
{
|
||||
return this->buffer_.rbegin();
|
||||
}
|
||||
|
||||
if (x <= index && x + chunk->size() > index)
|
||||
{
|
||||
return chunk->at(index - x);
|
||||
}
|
||||
x += chunk->size();
|
||||
}
|
||||
|
||||
assert(false && "out of range");
|
||||
|
||||
return this->chunks_->at(0)->at(0);
|
||||
auto rend() const
|
||||
{
|
||||
return this->buffer_.rend();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::vector<std::shared_ptr<std::vector<T>>>> chunks_;
|
||||
|
||||
size_t length_ = 0;
|
||||
size_t firstChunkOffset_ = 0;
|
||||
size_t lastChunkEnd_ = 0;
|
||||
std::vector<T> buffer_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
Reference in New Issue
Block a user