Iros
 
Loading...
Searching...
No Matches
ring_iterator.h
Go to the documentation of this file.
1#pragma once
2
5
6namespace di::container {
7template<typename T>
8class RingIterator : public IteratorBase<RingIterator<T>, RandomAccessIteratorTag, T, isize> {
9private:
10 constexpr static bool is_const = concepts::Const<T>;
11
12 template<typename>
13 friend class RingIterator;
14
15public:
16 RingIterator() = default;
17
18 constexpr explicit RingIterator(T* current, T* head, T* tail, T* begin, T* end, bool at_end)
19 : m_current(current), m_head(head), m_tail(tail), m_begin(begin), m_end(end), m_at_end(at_end) {}
20
21 RingIterator(RingIterator const&) = default;
23
25 requires(is_const)
26 : m_current(other.m_current)
27 , m_head(other.m_head)
28 , m_tail(other.m_tail)
29 , m_begin(other.m_begin)
30 , m_end(other.m_end)
31 , m_at_end(other.m_at_end) {}
32
33 auto operator=(RingIterator const&) -> RingIterator& = default;
34 auto operator=(RingIterator&&) -> RingIterator& = default;
35
36 constexpr auto unconst_unsafe() const
37 requires(is_const)
38 {
40 const_cast<meta::RemoveConst<T>*>(m_current), const_cast<meta::RemoveConst<T>*>(m_head),
41 const_cast<meta::RemoveConst<T>*>(m_tail), const_cast<meta::RemoveConst<T>*>(m_begin),
42 const_cast<meta::RemoveConst<T>*>(m_end), m_at_end);
43 }
44
45 constexpr auto operator*() const -> T& {
46 DI_ASSERT(!m_at_end);
47 return *m_current;
48 }
49 constexpr auto operator->() const -> T* {
50 DI_ASSERT(!m_at_end);
51 return m_current;
52 }
53
54 constexpr void advance_one() {
55 DI_ASSERT(!m_at_end);
56 if (m_current == m_end - 1) {
57 m_current = m_begin;
58 } else {
59 ++m_current;
60 }
61 if (m_current == m_tail) {
62 m_at_end = true;
63 }
64 }
65
66 constexpr void back_one() {
67 DI_ASSERT(m_current != m_head || m_at_end);
68 if (m_current == m_begin) {
69 m_current = m_end - 1;
70 } else {
71 --m_current;
72 }
73 m_at_end = false;
74 }
75
76 constexpr void advance_n(isize n) {
77 if (n == 0) {
78 return;
79 }
80 if (n > 0) {
81 auto max_distance = distance_to_tail();
82 DI_ASSERT(n <= max_distance);
83
84 if (n == max_distance) {
85 m_current = m_tail;
86 m_at_end = true;
87 return;
88 }
89
90 auto distance_to_end = m_end - m_current;
91 if (n < distance_to_end) {
92 m_current += n;
93 } else {
94 m_current = m_begin + (n - distance_to_end);
95 }
96 return;
97 }
98
99 DI_ASSERT(-n <= m_end - m_begin);
100 m_at_end = false;
101 auto distance_to_begin = m_current - m_begin;
102 if (-n <= distance_to_begin) {
103 m_current += n;
104 } else {
105 m_current = m_end + n + distance_to_begin;
106 }
107 }
108
109private:
110 constexpr friend auto operator==(RingIterator const& a, RingIterator const& b) -> bool {
111 DI_ASSERT(a.m_head == b.m_head);
112 DI_ASSERT(a.m_tail == b.m_tail);
113 DI_ASSERT(a.m_begin == b.m_begin);
114 DI_ASSERT(a.m_end == b.m_end);
115 return a.m_at_end == b.m_at_end && a.m_current == b.m_current;
116 }
117
118 constexpr friend auto operator<=>(RingIterator const& a, RingIterator const& b) {
119 DI_ASSERT(a.m_head == b.m_head);
120 DI_ASSERT(a.m_tail == b.m_tail);
121 DI_ASSERT(a.m_begin == b.m_begin);
122 DI_ASSERT(a.m_end == b.m_end);
123
124 // First compare the end state.
125 if (a.m_at_end || b.m_at_end) {
126 return a.m_at_end <=> b.m_at_end;
127 }
128
129 // If a and b are not on the same "side" of the ring, then early return.
130 if (auto result = (a.m_current < a.m_head) <=> (b.m_current < b.m_head); result != 0) {
131 return result;
132 }
133
134 // Since a and b are on the same "side" of the ring, just compare pointers.
135 return a.m_current <=> b.m_current;
136 }
137
138 constexpr auto distance_to_tail() const -> isize {
139 if (m_at_end) {
140 return 0;
141 }
142 if (m_current < m_tail) {
143 return m_tail - m_current;
144 }
145 return m_end - m_current + (m_tail - m_begin);
146 }
147
148 constexpr friend auto operator-(RingIterator const& a, RingIterator const& b) -> isize {
149 DI_ASSERT(a.m_head == b.m_head);
150 DI_ASSERT(a.m_tail == b.m_tail);
151 DI_ASSERT(a.m_begin == b.m_begin);
152 DI_ASSERT(a.m_end == b.m_end);
153
154 return b.distance_to_tail() - a.distance_to_tail();
155 }
156
157 T* m_current { nullptr };
158 T* m_head { nullptr };
159 T* m_tail { nullptr };
160 T* m_begin { nullptr };
161 T* m_end { nullptr };
162 bool m_at_end { true };
163};
164}
#define DI_ASSERT(...)
Definition assert_bool.h:7
constexpr void back_one()
Definition ring_iterator.h:66
constexpr auto operator*() const -> T &
Definition ring_iterator.h:45
constexpr friend auto operator-(RingIterator const &a, RingIterator const &b) -> isize
Definition ring_iterator.h:148
auto operator=(RingIterator const &) -> RingIterator &=default
constexpr RingIterator(RingIterator< meta::RemoveConst< T > > const &other)
Definition ring_iterator.h:24
friend class RingIterator
Definition ring_iterator.h:13
constexpr friend auto operator<=>(RingIterator const &a, RingIterator const &b)
Definition ring_iterator.h:118
constexpr void advance_n(isize n)
Definition ring_iterator.h:76
RingIterator(RingIterator const &)=default
auto operator=(RingIterator &&) -> RingIterator &=default
constexpr auto operator->() const -> T *
Definition ring_iterator.h:49
constexpr RingIterator(T *current, T *head, T *tail, T *begin, T *end, bool at_end)
Definition ring_iterator.h:18
RingIterator(RingIterator &&)=default
constexpr void advance_one()
Definition ring_iterator.h:54
constexpr friend auto operator==(RingIterator const &a, RingIterator const &b) -> bool
Definition ring_iterator.h:110
constexpr auto unconst_unsafe() const
Definition ring_iterator.h:36
Definition language.h:18
Definition sequence.h:12
constexpr auto end
Definition end.h:47
constexpr auto begin
Definition begin.h:44
Type< detail::RemoveConstHelper< T > > RemoveConst
Definition core.h:43
ssize_t isize
Definition integers.h:34
@ T
Definition key.h:29