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