mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 10:25:47 +02:00
feat: add iterators
This commit is contained in:
parent
33dba31e81
commit
fe3b3a24f2
4 changed files with 98 additions and 56 deletions
|
@ -5,6 +5,6 @@
|
||||||
#include "intrusive_string_list.h"
|
#include "intrusive_string_list.h"
|
||||||
|
|
||||||
namespace dfly {
|
namespace dfly {
|
||||||
ISLEntry IntrusiveStringList::Iterator::end_;
|
ISLEntry IntrusiveStringList::end_;
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
|
@ -196,7 +196,7 @@ class UniqueISLEntry : private ISLEntry {
|
||||||
|
|
||||||
class IntrusiveStringList {
|
class IntrusiveStringList {
|
||||||
public:
|
public:
|
||||||
class Iterator {
|
class iterator {
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::forward_iterator_tag;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
|
@ -204,7 +204,7 @@ class IntrusiveStringList {
|
||||||
using pointer = ISLEntry*;
|
using pointer = ISLEntry*;
|
||||||
using reference = ISLEntry&;
|
using reference = ISLEntry&;
|
||||||
|
|
||||||
Iterator(ISLEntry prev = end_.FakePrev()) : prev_(prev) {
|
iterator(ISLEntry prev = end_.FakePrev()) : prev_(prev) {
|
||||||
DCHECK(prev);
|
DCHECK(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ class IntrusiveStringList {
|
||||||
return prev_.Next().HasExpiry();
|
return prev_.Next().HasExpiry();
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator& operator++() {
|
iterator& operator++() {
|
||||||
prev_ = prev_.Next();
|
prev_ = prev_.Next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -243,9 +243,16 @@ class IntrusiveStringList {
|
||||||
return prev_.Next();
|
return prev_.Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator& r) {
|
||||||
|
return prev_.Next() == r.prev_.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& r) {
|
||||||
|
return !operator==(r);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISLEntry prev_;
|
ISLEntry prev_;
|
||||||
static ISLEntry end_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~IntrusiveStringList() {
|
~IntrusiveStringList() {
|
||||||
|
@ -262,10 +269,14 @@ class IntrusiveStringList {
|
||||||
r.start_ = {};
|
r.start_ = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator begin() {
|
iterator begin() {
|
||||||
return start_.FakePrev();
|
return start_.FakePrev();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static iterator end() {
|
||||||
|
return end_.FakePrev();
|
||||||
|
}
|
||||||
|
|
||||||
ISLEntry Insert(ISLEntry e) {
|
ISLEntry Insert(ISLEntry e) {
|
||||||
e.SetNext(start_);
|
e.SetNext(start_);
|
||||||
start_ = e;
|
start_ = e;
|
||||||
|
@ -286,7 +297,7 @@ class IntrusiveStringList {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Empty() {
|
bool Empty() {
|
||||||
return start_;
|
return !start_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO consider to wrap ISLEntry to prevent usage out of the list
|
// TODO consider to wrap ISLEntry to prevent usage out of the list
|
||||||
|
@ -295,7 +306,7 @@ class IntrusiveStringList {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO consider to wrap ISLEntry to prevent usage out of the list
|
// TODO consider to wrap ISLEntry to prevent usage out of the list
|
||||||
IntrusiveStringList::Iterator Find(std::string_view str) {
|
IntrusiveStringList::iterator Find(std::string_view str) {
|
||||||
auto it = begin();
|
auto it = begin();
|
||||||
for (; it && it->Key() != str; ++it)
|
for (; it && it->Key() != str; ++it)
|
||||||
;
|
;
|
||||||
|
@ -350,6 +361,7 @@ class IntrusiveStringList {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISLEntry start_;
|
ISLEntry start_;
|
||||||
|
static ISLEntry end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
|
@ -24,13 +24,16 @@ class IntrusiveStringSet {
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::forward_iterator_tag;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
using value_type = std::string_view;
|
using value_type = ISLEntry;
|
||||||
using pointer = std::string_view*;
|
using pointer = ISLEntry*;
|
||||||
using reference = std::string_view&;
|
using reference = ISLEntry&;
|
||||||
|
|
||||||
iterator(Buckets::iterator it,
|
iterator(Buckets::iterator it, Buckets::iterator end, IntrusiveStringList::iterator entry)
|
||||||
IntrusiveStringList::Iterator entry = IntrusiveStringList::Iterator())
|
: buckets_it_(it), end_(end), entry_(entry) {
|
||||||
: buckets_it_(it), entry_(entry) {
|
}
|
||||||
|
|
||||||
|
iterator(Buckets::iterator it, Buckets::iterator end) : buckets_it_(it), end_(end) {
|
||||||
|
SetEntryIt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32_t ExpiryTime() const {
|
// uint32_t ExpiryTime() const {
|
||||||
|
@ -47,29 +50,56 @@ class IntrusiveStringSet {
|
||||||
|
|
||||||
// void Advance();
|
// void Advance();
|
||||||
|
|
||||||
|
iterator& operator++() {
|
||||||
|
// TODO add expiration logic
|
||||||
|
if (entry_)
|
||||||
|
++entry_;
|
||||||
|
if (!entry_) {
|
||||||
|
++buckets_it_;
|
||||||
|
SetEntryIt();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const iterator& r) const {
|
bool operator==(const iterator& r) const {
|
||||||
return buckets_it_ == r.buckets_it_;
|
return buckets_it_ == r.buckets_it_ && entry_ == r.entry_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const iterator& r) const {
|
bool operator!=(const iterator& r) const {
|
||||||
return !operator==(r);
|
return !operator==(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
IntrusiveStringList::Iterator::value_type operator*() {
|
IntrusiveStringList::iterator::value_type operator*() {
|
||||||
return *entry_;
|
return *entry_;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntrusiveStringList::Iterator operator->() {
|
IntrusiveStringList::iterator operator->() {
|
||||||
return entry_;
|
return entry_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// find valid entry_ iterator starting from buckets_it_ and set it
|
||||||
|
void SetEntryIt() {
|
||||||
|
for (; buckets_it_ != end_; ++buckets_it_) {
|
||||||
|
if (!buckets_it_->Empty()) {
|
||||||
|
entry_ = buckets_it_->begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Buckets::iterator buckets_it_;
|
Buckets::iterator buckets_it_;
|
||||||
IntrusiveStringList::Iterator entry_;
|
Buckets::iterator end_;
|
||||||
|
IntrusiveStringList::iterator entry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return iterator(entries_.begin(), entries_.end());
|
||||||
|
}
|
||||||
|
|
||||||
iterator end() {
|
iterator end() {
|
||||||
return iterator(entries_.end());
|
return iterator(entries_.end(), entries_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit IntrusiveStringSet(PMR_NS::memory_resource* mr = PMR_NS::get_default_resource())
|
explicit IntrusiveStringSet(PMR_NS::memory_resource* mr = PMR_NS::get_default_resource())
|
||||||
|
@ -182,11 +212,11 @@ class IntrusiveStringSet {
|
||||||
|
|
||||||
iterator Find(std::string_view member) {
|
iterator Find(std::string_view member) {
|
||||||
if (entries_.empty())
|
if (entries_.empty())
|
||||||
return iterator(entries_.end());
|
return end();
|
||||||
auto bucket_id = BucketId(Hash(member));
|
auto bucket_id = BucketId(Hash(member));
|
||||||
auto entry_it = entries_.begin() + bucket_id;
|
auto entry_it = entries_.begin() + bucket_id;
|
||||||
auto res = entry_it->Find(member);
|
auto res = entry_it->Find(member);
|
||||||
return iterator(res ? entry_it : entries_.end(), res);
|
return iterator(res ? entry_it : entries_.end(), entries_.end(), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Contains(std::string_view member) {
|
bool Contains(std::string_view member) {
|
||||||
|
|
|
@ -75,6 +75,18 @@ class IntrusiveStringSetTest : public ::testing::Test {
|
||||||
mt19937 generator_;
|
mt19937 generator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static string random_string(mt19937& rand, unsigned len) {
|
||||||
|
const string_view alpanum = "1234567890abcdefghijklmnopqrstuvwxyz";
|
||||||
|
string ret;
|
||||||
|
ret.reserve(len);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
ret += alpanum[rand() % alpanum.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrusiveStringSetTest, IntrusiveStringListTest) {
|
TEST_F(IntrusiveStringSetTest, IntrusiveStringListTest) {
|
||||||
IntrusiveStringList isl;
|
IntrusiveStringList isl;
|
||||||
ISLEntry test = isl.Emplace("0123456789");
|
ISLEntry test = isl.Emplace("0123456789");
|
||||||
|
@ -208,18 +220,6 @@ TEST_F(IntrusiveStringSetTest, DisplacedBug) {
|
||||||
ss_->Add("HPq");
|
ss_->Add("HPq");
|
||||||
}
|
}
|
||||||
|
|
||||||
static string random_string(mt19937& rand, unsigned len) {
|
|
||||||
const string_view alpanum = "1234567890abcdefghijklmnopqrstuvwxyz";
|
|
||||||
string ret;
|
|
||||||
ret.reserve(len);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
ret += alpanum[rand() % alpanum.size()];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IntrusiveStringSetTest, Resizing) {
|
TEST_F(IntrusiveStringSetTest, Resizing) {
|
||||||
constexpr size_t num_strs = 4096;
|
constexpr size_t num_strs = 4096;
|
||||||
unordered_set<string> strs;
|
unordered_set<string> strs;
|
||||||
|
@ -434,33 +434,33 @@ TEST_F(IntrusiveStringSetTest, Pop) {
|
||||||
DCHECK(to_insert.empty());
|
DCHECK(to_insert.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_F(IntrusiveStringSetTest, Iteration) {
|
TEST_F(IntrusiveStringSetTest, Iteration) {
|
||||||
// ss_->Add("foo");
|
ss_->Add("foo");
|
||||||
// for (const sds ptr : *ss_) {
|
for (const auto& ptr : *ss_) {
|
||||||
// LOG(INFO) << ptr;
|
LOG(INFO) << ptr;
|
||||||
// }
|
}
|
||||||
// ss_->Clear();
|
ss_->Clear();
|
||||||
// constexpr size_t num_items = 8192;
|
constexpr size_t num_items = 8192;
|
||||||
// unordered_set<string> to_insert;
|
unordered_set<string> to_insert;
|
||||||
|
|
||||||
// while (to_insert.size() != num_items) {
|
while (to_insert.size() != num_items) {
|
||||||
// auto str = random_string(generator_, 10);
|
auto str = random_string(generator_, 10);
|
||||||
// if (to_insert.count(str)) {
|
if (to_insert.count(str)) {
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// to_insert.insert(str);
|
to_insert.insert(str);
|
||||||
// EXPECT_TRUE(ss_->Add(str));
|
EXPECT_TRUE(ss_->Add(str));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// for (const sds ptr : *ss_) {
|
for (const auto& ptr : *ss_) {
|
||||||
// string str{ptr, sdslen(ptr)};
|
std::string str(ptr.Key());
|
||||||
// EXPECT_TRUE(to_insert.count(str));
|
EXPECT_TRUE(to_insert.count(str));
|
||||||
// to_insert.erase(str);
|
to_insert.erase(str);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// EXPECT_EQ(to_insert.size(), 0);
|
EXPECT_EQ(to_insert.size(), 0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
TEST_F(IntrusiveStringSetTest, SetFieldExpireHasExpiry) {
|
TEST_F(IntrusiveStringSetTest, SetFieldExpireHasExpiry) {
|
||||||
EXPECT_TRUE(ss_->Add("k1", 100));
|
EXPECT_TRUE(ss_->Add("k1", 100));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue