feat: add iterators

This commit is contained in:
Borys 2025-04-25 11:49:02 +03:00
parent 33dba31e81
commit fe3b3a24f2
No known key found for this signature in database
GPG key ID: 753496F020ABFD14
4 changed files with 98 additions and 56 deletions

View file

@ -5,6 +5,6 @@
#include "intrusive_string_list.h"
namespace dfly {
ISLEntry IntrusiveStringList::Iterator::end_;
ISLEntry IntrusiveStringList::end_;
} // namespace dfly

View file

@ -196,7 +196,7 @@ class UniqueISLEntry : private ISLEntry {
class IntrusiveStringList {
public:
class Iterator {
class iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
@ -204,7 +204,7 @@ class IntrusiveStringList {
using pointer = ISLEntry*;
using reference = ISLEntry&;
Iterator(ISLEntry prev = end_.FakePrev()) : prev_(prev) {
iterator(ISLEntry prev = end_.FakePrev()) : prev_(prev) {
DCHECK(prev);
}
@ -226,7 +226,7 @@ class IntrusiveStringList {
return prev_.Next().HasExpiry();
}
Iterator& operator++() {
iterator& operator++() {
prev_ = prev_.Next();
return *this;
}
@ -243,9 +243,16 @@ class IntrusiveStringList {
return prev_.Next();
}
bool operator==(const iterator& r) {
return prev_.Next() == r.prev_.Next();
}
bool operator!=(const iterator& r) {
return !operator==(r);
}
private:
ISLEntry prev_;
static ISLEntry end_;
};
~IntrusiveStringList() {
@ -262,10 +269,14 @@ class IntrusiveStringList {
r.start_ = {};
}
Iterator begin() {
iterator begin() {
return start_.FakePrev();
}
static iterator end() {
return end_.FakePrev();
}
ISLEntry Insert(ISLEntry e) {
e.SetNext(start_);
start_ = e;
@ -286,7 +297,7 @@ class IntrusiveStringList {
}
bool Empty() {
return start_;
return !start_;
}
// 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
IntrusiveStringList::Iterator Find(std::string_view str) {
IntrusiveStringList::iterator Find(std::string_view str) {
auto it = begin();
for (; it && it->Key() != str; ++it)
;
@ -350,6 +361,7 @@ class IntrusiveStringList {
private:
ISLEntry start_;
static ISLEntry end_;
};
} // namespace dfly

View file

@ -24,13 +24,16 @@ class IntrusiveStringSet {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = std::string_view;
using pointer = std::string_view*;
using reference = std::string_view&;
using value_type = ISLEntry;
using pointer = ISLEntry*;
using reference = ISLEntry&;
iterator(Buckets::iterator it,
IntrusiveStringList::Iterator entry = IntrusiveStringList::Iterator())
: buckets_it_(it), entry_(entry) {
iterator(Buckets::iterator it, Buckets::iterator end, IntrusiveStringList::iterator entry)
: buckets_it_(it), end_(end), entry_(entry) {
}
iterator(Buckets::iterator it, Buckets::iterator end) : buckets_it_(it), end_(end) {
SetEntryIt();
}
// uint32_t ExpiryTime() const {
@ -47,29 +50,56 @@ class IntrusiveStringSet {
// void Advance();
iterator& operator++() {
// TODO add expiration logic
if (entry_)
++entry_;
if (!entry_) {
++buckets_it_;
SetEntryIt();
}
return *this;
}
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 {
return !operator==(r);
}
IntrusiveStringList::Iterator::value_type operator*() {
IntrusiveStringList::iterator::value_type operator*() {
return *entry_;
}
IntrusiveStringList::Iterator operator->() {
IntrusiveStringList::iterator operator->() {
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:
Buckets::iterator buckets_it_;
IntrusiveStringList::Iterator entry_;
Buckets::iterator end_;
IntrusiveStringList::iterator entry_;
};
iterator begin() {
return iterator(entries_.begin(), entries_.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())
@ -182,11 +212,11 @@ class IntrusiveStringSet {
iterator Find(std::string_view member) {
if (entries_.empty())
return iterator(entries_.end());
return end();
auto bucket_id = BucketId(Hash(member));
auto entry_it = entries_.begin() + bucket_id;
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) {

View file

@ -75,6 +75,18 @@ class IntrusiveStringSetTest : public ::testing::Test {
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) {
IntrusiveStringList isl;
ISLEntry test = isl.Emplace("0123456789");
@ -208,18 +220,6 @@ TEST_F(IntrusiveStringSetTest, DisplacedBug) {
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) {
constexpr size_t num_strs = 4096;
unordered_set<string> strs;
@ -434,33 +434,33 @@ TEST_F(IntrusiveStringSetTest, Pop) {
DCHECK(to_insert.empty());
}
// TEST_F(IntrusiveStringSetTest, Iteration) {
// ss_->Add("foo");
// for (const sds ptr : *ss_) {
// LOG(INFO) << ptr;
// }
// ss_->Clear();
// constexpr size_t num_items = 8192;
// unordered_set<string> to_insert;
TEST_F(IntrusiveStringSetTest, Iteration) {
ss_->Add("foo");
for (const auto& ptr : *ss_) {
LOG(INFO) << ptr;
}
ss_->Clear();
constexpr size_t num_items = 8192;
unordered_set<string> to_insert;
// while (to_insert.size() != num_items) {
// auto str = random_string(generator_, 10);
// if (to_insert.count(str)) {
// continue;
// }
while (to_insert.size() != num_items) {
auto str = random_string(generator_, 10);
if (to_insert.count(str)) {
continue;
}
// to_insert.insert(str);
// EXPECT_TRUE(ss_->Add(str));
// }
to_insert.insert(str);
EXPECT_TRUE(ss_->Add(str));
}
// for (const sds ptr : *ss_) {
// string str{ptr, sdslen(ptr)};
// EXPECT_TRUE(to_insert.count(str));
// to_insert.erase(str);
// }
for (const auto& ptr : *ss_) {
std::string str(ptr.Key());
EXPECT_TRUE(to_insert.count(str));
to_insert.erase(str);
}
// EXPECT_EQ(to_insert.size(), 0);
// }
EXPECT_EQ(to_insert.size(), 0);
}
TEST_F(IntrusiveStringSetTest, SetFieldExpireHasExpiry) {
EXPECT_TRUE(ss_->Add("k1", 100));