Iros
 
Loading...
Searching...
No Matches
path_iterator.h
Go to the documentation of this file.
1#pragma once
2
13
14namespace di::container {
15template<concepts::Encoding Enc>
16class PathIterator
17 : public IteratorBase<PathIterator<Enc>, BidirectionalIteratorTag, string::StringViewImpl<Enc>, ssize_t> {
18private:
19 using View = string::StringViewImpl<Enc>;
20 using CodePoint = meta::EncodingCodePoint<Enc>;
21
22 constexpr explicit PathIterator(View bounds, View current) : m_bounds(bounds), m_current(current) {}
23
24public:
25 PathIterator() = default;
26
27 constexpr auto operator*() const { return m_current; }
28
29 constexpr auto current_data() { return m_current.data(); }
30
31 constexpr void advance_one() {
32 do {
33 DI_ASSERT(m_current.begin() != m_bounds.end());
34 auto new_start = find_if_not(m_current.end(), m_bounds.end(), function::equal(CodePoint('/')));
35
36 // No more components, now produce end iterator.
37 if (new_start == m_bounds.end()) {
38 m_current = { m_bounds.end(), m_bounds.end() };
39 return;
40 }
41
42 // The new end will be the next '/' after the new start.
43 auto new_end = find(new_start, m_bounds.end(), CodePoint('/'));
44 m_current = { new_start, new_end };
45
46 // Skip over '.' components.
47 } while (container::equal(m_current, view::single(CodePoint('.'))));
48 }
49
50 constexpr void back_one() {
51 do {
52 DI_ASSERT(m_current.begin() != m_bounds.begin());
53 auto new_end = container::prev(m_current.begin());
54 while (new_end != m_bounds.begin() && *new_end == CodePoint('/')) {
55 --new_end;
56 }
57
58 // No more components, the iterator should not produce a single '/'.
59 if (new_end == m_bounds.begin()) {
60 m_current = { m_bounds.begin(), container::next(new_end) };
61 return;
62 }
63
64 // The new start will be the last non-slash character before the new end.
65 auto new_start = new_end;
66 while (new_start != m_bounds.begin() && *new_start != CodePoint('/')) {
67 --new_start;
68 }
69
70 // If the new_start points to a '/', advance it. Otherwise, this is a relative path.
71 if (*new_start == CodePoint('/')) {
72 m_current = { container::next(new_start), container::next(new_end) };
73 } else {
74 m_current = { new_start, container::next(new_end) };
75 }
76
77 // Skip over '.' components.
78 } while (m_current.begin() != m_bounds.begin() && container::equal(m_current, view::single(CodePoint('.'))));
79 }
80
81private:
82 template<typename, concepts::Encoding>
84
85 constexpr friend auto operator==(PathIterator const& a, PathIterator const& b) -> bool {
86 return a.m_current == b.m_current;
87 }
88 constexpr friend auto operator<=>(PathIterator const& a, PathIterator const& b) {
89 return a.m_current.data() <=> b.m_current.data();
90 }
91
92 View m_bounds;
93 View m_current;
94};
95}
#define DI_ASSERT(...)
Definition assert_bool.h:7
constexpr auto current_data()
Definition path_iterator.h:29
friend class ConstantPathInterface
Definition path_iterator.h:83
constexpr friend auto operator<=>(PathIterator const &a, PathIterator const &b)
Definition path_iterator.h:88
constexpr friend auto operator==(PathIterator const &a, PathIterator const &b) -> bool
Definition path_iterator.h:85
constexpr auto operator*() const
Definition path_iterator.h:27
constexpr void back_one()
Definition path_iterator.h:50
constexpr void advance_one()
Definition path_iterator.h:31
Definition view.h:35
constexpr auto data() const
Definition constant_string_interface.h:67
Definition string_view_impl_forward_declaration.h:7
constexpr auto single
Definition single.h:23
Definition sequence.h:12
constexpr auto prev
Definition prev.h:28
constexpr auto next
Definition next.h:35
constexpr auto find
Definition find.h:35
constexpr auto equal
Definition equal.h:46
constexpr auto find_if_not
Definition find_if_not.h:31
constexpr auto equal
Definition equal.h:23
RemoveCVRef< T >::CodePoint EncodingCodePoint
Definition encoding.h:19