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:
Daniel Sage
2022-06-18 06:44:48 -04:00
committed by GitHub
parent f3f340335f
commit 81caf1aae0
12 changed files with 576 additions and 341 deletions
+32 -30
View File
@@ -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