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:
@@ -0,0 +1,132 @@
|
||||
#include "messages/LimitedQueue.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &os,
|
||||
const LimitedQueueSnapshot<T> &snapshot)
|
||||
{
|
||||
os << "[ ";
|
||||
for (size_t i = 0; i < snapshot.size(); ++i)
|
||||
{
|
||||
os << snapshot[i] << ' ';
|
||||
}
|
||||
os << "]";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &os, const vector<T> &vec)
|
||||
{
|
||||
os << "[ ";
|
||||
for (const auto &item : vec)
|
||||
{
|
||||
os << item << ' ';
|
||||
}
|
||||
os << "]";
|
||||
|
||||
return os;
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
template <typename T>
|
||||
inline void SNAPSHOT_EQUALS(const LimitedQueueSnapshot<T> &snapshot,
|
||||
const std::vector<T> &values,
|
||||
const std::string &msg)
|
||||
{
|
||||
SCOPED_TRACE(msg);
|
||||
ASSERT_EQ(snapshot.size(), values.size())
|
||||
<< "snapshot = " << snapshot << " values = " << values;
|
||||
|
||||
if (snapshot.size() != values.size())
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < snapshot.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(snapshot[i], values[i]) << "i = " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LimitedQueue, PushBack)
|
||||
{
|
||||
LimitedQueue<int> queue(5);
|
||||
int d = 0;
|
||||
bool flag;
|
||||
|
||||
EXPECT_TRUE(queue.empty());
|
||||
flag = queue.pushBack(1, d);
|
||||
EXPECT_FALSE(flag);
|
||||
flag = queue.pushBack(2, d);
|
||||
EXPECT_FALSE(flag);
|
||||
|
||||
EXPECT_FALSE(queue.empty());
|
||||
|
||||
auto snapshot1 = queue.getSnapshot();
|
||||
SNAPSHOT_EQUALS(snapshot1, {1, 2}, "first snapshot");
|
||||
|
||||
flag = queue.pushBack(3, d);
|
||||
EXPECT_FALSE(flag);
|
||||
flag = queue.pushBack(4, d);
|
||||
EXPECT_FALSE(flag);
|
||||
|
||||
// snapshot should be the same
|
||||
SNAPSHOT_EQUALS(snapshot1, {1, 2}, "first snapshot same 1");
|
||||
|
||||
flag = queue.pushBack(5, d);
|
||||
EXPECT_FALSE(flag);
|
||||
flag = queue.pushBack(6, d);
|
||||
EXPECT_TRUE(flag);
|
||||
EXPECT_EQ(d, 1);
|
||||
|
||||
SNAPSHOT_EQUALS(snapshot1, {1, 2}, "first snapshot same 2");
|
||||
|
||||
auto snapshot2 = queue.getSnapshot();
|
||||
SNAPSHOT_EQUALS(snapshot2, {2, 3, 4, 5, 6}, "second snapshot");
|
||||
SNAPSHOT_EQUALS(snapshot1, {1, 2}, "first snapshot same 3");
|
||||
}
|
||||
|
||||
TEST(LimitedQueue, PushFront)
|
||||
{
|
||||
LimitedQueue<int> queue(5);
|
||||
queue.pushBack(1);
|
||||
queue.pushBack(2);
|
||||
queue.pushBack(3);
|
||||
|
||||
std::vector<int> expectedPush = {7, 8};
|
||||
auto pushed = queue.pushFront({4, 5, 6, 7, 8});
|
||||
auto snapshot = queue.getSnapshot();
|
||||
SNAPSHOT_EQUALS(snapshot, {7, 8, 1, 2, 3}, "first snapshot");
|
||||
EXPECT_EQ(pushed, expectedPush);
|
||||
|
||||
auto pushed2 = queue.pushFront({9, 10, 11});
|
||||
EXPECT_EQ(pushed2.size(), 0);
|
||||
}
|
||||
|
||||
TEST(LimitedQueue, ReplaceItem)
|
||||
{
|
||||
LimitedQueue<int> queue(5);
|
||||
queue.pushBack(1);
|
||||
queue.pushBack(2);
|
||||
queue.pushBack(3);
|
||||
|
||||
int idex = queue.replaceItem(2, 10);
|
||||
EXPECT_EQ(idex, 1);
|
||||
idex = queue.replaceItem(5, 11);
|
||||
EXPECT_EQ(idex, -1);
|
||||
|
||||
bool res = queue.replaceItem(std::size_t(0), 9);
|
||||
EXPECT_TRUE(res);
|
||||
res = queue.replaceItem(std::size_t(5), 4);
|
||||
EXPECT_FALSE(res);
|
||||
|
||||
SNAPSHOT_EQUALS(queue.getSnapshot(), {9, 10, 3}, "first snapshot");
|
||||
}
|
||||
Reference in New Issue
Block a user