Iros
 
Loading...
Searching...
No Matches
ring_operations.h
Go to the documentation of this file.
1#pragma once
2
11#include "di/util/create.h"
13
16 return ring.span().size();
17}
18
20 return ring.span().size_bytes();
21}
22
23constexpr auto empty(concepts::detail::ConstantRing auto& ring) -> bool {
24 return ring::size(ring) == 0;
25}
26
27constexpr auto begin_pointer(concepts::detail::ConstantRing auto& ring) -> auto* {
28 return ring.span().data();
29}
30
31constexpr auto end_pointer(concepts::detail::ConstantRing auto& ring) -> auto* {
32 return ring::begin_pointer(ring) + ring.capacity();
33}
34
35constexpr auto head_pointer(concepts::detail::ConstantRing auto& ring) -> auto* {
36 return ring::begin_pointer(ring) + ring.head();
37}
38
39constexpr auto tail_pointer(concepts::detail::ConstantRing auto& ring) -> auto* {
40 return ring::begin_pointer(ring) + ring.tail();
41}
42
43template<concepts::detail::ConstantRing Ring, typename Value = meta::detail::RingValue<Ring>>
48
49template<concepts::detail::ConstantRing Ring, typename Value = meta::detail::RingValue<Ring>>
54
55constexpr auto lookup(concepts::detail::ConstantRing auto& ring, usize index) -> decltype(auto) {
56 return ring::begin(ring)[index];
57}
58
59constexpr auto at(concepts::detail::ConstantRing auto& ring, usize index) {
60 return lift_bool(index < ring::size(ring)) % [&] {
61 return util::ref(ring::lookup(ring, index));
62 };
63}
64
66 return ring::at(ring, 0);
67}
68
70 // NOTE: This is safe because unsigned underflow is defined behavior. If the ring is empty, then at() will return
71 // nullopt.
72 return ring::at(ring, ring::size(ring) - 1U);
73}
74
75template<concepts::detail::MutableRing Ring, typename Value = meta::detail::RingValue<Ring>>
76requires(!concepts::Const<Ring>)
78 // SAFETY: this is safe because we are provided a mutable reference to the ring.
79 return iterator.unconst_unsafe();
80}
81
82template<concepts::detail::ConstantRing Ring>
83requires(!concepts::Const<Ring>)
84constexpr auto iterator(Ring& ring, usize index) {
85 DI_ASSERT(index <= ring::size(ring));
86 return ring::begin(ring) + index;
87}
88
89template<concepts::detail::ConstantRing Ring>
90constexpr auto iterator(Ring const& ring, usize index) {
91 DI_ASSERT(index <= ring::size(ring));
92 return ring::begin(ring) + index;
93}
94
97 ring.assume_size(0);
98 ring.assume_head(0);
99 ring.assume_tail(0);
100}
101
102template<concepts::detail::MutableRing Ring, typename R = meta::detail::RingAllocResult<Ring>>
103constexpr auto reserve(Ring& ring, usize capacity) -> R {
104 if (capacity <= ring.capacity()) {
105 return util::create<R>();
106 }
107
108 auto size = ring::size(ring);
109 auto temp = Ring();
110 return invoke_as_fallible([&] {
111 return temp.reserve_from_nothing(capacity);
112 }) % [&] {
113 auto new_buffer = ring::begin_pointer(temp);
114 // FIXME: Use an optimized algorithm which breaks the ring buffer into 2 contigous parts.
115 container::uninitialized_relocate(ring::begin(ring), ring::end(ring), new_buffer, new_buffer + capacity);
116 temp.assume_size(size);
117 temp.assume_head(0);
118 temp.assume_tail(size);
119 ring.assume_size(0);
120 ring.assume_head(0);
121 ring.assume_tail(0);
122 util::swap(ring, temp);
123 } | try_infallible;
124}
125
126template<concepts::detail::MutableRing Ring, typename... Args>
128constexpr auto emplace_back(Ring& ring, Args&&... args) -> decltype(auto) {
129 auto size = ring::size(ring);
130 return invoke_as_fallible([&] {
131 return ring::reserve(ring, ring.grow_capacity(size + 1));
132 }) % [&] {
134 auto result = util::construct_at(end, util::forward<Args>(args)...);
135 ring.assume_size(size + 1);
136 ring.assume_tail((ring.tail() + 1) % ring.capacity());
137 return util::ref(*result);
138 } | try_infallible;
139}
140
141template<concepts::detail::MutableRing Ring, concepts::InputContainer Con, typename T = meta::detail::RingValue<Ring>,
142 typename R = meta::detail::RingAllocResult<Ring>>
144constexpr auto append_container(Ring& ring, Con&& container) -> R {
145 return container::sequence(util::forward<Con>(container), [&]<typename X>(X&& value) {
146 return as_fallible(ring::emplace_back(ring, util::forward<X>(value)));
147 });
148}
149
151 auto size = ring::size(ring);
152 return lift_bool(size > 0) % [&] {
153 auto new_size = size - 1;
154 auto result = util::relocate(ring::lookup(ring, new_size));
155 ring.assume_size(new_size);
156 ring.assume_tail((ring.tail() + ring.capacity() - 1) % ring.capacity());
157 return result;
158 };
159}
160
161template<concepts::detail::MutableRing Ring, typename... Args>
163constexpr auto emplace_front(Ring& ring, Args&&... args) -> decltype(auto) {
164 auto size = ring::size(ring);
165 return invoke_as_fallible([&] {
166 return ring::reserve(ring, ring.grow_capacity(size + 1));
167 }) % [&] {
168 auto new_head = (ring.head() + ring.capacity() - 1) % ring.capacity();
169 ring.assume_head(new_head);
170
171 auto head = ring::head_pointer(ring);
172 auto result = util::construct_at(head, util::forward<Args>(args)...);
173
174 ring.assume_size(size + 1);
175 return util::ref(*result);
176 } | try_infallible;
177}
178
179template<concepts::detail::MutableRing Ring, concepts::InputContainer Con, typename T = meta::detail::RingValue<Ring>,
180 typename R = meta::detail::RingAllocResult<Ring>>
182constexpr auto prepend_container(Ring& ring, Con&& container) -> R {
183 return container::sequence(util::forward<Con>(container), [&]<typename X>(X&& value) {
184 return as_fallible(ring::emplace_front(ring, util::forward<X>(value)));
185 });
186}
187
189 auto size = ring::size(ring);
190 return lift_bool(size > 0) % [&] {
191 auto new_size = size - 1;
192 auto result = util::relocate(ring::lookup(ring, 0));
193 ring.assume_size(new_size);
194 ring.assume_head((ring.head() + 1) % ring.capacity());
195 return result;
196 };
197}
198
199template<concepts::detail::MutableRing Ring, typename T = meta::detail::RingValue<Ring>, typename... Args>
201constexpr auto emplace(Ring& ring, RingIterator<T const> it, Args&&... args) {
202 auto position = it - ring::begin(ring);
203 return as_fallible(ring::emplace_back(ring, util::forward<Args>(args)...)) % [&](auto&) {
204 auto new_it = ring::begin(ring) + position;
205 auto last = ring::end(ring);
206 container::rotate(new_it, last - 1, last);
207 return new_it;
208 } | try_infallible;
209}
210
211template<concepts::detail::MutableRing Ring, typename Value = meta::detail::RingValue<Ring>>
213 if (first == last) {
214 return ring::iterator(ring, first);
215 }
216
217 // Rotate the range [first, last) to the end of the buffer.
218 auto const first_position = first - ring::begin(ring);
219 auto const to_remove = last - first;
220 auto [new_tail, end] = container::rotate(ring::iterator(ring, first), ring::iterator(ring, last), ring::end(ring));
221
222 // Destroy the trailing elements.
223 container::destroy(new_tail, end);
224
225 ring.assume_size(ring::size(ring) - to_remove);
226 ring.assume_tail((ring.tail() + ring.capacity() - to_remove) % ring.capacity());
227 return ring::iterator(ring, first_position);
228}
229
230template<concepts::detail::MutableRing Ring, typename Value = meta::detail::RingValue<Ring>>
231constexpr auto erase(Ring& ring, RingIterator<Value const> citerator) {
232 return ring::erase(ring, citerator, citerator + 1);
233}
234
236 auto head = ring.head();
237 auto tail = ring.tail();
238 auto size = ring::size(ring);
239 if (head < tail) {
240 // Move the range [head, tail) to the beginning of the buffer.
243 ring.assume_head(0);
244 ring.assume_tail(size);
245 return ring.span();
246 }
247
248 // Move the range [head, capacity) to directly after tail.
251 // Rotate the range [0, tail) into place.
253 ring.assume_head(0);
254 ring.assume_tail(size);
255 return ring.span();
256}
257
258template<concepts::detail::MutableRing Ring, typename T = meta::detail::RingValue<Ring>>
260constexpr auto resize(Ring& ring, usize count) {
262 return invoke_as_fallible([&] {
263 return vector::resize(ring, count);
264 }) % [&] {
265 ring.assume_tail(ring::size(ring));
266 } | try_infallible;
267}
268
269template<concepts::detail::MutableRing Ring, typename T = meta::detail::RingValue<Ring>>
271constexpr auto resize(Ring& ring, usize count, T const& value) {
273 return invoke_as_fallible([&] {
274 return vector::resize(ring, count, value);
275 }) % [&] {
276 ring.assume_tail(ring::size(ring));
277 } | try_infallible;
278}
279}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition ring_iterator.h:8
Definition ring.h:22
Definition language.h:18
Definition operations.h:11
Definition container_compatible.h:9
Definition operations.h:34
Definition operations.h:24
Definition constant_ring.h:10
Definition mutable_ring.h:8
Definition ring_operations.h:14
constexpr auto pop_front(concepts::detail::MutableRing auto &ring)
Definition ring_operations.h:188
constexpr auto prepend_container(Ring &ring, Con &&container) -> R
Definition ring_operations.h:182
constexpr auto end(Ring &ring)
Definition ring_operations.h:50
constexpr auto emplace_back(Ring &ring, Args &&... args) -> decltype(auto)
Definition ring_operations.h:128
constexpr auto append_container(Ring &ring, Con &&container) -> R
Definition ring_operations.h:144
constexpr auto lookup(concepts::detail::ConstantRing auto &ring, usize index) -> decltype(auto)
Definition ring_operations.h:55
constexpr auto iterator(Ring &, RingIterator< Value const > iterator)
Definition ring_operations.h:77
constexpr auto end_pointer(concepts::detail::ConstantRing auto &ring) -> auto *
Definition ring_operations.h:31
constexpr auto empty(concepts::detail::ConstantRing auto &ring) -> bool
Definition ring_operations.h:23
constexpr auto resize(Ring &ring, usize count)
Definition ring_operations.h:260
constexpr auto make_contigous(concepts::detail::MutableRing auto &ring)
Definition ring_operations.h:235
constexpr auto begin_pointer(concepts::detail::ConstantRing auto &ring) -> auto *
Definition ring_operations.h:27
constexpr auto at(concepts::detail::ConstantRing auto &ring, usize index)
Definition ring_operations.h:59
constexpr auto size_bytes(concepts::detail::ConstantRing auto &ring)
Definition ring_operations.h:19
constexpr auto begin(Ring &ring)
Definition ring_operations.h:44
constexpr void clear(concepts::detail::MutableRing auto &ring)
Definition ring_operations.h:95
constexpr auto erase(Ring &ring, RingIterator< Value const > first, RingIterator< Value const > last)
Definition ring_operations.h:212
constexpr auto reserve(Ring &ring, usize capacity) -> R
Definition ring_operations.h:103
constexpr auto emplace_front(Ring &ring, Args &&... args) -> decltype(auto)
Definition ring_operations.h:163
constexpr auto tail_pointer(concepts::detail::ConstantRing auto &ring) -> auto *
Definition ring_operations.h:39
constexpr auto pop_back(concepts::detail::MutableRing auto &ring)
Definition ring_operations.h:150
constexpr auto emplace(Ring &ring, RingIterator< T const > it, Args &&... args)
Definition ring_operations.h:201
constexpr auto head_pointer(concepts::detail::ConstantRing auto &ring) -> auto *
Definition ring_operations.h:35
constexpr auto size(concepts::detail::ConstantRing auto &ring)
Definition ring_operations.h:15
constexpr auto resize(Vec &vector, size_t count) -> R
Definition vector_resize.h:19
Definition sequence.h:12
constexpr auto front
Definition access.h:58
constexpr auto empty
Definition empty.h:45
constexpr auto uninitialized_relocate
Definition uninitialized_relocate.h:41
constexpr auto uninitialized_relocate_backwards
Definition uninitialized_relocate_backwards.h:45
constexpr auto at
Definition access.h:147
constexpr auto sequence
Definition sequence.h:34
constexpr auto destroy
Definition destroy.h:35
constexpr auto size
Definition size.h:54
constexpr auto erase
Definition erase.h:76
constexpr auto count
Definition count.h:37
constexpr auto end
Definition end.h:47
constexpr auto back
Definition access.h:94
constexpr auto rotate
Definition rotate.h:94
constexpr auto begin
Definition begin.h:44
size_t usize
Definition integers.h:33
constexpr auto ref
Definition reference_wrapper.h:98
constexpr auto relocate
Definition relocate.h:21
constexpr struct di::util::SwapFunction swap
constexpr auto create(Args &&... args)
Definition create.h:21
constexpr auto construct_at
Definition construct_at.h:27
constexpr auto invoke_as_fallible
Definition invoke_as_fallible.h:37
constexpr auto as_fallible
Definition as_fallible.h:26
constexpr auto try_infallible
Definition try_infallible.h:31
constexpr auto lift_bool
Definition lift_bool.h:13