@@ -24,30 +24,37 @@ template <typename V> struct RaxTreeMap {
24
24
25
25
// Simple seeking iterator
26
26
struct SeekIterator {
27
- friend struct FindIterator ;
28
-
29
27
SeekIterator () {
30
- raxStart (&it_, nullptr );
31
- it_.node = nullptr ;
32
- }
33
-
34
- ~SeekIterator () {
35
- raxStop (&it_);
28
+ it_.rt = nullptr ;
36
29
}
37
30
38
- SeekIterator (SeekIterator&&) = delete ; // self-referential
39
- SeekIterator (const SeekIterator&) = delete ; // self-referential
40
-
41
31
SeekIterator (rax* tree, const char * op, std::string_view key) {
42
32
raxStart (&it_, tree);
43
- raxSeek (&it_, op, to_key_ptr (key), key.size ());
44
- operator ++();
33
+ if (raxSeek (&it_, op, to_key_ptr (key), key.size ())) { // Successfuly seeked
34
+ operator ++();
35
+ } else {
36
+ InvalidateIterator ();
37
+ }
45
38
}
46
39
47
40
explicit SeekIterator (rax* tree) : SeekIterator(tree, " ^" , std::string_view{nullptr , 0 }) {
48
41
}
49
42
43
+ /* Remove copy/move constructors to avoid double iterator invalidation */
44
+ SeekIterator (SeekIterator&&) = delete ;
45
+ SeekIterator (const SeekIterator&) = delete ;
46
+ SeekIterator& operator =(SeekIterator&&) = delete ;
47
+ SeekIterator& operator =(const SeekIterator&) = delete ;
48
+
49
+ ~SeekIterator () {
50
+ if (IsValid ()) {
51
+ InvalidateIterator ();
52
+ }
53
+ }
54
+
50
55
bool operator ==(const SeekIterator& rhs) const {
56
+ if (!IsValid () || !rhs.IsValid ())
57
+ return !IsValid () && !rhs.IsValid ();
51
58
return it_.node == rhs.it_ .node ;
52
59
}
53
60
@@ -56,31 +63,40 @@ template <typename V> struct RaxTreeMap {
56
63
}
57
64
58
65
SeekIterator& operator ++() {
59
- if (! raxNext (&it_)) {
60
- raxStop (&it_);
61
- it_. node = nullptr ;
66
+ int next_result = raxNext (&it_);
67
+ if (!next_result) { // OOM or we reached the end of the tree
68
+ InvalidateIterator () ;
62
69
}
63
70
return *this ;
64
71
}
65
72
73
+ /* After operator++() the first value (string_view) is invalid. So make sure your copied it to
74
+ * string */
66
75
std::pair<std::string_view, V&> operator *() const {
76
+ assert (IsValid () && it_.node && it_.node ->iskey && it_.data );
67
77
return {std::string_view{reinterpret_cast <const char *>(it_.key ), it_.key_len },
68
78
*reinterpret_cast <V*>(it_.data )};
69
79
}
70
80
81
+ bool IsValid () const {
82
+ return it_.rt ;
83
+ }
84
+
71
85
private:
86
+ void InvalidateIterator () {
87
+ raxStop (&it_);
88
+ it_.rt = nullptr ;
89
+ }
90
+
72
91
raxIterator it_;
73
92
};
74
93
75
94
// Result of find() call. Inherits from pair to mimic iterator interface, not incrementable.
76
95
struct FindIterator : public std ::optional<std::pair<std::string, V&>> {
77
96
bool operator ==(const SeekIterator& rhs) const {
78
- if (this ->has_value () != !bool (rhs.it_ .flags & RAX_ITER_EOF))
79
- return false ;
80
- if (!this ->has_value ())
81
- return true ;
82
- return (*this )->first ==
83
- std::string_view{reinterpret_cast <const char *>(rhs.it_ .key ), rhs.it_ .key_len };
97
+ if (!this ->has_value () || !rhs.IsValid ())
98
+ return !this ->has_value () && !rhs.IsValid ();
99
+ return (*this )->first == (*rhs).first ;
84
100
}
85
101
86
102
bool operator !=(const SeekIterator& rhs) const {
@@ -160,7 +176,7 @@ std::pair<typename RaxTreeMap<V>::FindIterator, bool> RaxTreeMap<V>::try_emplace
160
176
161
177
V* old = nullptr ;
162
178
raxInsert (tree_, to_key_ptr (key), key.size (), ptr, reinterpret_cast <void **>(&old));
163
- assert (old == nullptr );
179
+ assert (! old);
164
180
165
181
auto it = std::make_optional (std::pair<std::string, V&>(std::string (key), *ptr));
166
182
return std::make_pair (std::move (FindIterator{it}), true );
0 commit comments