mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 10:25:47 +02:00
chore: Add more qlist tests (#4217)
* chore: Add more qlist tests Also fix a typo bug in NodeAllowMerge. Signed-off-by: Roman Gershman <roman@dragonflydb.io> * chore: fix build --------- Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
dc04b196d5
commit
c9654d4050
3 changed files with 371 additions and 58 deletions
|
@ -65,7 +65,7 @@ static_assert(sizeof(QList) == 32);
|
||||||
enum IterDir : uint8_t { FWD = 1, REV = 0 };
|
enum IterDir : uint8_t { FWD = 1, REV = 0 };
|
||||||
|
|
||||||
/* This is for test suite development purposes only, 0 means disabled. */
|
/* This is for test suite development purposes only, 0 means disabled. */
|
||||||
static size_t packed_threshold = 0;
|
size_t packed_threshold = 0;
|
||||||
|
|
||||||
/* Optimization levels for size-based filling.
|
/* Optimization levels for size-based filling.
|
||||||
* Note that the largest possible limit is 64k, so even if each record takes
|
* Note that the largest possible limit is 64k, so even if each record takes
|
||||||
|
@ -123,7 +123,9 @@ bool NodeAllowMerge(const quicklistNode* a, const quicklistNode* b, const int fi
|
||||||
/* approximate merged listpack size (- 7 to remove one listpack
|
/* approximate merged listpack size (- 7 to remove one listpack
|
||||||
* header/trailer, see LP_HDR_SIZE and LP_EOF) */
|
* header/trailer, see LP_HDR_SIZE and LP_EOF) */
|
||||||
unsigned int merge_sz = a->sz + b->sz - 7;
|
unsigned int merge_sz = a->sz + b->sz - 7;
|
||||||
return quicklistNodeExceedsLimit(fill, merge_sz, a->count + b->count);
|
|
||||||
|
// Allow merge if new node will not exceed the limit.
|
||||||
|
return !quicklistNodeExceedsLimit(fill, merge_sz, a->count + b->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
quicklistNode* CreateNode() {
|
quicklistNode* CreateNode() {
|
||||||
|
@ -140,6 +142,7 @@ quicklistNode* CreateNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* LP_Insert(uint8_t* lp, string_view elem, uint8_t* pos, int lp_where) {
|
uint8_t* LP_Insert(uint8_t* lp, string_view elem, uint8_t* pos, int lp_where) {
|
||||||
|
DCHECK(pos);
|
||||||
return lpInsertString(lp, uint_ptr(elem), elem.size(), pos, lp_where, NULL);
|
return lpInsertString(lp, uint_ptr(elem), elem.size(), pos, lp_where, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +293,10 @@ quicklistNode* SplitNode(quicklistNode* node, int offset, bool after) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void QList::SetPackedThreshold(unsigned threshold) {
|
||||||
|
packed_threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
QList::QList() : fill_(-2), compress_(0), bookmark_count_(0) {
|
QList::QList() : fill_(-2), compress_(0), bookmark_count_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,28 +536,15 @@ void QList::InsertNode(quicklistNode* old_node, quicklistNode* new_node, InsertO
|
||||||
}
|
}
|
||||||
|
|
||||||
void QList::Insert(Iterator it, std::string_view elem, InsertOpt insert_opt) {
|
void QList::Insert(Iterator it, std::string_view elem, InsertOpt insert_opt) {
|
||||||
|
DCHECK(it.current_);
|
||||||
|
DCHECK(it.zi_);
|
||||||
|
|
||||||
int full = 0, at_tail = 0, at_head = 0, avail_next = 0, avail_prev = 0;
|
int full = 0, at_tail = 0, at_head = 0, avail_next = 0, avail_prev = 0;
|
||||||
quicklistNode* node = it.current_;
|
quicklistNode* node = it.current_;
|
||||||
quicklistNode* new_node = NULL;
|
quicklistNode* new_node = NULL;
|
||||||
size_t sz = elem.size();
|
size_t sz = elem.size();
|
||||||
bool after = insert_opt == AFTER;
|
bool after = insert_opt == AFTER;
|
||||||
|
|
||||||
if (!node) {
|
|
||||||
/* we have no reference node, so let's create only node in the list */
|
|
||||||
DCHECK_EQ(count_, 0u);
|
|
||||||
DCHECK_EQ(len_, 0u);
|
|
||||||
|
|
||||||
if (ABSL_PREDICT_FALSE(IsLargeElement(sz, fill_))) {
|
|
||||||
InsertPlainNode(tail_, elem, insert_opt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, elem);
|
|
||||||
InsertNode(NULL, new_node, insert_opt);
|
|
||||||
count_++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Populate accounting flags for easier boolean checks later */
|
/* Populate accounting flags for easier boolean checks later */
|
||||||
if (!NodeAllowInsert(node, fill_, sz)) {
|
if (!NodeAllowInsert(node, fill_, sz)) {
|
||||||
full = 1;
|
full = 1;
|
||||||
|
@ -831,10 +825,10 @@ quicklistNode* QList::ListpackMerge(quicklistNode* a, quicklistNode* b) {
|
||||||
DelNode(nokeep);
|
DelNode(nokeep);
|
||||||
quicklistCompress(keep);
|
quicklistCompress(keep);
|
||||||
return keep;
|
return keep;
|
||||||
} else {
|
|
||||||
/* else, the merge returned NULL and nothing changed. */
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* else, the merge returned NULL and nothing changed. */
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QList::DelNode(quicklistNode* node) {
|
void QList::DelNode(quicklistNode* node) {
|
||||||
|
@ -909,13 +903,13 @@ auto QList::GetIterator(Where where) const -> Iterator {
|
||||||
auto QList::GetIterator(long idx) const -> Iterator {
|
auto QList::GetIterator(long idx) const -> Iterator {
|
||||||
quicklistNode* n;
|
quicklistNode* n;
|
||||||
unsigned long long accum = 0;
|
unsigned long long accum = 0;
|
||||||
unsigned long long index;
|
|
||||||
int forward = idx < 0 ? 0 : 1; /* < 0 -> reverse, 0+ -> forward */
|
int forward = idx < 0 ? 0 : 1; /* < 0 -> reverse, 0+ -> forward */
|
||||||
|
uint64_t index = forward ? idx : (-idx) - 1;
|
||||||
index = forward ? idx : (-idx) - 1;
|
|
||||||
if (index >= count_)
|
if (index >= count_)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
DCHECK(head_);
|
||||||
|
|
||||||
/* Seek in the other direction if that way is shorter. */
|
/* Seek in the other direction if that way is shorter. */
|
||||||
int seek_forward = forward;
|
int seek_forward = forward;
|
||||||
unsigned long long seek_index = index;
|
unsigned long long seek_index = index;
|
||||||
|
|
|
@ -46,6 +46,10 @@ class QList {
|
||||||
|
|
||||||
bool operator==(std::string_view sv) const;
|
bool operator==(std::string_view sv) const;
|
||||||
|
|
||||||
|
friend bool operator==(std::string_view sv, const Entry& entry) {
|
||||||
|
return entry == sv;
|
||||||
|
}
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string to_string() const {
|
||||||
if (std::holds_alternative<int64_t>(value_)) {
|
if (std::holds_alternative<int64_t>(value_)) {
|
||||||
return std::to_string(std::get<int64_t>(value_));
|
return std::to_string(std::get<int64_t>(value_));
|
||||||
|
@ -100,6 +104,8 @@ class QList {
|
||||||
// Returns true if pivot found and elem inserted, false otherwise.
|
// Returns true if pivot found and elem inserted, false otherwise.
|
||||||
bool Insert(std::string_view pivot, std::string_view elem, InsertOpt opt);
|
bool Insert(std::string_view pivot, std::string_view elem, InsertOpt opt);
|
||||||
|
|
||||||
|
void Insert(Iterator it, std::string_view elem, InsertOpt opt);
|
||||||
|
|
||||||
// Returns true if item was replaced, false if index is out of range.
|
// Returns true if item was replaced, false if index is out of range.
|
||||||
bool Replace(long index, std::string_view elem);
|
bool Replace(long index, std::string_view elem);
|
||||||
|
|
||||||
|
@ -141,6 +147,12 @@ class QList {
|
||||||
return tail_;
|
return tail_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_fill(int fill) {
|
||||||
|
fill_ = fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetPackedThreshold(unsigned threshold);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool AllowCompression() const {
|
bool AllowCompression() const {
|
||||||
return compress_ != 0;
|
return compress_ != 0;
|
||||||
|
@ -153,7 +165,6 @@ class QList {
|
||||||
bool PushTail(std::string_view value);
|
bool PushTail(std::string_view value);
|
||||||
void InsertPlainNode(quicklistNode* old_node, std::string_view, InsertOpt insert_opt);
|
void InsertPlainNode(quicklistNode* old_node, std::string_view, InsertOpt insert_opt);
|
||||||
void InsertNode(quicklistNode* old_node, quicklistNode* new_node, InsertOpt insert_opt);
|
void InsertNode(quicklistNode* old_node, quicklistNode* new_node, InsertOpt insert_opt);
|
||||||
void Insert(Iterator it, std::string_view elem, InsertOpt opt);
|
|
||||||
void Replace(Iterator it, std::string_view elem);
|
void Replace(Iterator it, std::string_view elem);
|
||||||
|
|
||||||
void Compress(quicklistNode* node);
|
void Compress(quicklistNode* node);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "core/qlist.h"
|
#include "core/qlist.h"
|
||||||
|
|
||||||
|
#include <absl/strings/match.h>
|
||||||
#include <absl/strings/str_cat.h>
|
#include <absl/strings/str_cat.h>
|
||||||
#include <absl/strings/str_format.h>
|
#include <absl/strings/str_format.h>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
@ -76,6 +77,7 @@ static int ql_verify(const QList& ql, uint32_t nc, uint32_t count, uint32_t head
|
||||||
while (node) {
|
while (node) {
|
||||||
node_size += node->count;
|
node_size += node->count;
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
CHECK(node != ql.Head());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node_size != ql.Size()) {
|
if (node_size != ql.Size()) {
|
||||||
|
@ -101,13 +103,13 @@ static int ql_verify(const QList& ql, uint32_t nc, uint32_t count, uint32_t head
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ql.Head() && head_count != ql.Head()->count && head_count != lpLength(ql.Head()->entry)) {
|
if (head_count != ql.Head()->count && head_count != lpLength(ql.Head()->entry)) {
|
||||||
LOG(ERROR) << absl::StrFormat("head count wrong: expected %u got cached %u vs. actual %lu",
|
LOG(ERROR) << absl::StrFormat("head count wrong: expected %u got cached %u vs. actual %lu",
|
||||||
head_count, ql.Head()->count, lpLength(ql.Head()->entry));
|
head_count, ql.Head()->count, lpLength(ql.Head()->entry));
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ql.Tail() && tail_count != ql.Tail()->count && tail_count != lpLength(ql.Tail()->entry)) {
|
if (tail_count != ql.Tail()->count && tail_count != lpLength(ql.Tail()->entry)) {
|
||||||
LOG(ERROR) << "tail count wrong: expected " << tail_count << "got cached " << ql.Tail()->count
|
LOG(ERROR) << "tail count wrong: expected " << tail_count << "got cached " << ql.Tail()->count
|
||||||
<< " vs. actual " << lpLength(ql.Tail()->entry);
|
<< " vs. actual " << lpLength(ql.Tail()->entry);
|
||||||
errors++;
|
errors++;
|
||||||
|
@ -247,6 +249,37 @@ TEST_F(QListTest, PushPlain) {
|
||||||
EXPECT_THAT(items, ElementsAre(val));
|
EXPECT_THAT(items, ElementsAre(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(QListTest, GetNum) {
|
||||||
|
ql_.Push("1251977", QList::HEAD);
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
EXPECT_EQ(1251977, it.Get().ival());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QListTest, CompressionPlain) {
|
||||||
|
char buf[256];
|
||||||
|
QList::SetPackedThreshold(1);
|
||||||
|
ql_ = QList(-2, 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 500; i++) {
|
||||||
|
/* Set to 256 to allow the node to be triggered to compress,
|
||||||
|
* if it is less than 48(nocompress), the test will be successful. */
|
||||||
|
snprintf(buf, sizeof(buf), "hello%d", i);
|
||||||
|
ql_.Push(string_view{buf, sizeof(buf)}, QList::HEAD);
|
||||||
|
}
|
||||||
|
QList::SetPackedThreshold(0);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||||
|
int i = 0;
|
||||||
|
while (it.Next()) {
|
||||||
|
string_view sv = it.Get().view();
|
||||||
|
ASSERT_EQ(sizeof(buf), sv.size());
|
||||||
|
ASSERT_TRUE(absl::StartsWith(sv, StrCat("hello", i)));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(500, i);
|
||||||
|
}
|
||||||
|
|
||||||
using FillCompress = tuple<int, unsigned>;
|
using FillCompress = tuple<int, unsigned>;
|
||||||
|
|
||||||
class PrintToFillCompress {
|
class PrintToFillCompress {
|
||||||
|
@ -289,6 +322,25 @@ TEST_P(OptionsTest, Numbers) {
|
||||||
EXPECT_EQ("xxxxxxxxxxxxxxxxxxxx", it.Get().view());
|
EXPECT_EQ("xxxxxxxxxxxxxxxxxxxx", it.Get().view());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, NumbersIndex) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
|
||||||
|
long long nums[5000];
|
||||||
|
for (int i = 0; i < 760; i++) {
|
||||||
|
nums[i] = -5157318210846258176 + i;
|
||||||
|
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i = 437;
|
||||||
|
QList::Iterator it = ql_.GetIterator(i);
|
||||||
|
while (it.Next()) {
|
||||||
|
ASSERT_EQ(nums[i], it.Get().ival());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ASSERT_EQ(760, i);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelRangeA) {
|
TEST_P(OptionsTest, DelRangeA) {
|
||||||
auto [fill, compress] = GetParam();
|
auto [fill, compress] = GetParam();
|
||||||
ql_ = QList(fill, compress);
|
ql_ = QList(fill, compress);
|
||||||
|
@ -297,15 +349,17 @@ TEST_P(OptionsTest, DelRangeA) {
|
||||||
nums[i] = -5157318210846258176 + i;
|
nums[i] = -5157318210846258176 + i;
|
||||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||||
}
|
}
|
||||||
if (fill == 32)
|
|
||||||
ql_verify(ql_, 2, 33, 32, 1);
|
if (fill == 32) {
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||||
|
}
|
||||||
|
|
||||||
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
||||||
ql_.Erase(0, 3);
|
ql_.Erase(0, 3);
|
||||||
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 1, 1, 1, 1);
|
ASSERT_EQ(0, ql_verify(ql_, 1, 1, 1, 1));
|
||||||
|
}
|
||||||
auto it = ql_.GetIterator(0);
|
auto it = ql_.GetIterator(0);
|
||||||
ASSERT_TRUE(it.Next());
|
ASSERT_TRUE(it.Next());
|
||||||
EXPECT_EQ(-5157318210846258173, it.Get().ival());
|
EXPECT_EQ(-5157318210846258173, it.Get().ival());
|
||||||
|
@ -320,14 +374,15 @@ TEST_P(OptionsTest, DelRangeB) {
|
||||||
nums[i] = i;
|
nums[i] = i;
|
||||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||||
}
|
}
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 2, 33, 32, 1);
|
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||||
|
}
|
||||||
/* ltrim 5 16 (keep [5,16] inclusive = 12 remaining) */
|
/* ltrim 5 16 (keep [5,16] inclusive = 12 remaining) */
|
||||||
ql_.Erase(0, 5);
|
ql_.Erase(0, 5);
|
||||||
ql_.Erase(-16, 16);
|
ql_.Erase(-16, 16);
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 1, 12, 12, 12);
|
ASSERT_EQ(0, ql_verify(ql_, 1, 12, 12, 12));
|
||||||
|
}
|
||||||
|
|
||||||
auto it = ql_.GetIterator(0);
|
auto it = ql_.GetIterator(0);
|
||||||
ASSERT_TRUE(it.Next());
|
ASSERT_TRUE(it.Next());
|
||||||
|
@ -357,14 +412,16 @@ TEST_P(OptionsTest, DelRangeC) {
|
||||||
nums[i] = -5157318210846258176 + i;
|
nums[i] = -5157318210846258176 + i;
|
||||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||||
}
|
}
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 2, 33, 32, 1);
|
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||||
|
}
|
||||||
|
|
||||||
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
||||||
ql_.Erase(0, 3);
|
ql_.Erase(0, 3);
|
||||||
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 1, 1, 1, 1);
|
ASSERT_EQ(0, ql_verify(ql_, 1, 1, 1, 1));
|
||||||
|
}
|
||||||
auto it = ql_.GetIterator(0);
|
auto it = ql_.GetIterator(0);
|
||||||
ASSERT_TRUE(it.Next());
|
ASSERT_TRUE(it.Next());
|
||||||
ASSERT_EQ(-5157318210846258173, it.Get().ival());
|
ASSERT_EQ(-5157318210846258173, it.Get().ival());
|
||||||
|
@ -378,8 +435,9 @@ TEST_P(OptionsTest, DelRangeD) {
|
||||||
nums[i] = -5157318210846258176 + i;
|
nums[i] = -5157318210846258176 + i;
|
||||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||||
}
|
}
|
||||||
if (fill == 32)
|
if (fill == 32) {
|
||||||
ql_verify(ql_, 2, 33, 32, 1);
|
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||||
|
}
|
||||||
ql_.Erase(-12, 3);
|
ql_.Erase(-12, 3);
|
||||||
|
|
||||||
ASSERT_EQ(30, ql_.Size());
|
ASSERT_EQ(30, ql_.Size());
|
||||||
|
@ -392,9 +450,9 @@ TEST_P(OptionsTest, DelRangeNode) {
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
|
|
||||||
ql_verify(ql_, 1, 32, 32, 32);
|
ASSERT_EQ(0, ql_verify(ql_, 1, 32, 32, 32));
|
||||||
ql_.Erase(0, 32);
|
ql_.Erase(0, 32);
|
||||||
ql_verify(ql_, 0, 0, 0, 0);
|
ASSERT_EQ(0, ql_verify(ql_, 0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelRangeNodeOverflow) {
|
TEST_P(OptionsTest, DelRangeNodeOverflow) {
|
||||||
|
@ -403,9 +461,9 @@ TEST_P(OptionsTest, DelRangeNodeOverflow) {
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
ql_verify(ql_, 1, 32, 32, 32);
|
ASSERT_EQ(0, ql_verify(ql_, 1, 32, 32, 32));
|
||||||
ql_.Erase(0, 128);
|
ql_.Erase(0, 128);
|
||||||
ql_verify(ql_, 0, 0, 0, 0);
|
ASSERT_EQ(0, ql_verify(ql_, 0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelRangeMiddle100of500) {
|
TEST_P(OptionsTest, DelRangeMiddle100of500) {
|
||||||
|
@ -415,9 +473,9 @@ TEST_P(OptionsTest, DelRangeMiddle100of500) {
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
|
|
||||||
ql_verify(ql_, 16, 500, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||||
ql_.Erase(200, 100);
|
ql_.Erase(200, 100);
|
||||||
ql_verify(ql_, 14, 400, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 14, 400, 32, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelLessFillAcrossNodes) {
|
TEST_P(OptionsTest, DelLessFillAcrossNodes) {
|
||||||
|
@ -426,9 +484,9 @@ TEST_P(OptionsTest, DelLessFillAcrossNodes) {
|
||||||
|
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
ql_verify(ql_, 16, 500, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||||
ql_.Erase(60, 10);
|
ql_.Erase(60, 10);
|
||||||
ql_verify(ql_, 16, 490, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 490, 32, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelNegOne) {
|
TEST_P(OptionsTest, DelNegOne) {
|
||||||
|
@ -436,9 +494,9 @@ TEST_P(OptionsTest, DelNegOne) {
|
||||||
ql_ = QList(32, compress);
|
ql_ = QList(32, compress);
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
ql_verify(ql_, 16, 500, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||||
ql_.Erase(-1, 1);
|
ql_.Erase(-1, 1);
|
||||||
ql_verify(ql_, 16, 499, 32, 19);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 499, 32, 19));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelNegOneOverflow) {
|
TEST_P(OptionsTest, DelNegOneOverflow) {
|
||||||
|
@ -447,10 +505,10 @@ TEST_P(OptionsTest, DelNegOneOverflow) {
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
|
|
||||||
ql_verify(ql_, 16, 500, 32, 20);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||||
ql_.Erase(-1, 128);
|
ql_.Erase(-1, 128);
|
||||||
|
|
||||||
ql_verify(ql_, 16, 499, 32, 19);
|
ASSERT_EQ(0, ql_verify(ql_, 16, 499, 32, 19));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelNeg100From500) {
|
TEST_P(OptionsTest, DelNeg100From500) {
|
||||||
|
@ -459,7 +517,7 @@ TEST_P(OptionsTest, DelNeg100From500) {
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
ql_.Erase(-100, 100);
|
ql_.Erase(-100, 100);
|
||||||
ql_verify(ql_, 13, 400, 32, 16);
|
ASSERT_EQ(0, ql_verify(ql_, 13, 400, 32, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelMin10_5_from50) {
|
TEST_P(OptionsTest, DelMin10_5_from50) {
|
||||||
|
@ -468,9 +526,9 @@ TEST_P(OptionsTest, DelMin10_5_from50) {
|
||||||
|
|
||||||
for (int i = 0; i < 50; i++)
|
for (int i = 0; i < 50; i++)
|
||||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
ql_verify(ql_, 2, 50, 32, 18);
|
ASSERT_EQ(0, ql_verify(ql_, 2, 50, 32, 18));
|
||||||
ql_.Erase(-10, 5);
|
ql_.Erase(-10, 5);
|
||||||
ql_verify(ql_, 2, 45, 32, 13);
|
ASSERT_EQ(0, ql_verify(ql_, 2, 45, 32, 13));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(OptionsTest, DelElems) {
|
TEST_P(OptionsTest, DelElems) {
|
||||||
|
@ -513,4 +571,254 @@ TEST_P(OptionsTest, DelElems) {
|
||||||
EXPECT_THAT(ToItems(), ElementsAreArray(resultB));
|
EXPECT_THAT(ToItems(), ElementsAreArray(resultB));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, IterateReverse) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(32, compress);
|
||||||
|
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||||
|
int i = 0;
|
||||||
|
while (it.Next()) {
|
||||||
|
ASSERT_EQ(StrCat("hello", i), it.Get());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ASSERT_EQ(500, i);
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 20, 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, Iterate500) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(32, compress);
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||||
|
int i = 499, count = 0;
|
||||||
|
while (it.Next()) {
|
||||||
|
QList::Entry entry = it.Get();
|
||||||
|
ASSERT_EQ(StrCat("hello", i), entry);
|
||||||
|
i--;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(500, count);
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 20, 32));
|
||||||
|
|
||||||
|
it = ql_.GetIterator(QList::TAIL);
|
||||||
|
i = 0;
|
||||||
|
while (it.Next()) {
|
||||||
|
ASSERT_EQ(StrCat("hello", i), it.Get());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(500, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, IterateAfterOne) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(-2, compress);
|
||||||
|
ql_.Push("hello", QList::HEAD);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(0);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ql_.Insert(it, "abc", QList::AFTER);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 1, 2, 2, 2));
|
||||||
|
|
||||||
|
/* verify results */
|
||||||
|
it = ql_.GetIterator(0);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(1);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("abc", it.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, IterateDelete) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
|
||||||
|
ql_.Push("abc", QList::TAIL);
|
||||||
|
ql_.Push("def", QList::TAIL);
|
||||||
|
ql_.Push("hij", QList::TAIL);
|
||||||
|
ql_.Push("jkl", QList::TAIL);
|
||||||
|
ql_.Push("oop", QList::TAIL);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||||
|
int i = 0;
|
||||||
|
while (it.Next()) {
|
||||||
|
if (it.Get() == "hij") {
|
||||||
|
it = ql_.Erase(it);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(5, i);
|
||||||
|
|
||||||
|
ASSERT_THAT(ToItems(), ElementsAre("abc", "def", "jkl", "oop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertBeforeOne) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(-2, compress);
|
||||||
|
|
||||||
|
ql_.Push("hello", QList::HEAD);
|
||||||
|
QList::Iterator it = ql_.GetIterator(0);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ql_.Insert(it, "abc", QList::BEFORE);
|
||||||
|
ql_verify(ql_, 1, 2, 2, 2);
|
||||||
|
|
||||||
|
/* verify results */
|
||||||
|
it = ql_.GetIterator(0);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("abc", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(1);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello", it.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertWithHeadFull) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(4, compress);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
ql_.Push(StrCat("hello", i), QList::TAIL);
|
||||||
|
|
||||||
|
ql_.set_fill(-1);
|
||||||
|
QList::Iterator it = ql_.GetIterator(-10);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
|
||||||
|
char buf[4096] = {0};
|
||||||
|
ql_.Insert(it, string_view{buf, sizeof(buf)}, QList::BEFORE);
|
||||||
|
ql_verify(ql_, 4, 11, 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertWithTailFull) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(4, compress);
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
|
|
||||||
|
ql_.set_fill(-1);
|
||||||
|
QList::Iterator it = ql_.GetIterator(-1);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
|
||||||
|
char buf[4096] = {0};
|
||||||
|
ql_.Insert(it, string_view{buf, sizeof(buf)}, QList::AFTER);
|
||||||
|
ql_verify(ql_, 4, 11, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertOnceWhileIterating) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
|
||||||
|
ql_.Push("abc", QList::TAIL);
|
||||||
|
ql_.set_fill(1);
|
||||||
|
|
||||||
|
ql_.Push("def", QList::TAIL);
|
||||||
|
ql_.set_fill(fill);
|
||||||
|
ql_.Push("bob", QList::TAIL);
|
||||||
|
ql_.Push("foo", QList::TAIL);
|
||||||
|
ql_.Push("zoo", QList::TAIL);
|
||||||
|
|
||||||
|
/* insert "bar" before "bob" while iterating over list. */
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||||
|
while (it.Next()) {
|
||||||
|
if (it.Get() == "bob") {
|
||||||
|
ql_.Insert(it, "bar", QList::BEFORE);
|
||||||
|
break; /* didn't we fix insert-while-iterating? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_THAT(ToItems(), ElementsAre("abc", "def", "bar", "bob", "foo", "zoo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertBefore250NewInMiddleOf500Elements) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
for (int i = 0; i < 500; i++) {
|
||||||
|
string val = StrCat("hello", i);
|
||||||
|
val.resize(32);
|
||||||
|
ql_.Push(val, QList::TAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 250; i++) {
|
||||||
|
QList::Iterator it = ql_.GetIterator(250);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ql_.Insert(it, StrCat("abc", i), QList::BEFORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fill == 32) {
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 25, 750, 32, 20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, InsertAfter250NewInMiddleOf500Elements) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||||
|
|
||||||
|
for (int i = 0; i < 250; i++) {
|
||||||
|
QList::Iterator it = ql_.GetIterator(250);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ql_.Insert(it, StrCat("abc", i), QList::AFTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(750, ql_.Size());
|
||||||
|
|
||||||
|
if (fill == 32) {
|
||||||
|
ASSERT_EQ(0, ql_verify(ql_, 26, 750, 20, 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, NextPlain) {
|
||||||
|
auto [_, compress] = GetParam();
|
||||||
|
ql_ = QList(-2, compress);
|
||||||
|
|
||||||
|
QList::SetPackedThreshold(3);
|
||||||
|
|
||||||
|
const char* strings[] = {"hello1", "hello2", "h3", "h4", "hello5"};
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
ql_.Push(strings[i], QList::HEAD);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while (it.Next()) {
|
||||||
|
ASSERT_EQ(strings[j], it.Get());
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OptionsTest, IndexFrom500) {
|
||||||
|
auto [fill, compress] = GetParam();
|
||||||
|
ql_ = QList(fill, compress);
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||||
|
|
||||||
|
QList::Iterator it = ql_.GetIterator(1);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello2", it.Get());
|
||||||
|
it = ql_.GetIterator(200);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello201", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(-1);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello500", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(-2);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello499", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(-100);
|
||||||
|
ASSERT_TRUE(it.Next());
|
||||||
|
ASSERT_EQ("hello401", it.Get());
|
||||||
|
|
||||||
|
it = ql_.GetIterator(500);
|
||||||
|
ASSERT_FALSE(it.Next());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue