Skip to content

Commit 0e81a35

Browse files
committed
libutil: Make CanonPath a proper range
This was we can use std::ranges algorithms on it. Requires making the iterator a proper forward iterator type as well.
1 parent 94c3bb3 commit 0e81a35

File tree

1 file changed

+58
-8
lines changed

1 file changed

+58
-8
lines changed

src/libutil/include/nix/util/canon-path.hh

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <iostream>
99
#include <set>
1010
#include <vector>
11+
#include <ranges>
1112

1213
#include <boost/container_hash/hash.hpp>
1314

@@ -122,43 +123,90 @@ public:
122123
return &cs[1];
123124
}
124125

125-
struct Iterator
126+
class Iterator
126127
{
128+
/**
129+
* Helper class with overloaded operator-> for "drill-down" behavior.
130+
* This was a "temporary" string_view doesn't have to be stored anywhere.
131+
*/
132+
class PointerProxy
133+
{
134+
std::string_view segment;
135+
136+
public:
137+
PointerProxy(std::string_view segment_)
138+
: segment(segment_)
139+
{
140+
}
141+
142+
const std::string_view * operator->() const
143+
{
144+
return &segment;
145+
}
146+
};
147+
148+
public:
149+
using value_type = std::string_view;
150+
using reference_type = const std::string_view;
151+
using pointer_type = PointerProxy;
152+
using difference_type = std::ptrdiff_t;
153+
using iterator_category = std::forward_iterator_tag;
154+
127155
std::string_view remaining;
128156
size_t slash;
129157

158+
/**
159+
* Dummy default constructor required for forward iterators. Doesn't return
160+
* a usable iterator.
161+
*/
162+
Iterator()
163+
: remaining()
164+
, slash(0)
165+
{
166+
}
167+
130168
Iterator(std::string_view remaining)
131169
: remaining(remaining)
132170
, slash(remaining.find('/'))
133171
{
134172
}
135173

136-
bool operator!=(const Iterator & x) const
174+
bool operator==(const Iterator & x) const
137175
{
138-
return remaining.data() != x.remaining.data();
176+
return remaining.data() == x.remaining.data();
139177
}
140178

141-
bool operator==(const Iterator & x) const
179+
reference_type operator*() const
142180
{
143-
return !(*this != x);
181+
return remaining.substr(0, slash);
144182
}
145183

146-
const std::string_view operator*() const
184+
pointer_type operator->() const
147185
{
148-
return remaining.substr(0, slash);
186+
return PointerProxy(**this);
149187
}
150188

151-
void operator++()
189+
Iterator & operator++()
152190
{
153191
if (slash == remaining.npos)
154192
remaining = remaining.substr(remaining.size());
155193
else {
156194
remaining = remaining.substr(slash + 1);
157195
slash = remaining.find('/');
158196
}
197+
return *this;
198+
}
199+
200+
Iterator operator++(int)
201+
{
202+
auto tmp = *this;
203+
++*this;
204+
return tmp;
159205
}
160206
};
161207

208+
static_assert(std::forward_iterator<Iterator>);
209+
162210
Iterator begin() const
163211
{
164212
return Iterator(rel());
@@ -265,6 +313,8 @@ public:
265313
friend std::size_t hash_value(const CanonPath &);
266314
};
267315

316+
static_assert(std::ranges::forward_range<CanonPath>);
317+
268318
std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
269319

270320
inline std::size_t hash_value(const CanonPath & path)

0 commit comments

Comments
 (0)