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
+19 -32
View File
@@ -381,7 +381,7 @@ void ChannelView::performLayout(bool causedByScrollbar)
// BenchmarkGuard benchmark("layout");
/// Get messages and check if there are at least 1
auto messages = this->getMessagesSnapshot();
auto &messages = this->getMessagesSnapshot();
this->showingLatestMessages_ =
this->scrollBar_->isAtBottom() || !this->scrollBar_->isVisible();
@@ -502,7 +502,7 @@ QString ChannelView::getSelectedText()
{
QString result = "";
LimitedQueueSnapshot<MessageLayoutPtr> messagesSnapshot =
LimitedQueueSnapshot<MessageLayoutPtr> &messagesSnapshot =
this->getMessagesSnapshot();
Selection _selection = this->selection_;
@@ -561,7 +561,7 @@ const boost::optional<MessageElementFlags> &ChannelView::getOverrideFlags()
return this->overrideFlags_;
}
LimitedQueueSnapshot<MessageLayoutPtr> ChannelView::getMessagesSnapshot()
LimitedQueueSnapshot<MessageLayoutPtr> &ChannelView::getMessagesSnapshot()
{
if (!this->paused() /*|| this->scrollBar_->isVisible()*/)
{
@@ -682,11 +682,9 @@ void ChannelView::setChannel(ChannelPtr underlyingChannel)
auto snapshot = underlyingChannel->getMessageSnapshot();
for (size_t i = 0; i < snapshot.size(); i++)
for (const auto &msg : snapshot)
{
MessageLayoutPtr deleted;
auto messageLayout = new MessageLayout(snapshot[i]);
auto messageLayout = new MessageLayout(msg);
if (this->lastMessageHasAlternateBackground_)
{
@@ -700,11 +698,10 @@ void ChannelView::setChannel(ChannelPtr underlyingChannel)
messageLayout->flags.set(MessageLayoutFlag::IgnoreHighlights);
}
this->messages_.pushBack(MessageLayoutPtr(messageLayout), deleted);
this->messages_.pushBack(MessageLayoutPtr(messageLayout));
if (this->showScrollbarHighlights())
{
this->scrollBar_->addHighlight(
snapshot[i]->getScrollBarHighlight());
this->scrollBar_->addHighlight(msg->getScrollBarHighlight());
}
}
@@ -776,8 +773,6 @@ bool ChannelView::hasSourceChannel() const
void ChannelView::messageAppended(MessagePtr &message,
boost::optional<MessageFlags> overridingFlags)
{
MessageLayoutPtr deleted;
auto *messageFlags = &message->flags;
if (overridingFlags)
{
@@ -809,7 +804,7 @@ void ChannelView::messageAppended(MessagePtr &message,
loop.exec();
}
if (this->messages_.pushBack(MessageLayoutPtr(messageRef), deleted))
if (this->messages_.pushBack(MessageLayoutPtr(messageRef)))
{
if (this->paused())
{
@@ -915,22 +910,16 @@ void ChannelView::messageRemoveFromStart(MessagePtr &message)
void ChannelView::messageReplaced(size_t index, MessagePtr &replacement)
{
if (index >= this->messages_.getSnapshot().size())
auto oMessage = this->messages_.get(index);
if (!oMessage)
{
return;
}
auto message = *oMessage;
MessageLayoutPtr newItem(new MessageLayout(replacement));
auto snapshot = this->messages_.getSnapshot();
if (index >= snapshot.size())
{
qCDebug(chatterinoWidget)
<< "Tried to replace out of bounds message. Index:" << index
<< ". Length:" << snapshot.size();
return;
}
const auto &message = snapshot[index];
if (message->flags.has(MessageLayoutFlag::AlternateBackground))
{
newItem->flags.set(MessageLayoutFlag::AlternateBackground);
@@ -945,11 +934,9 @@ void ChannelView::messageReplaced(size_t index, MessagePtr &replacement)
void ChannelView::updateLastReadMessage()
{
auto _snapshot = this->getMessagesSnapshot();
if (_snapshot.size() > 0)
if (auto lastMessage = this->messages_.last())
{
this->lastReadMessage_ = _snapshot[_snapshot.size() - 1];
this->lastReadMessage_ = *lastMessage;
}
this->update();
@@ -1055,7 +1042,7 @@ void ChannelView::paintEvent(QPaintEvent * /*event*/)
// such as the grey overlay when a message is disabled
void ChannelView::drawMessages(QPainter &painter)
{
auto messagesSnapshot = this->getMessagesSnapshot();
auto &messagesSnapshot = this->getMessagesSnapshot();
size_t start = size_t(this->scrollBar_->getCurrentValue());
@@ -1122,7 +1109,7 @@ void ChannelView::drawMessages(QPainter &painter)
// add all messages on screen to the map
for (size_t i = start; i < messagesSnapshot.size(); ++i)
{
std::shared_ptr<MessageLayout> layout = messagesSnapshot[i];
const std::shared_ptr<MessageLayout> &layout = messagesSnapshot[i];
this->messagesOnScreen_.insert(layout);
@@ -1153,7 +1140,7 @@ void ChannelView::wheelEvent(QWheelEvent *event)
qreal desired = this->scrollBar_->getDesiredValue();
qreal delta = event->angleDelta().y() * qreal(1.5) * mouseMultiplier;
auto snapshot = this->getMessagesSnapshot();
auto &snapshot = this->getMessagesSnapshot();
int snapshotLength = int(snapshot.size());
int i = std::min<int>(int(desired), snapshotLength);
@@ -1553,7 +1540,7 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex))
{
setCursor(Qt::ArrowCursor);
auto messagesSnapshot = this->getMessagesSnapshot();
auto &messagesSnapshot = this->getMessagesSnapshot();
if (messagesSnapshot.size() == 0)
{
return;
@@ -2387,7 +2374,7 @@ bool ChannelView::tryGetMessageAt(QPoint p,
std::shared_ptr<MessageLayout> &_message,
QPoint &relativePos, int &index)
{
auto messagesSnapshot = this->getMessagesSnapshot();
auto &messagesSnapshot = this->getMessagesSnapshot();
size_t start = this->scrollBar_->getCurrentValue();