IceShard 1
A personal game engine project, with development focused on 2D/2.5D games.
Loading...
Searching...
No Matches
queue.hxx
Go to the documentation of this file.
1
3
4#pragma once
10
11namespace ice
12{
13
20 template<typename Type, ice::ContainerLogic Logic = ice::Constant_DefaultContainerLogic<Type>>
21 struct Queue
24 {
25 static_assert(
27 "Collection element type is not allowed with 'Trivial' logic!"
28 );
29
30 using ValueType = Type;
31 using ConstContainerValueType = Type const;
32 using Iterator = Type*;
33 using ReverseIterator = std::reverse_iterator<Type*>;
34 using ConstIterator = Type const*;
35 using ConstReverseIterator = std::reverse_iterator<Type const*>;
38
43 Type* _data;
44
45 inline explicit Queue(ice::Allocator& alloc) noexcept;
46 inline Queue(Queue&& other) noexcept;
47 inline Queue(Queue const& other) noexcept
48 requires std::copy_constructible<Type>;
49 inline ~Queue() noexcept;
50
51 // API Requirements Of: Container
52 constexpr auto size() const noexcept -> ice::ncount { return { _count, sizeof(ValueType) }; }
53
54 // API Requirements Of: Resizable Container
55 constexpr auto capacity() const noexcept -> ice::ncount { return { _capacity, sizeof(ValueType) }; }
56 constexpr void set_capacity(ice::ncount new_capacity) noexcept;
57 constexpr void resize(ice::ncount new_size) noexcept;
58 constexpr void clear() noexcept;
59
60 // API Manipulation
61 template<typename ItemType = Type>
62 requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
63 constexpr void push_front(ItemType&& item) noexcept;
64
65 template<typename ItemType = Type>
66 requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
67 constexpr void push_back(ItemType&& item) noexcept;
68
69 // TODO: Think of changing it to iterable container?
70 template<ice::concepts::ContiguousContainer ContainerT>
71 requires (ice::concepts::CompatibleContainer<Type, ContainerT>)
72 constexpr void push_front(ContainerT const& other) noexcept;
73
74 // TODO: Think of changing it to iterable container?
75 template<ice::concepts::ContiguousContainer ContainerT>
76 requires (ice::concepts::CompatibleContainer<Type, ContainerT>)
77 constexpr void push_back(ContainerT const& other) noexcept;
78
79 constexpr void pop_front(ice::ncount count = 1_count) noexcept;
80 constexpr void pop_back(ice::ncount count = 1_count) noexcept;
81
82 // Explicit functionality
83 template<typename Self>
84 constexpr auto front(this Self&& self) noexcept -> ice::container::ValueRef<Self>;
85 template<typename Self>
86 constexpr auto back(this Self&& self) noexcept -> ice::container::ValueRef<Self>;
87
88 template<typename Self, typename Fn>
89 constexpr void for_each(this Self&& self, Fn&& fn) noexcept;
90 template<typename Self, typename Fn>
91 constexpr void for_each_reverse(this Self&& self, Fn&& fn) noexcept;
92
93 template<typename Self>
94 constexpr auto take_front(this Self&& self, ice::Span<Type> out_values) noexcept -> ice::ncount;
95
96 // API Requirements Of: Memory
97 constexpr auto memory_view(this Queue& self) noexcept -> ice::Memory;
98
99 // Operators and implicit conversions
100 inline auto operator=(Queue&& other) noexcept -> Queue&;
101 inline auto operator=(Queue const& other) noexcept -> Queue&
102 requires std::copy_constructible<Type>;
103
104 template<typename Self>
105 constexpr auto operator[](
106 this Self&& self, ice::nindex idx
107 ) noexcept -> ice::container::ValueRef<Self>;
108 };
109
110 namespace queue::detail
111 {
112
113 template<typename Type>
115 {
116 ice::u32 const raw_end_idx = queue._offset + destroy_count.u32();
117 ice::nindex const start_idx = queue._offset;
118 ice::nindex const end_idx = raw_end_idx % queue._capacity;
119
120 // We got a wrapped case
121 if (start_idx > end_idx)
122 {
123 ice::mem_destruct_n_at(queue._data + start_idx, queue._capacity - start_idx);
124 ice::mem_destruct_n_at(queue._data, end_idx);
125 }
126 else
127 {
128 ice::mem_destruct_n_at(queue._data + start_idx, destroy_count);
129 }
130 }
131
132 template<typename Type>
134 {
135 ice::u32 const raw_end_idx = queue._offset + queue._count;
136 ice::nindex const start_idx = (raw_end_idx - destroy_count.u32()) % queue._capacity;
137 ice::nindex const end_idx = raw_end_idx % queue._capacity;
138
139 // We got a wrapped case
140 if (start_idx > end_idx)
141 {
142 ice::mem_destruct_n_at(queue._data + start_idx, queue._capacity - start_idx);
143 ice::mem_destruct_n_at(queue._data, end_idx);
144 }
145 else
146 {
147 ice::mem_destruct_n_at(queue._data + start_idx, destroy_count);
148 }
149 }
150
151 template<typename Type>
153 {
154 ice::u32 const start_idx = queue._offset;
155 ice::u32 const head_count = queue._capacity - start_idx;
156 ice::usize const head_size = ice::size_of<Type> * head_count;
157
158 ice::mem_copy_construct_n_at(dest, queue._data + start_idx, head_count);
159 // Move destination pointer
160 dest.size.value = static_cast<ice::usize::base_type>((dest.size - head_size).value);
161 dest.location = ice::ptr_add(dest.location, ice::size_of<Type> * head_count);
162 ice::mem_copy_construct_n_at(dest, queue._data, queue._count - head_count);
163 }
164
165 template<typename Type>
167 {
168 ice::u32 const start_idx = queue._offset;
169 ice::u32 const head_count = queue._capacity - start_idx;
170 ice::usize const head_size = ice::size_of<Type> * head_count;
171
172 ice::mem_move_construct_n_at(dest, queue._data + start_idx, head_count);
173 // Move destination pointer
174 dest.size.value = static_cast<ice::usize::base_type>((dest.size - head_size).value);
175 dest.location = ice::ptr_add(dest.location, ice::size_of<Type> *head_count);
176 ice::mem_move_construct_n_at(dest, queue._data, queue._count - head_count);
177
178 // Destroy the items left in the old queue memory.
179 ice::mem_destruct_n_at(queue._data + start_idx, head_count);
180 ice::mem_destruct_n_at(queue._data, queue._count - head_count);
181 }
182
183 template<typename Type>
185 {
186 ice::usize const total_size = ice::size_of<Type> * queue._count;
187
188 ice::u32 const head_count = std::min(queue._offset + queue._count, queue._capacity) - queue._offset;
189 ice::u32 const tail_count = queue._count - head_count;
190
191 ice::usize const head_size = ice::size_of<Type> * head_count;
192 ice::usize const head_end_offset = ice::size_of<Type> * head_count;
193 ice::usize const tail_end_offset = ice::size_of<Type> * tail_count;
194
196 dest,
197 Data{
198 .location = queue._data + queue._offset,
199 .size = head_end_offset,
200 .alignment = ice::align_of<Type>
201 }
202 );
203 // Move destination pointer
204 dest.size.value = static_cast<ice::usize::base_type>((dest.size - head_size).value);
205 dest.location = ice::ptr_add(dest.location, head_size);
207 dest,
208 Data{
209 .location = queue._data,
210 .size = tail_end_offset,
211 .alignment = ice::align_of<Type>
212 }
213 );
214 }
215
216 } // namespace queue::detail
217
218 template<typename Type, ice::ContainerLogic Logic>
220 : _allocator{ &alloc }
221 , _capacity{ 0 }
222 , _count{ 0 }
223 , _offset{ 0 }
224 , _data{ nullptr }
225 {
226 }
227
228 template<typename Type, ice::ContainerLogic Logic>
229 inline Queue<Type, Logic>::Queue(Queue&& other) noexcept
230 : _allocator{ other._allocator }
231 , _capacity{ ice::exchange(other._capacity, 0) }
232 , _count{ ice::exchange(other._count, 0) }
233 , _offset{ ice::exchange(other._offset, 0) }
234 , _data{ ice::exchange(other._data, nullptr) }
235 {
236 }
237
238 template<typename Type, ice::ContainerLogic Logic>
239 inline Queue<Type, Logic>::Queue(Queue const& other) noexcept requires std::copy_constructible<Type>
240 : _allocator{ other._allocator }
241 , _capacity{ 0 }
242 , _count{ 0 }
243 , _offset{ 0 }
244 , _data{ nullptr }
245 {
246 if (other._count > 0)
247 {
248 this->set_capacity(other.size());
249
250 if constexpr (Logic == ContainerLogic::Complex)
251 {
253 }
254 else
255 {
257 }
258
259 _count = other._count;
260 }
261 }
262
263 template<typename Type, ice::ContainerLogic Logic>
265 {
266 if constexpr (Logic == ContainerLogic::Complex)
267 {
268 ice::u32 const last_raw_idx = _offset + _count;
269 if (last_raw_idx > _capacity)
270 {
271 ice::u32 const wrapped_count = last_raw_idx - _capacity;
272 // Destroyes elements at the end of the ring buffer [_offset, count_until_capacity)
273 ice::mem_destruct_n_at(_data + _offset, _count - wrapped_count);
274 // Destroys wrapped tail elements [0, tail_size)
275 ice::mem_destruct_n_at(_data, wrapped_count);
276 }
277 else
278 {
280 }
281 }
282
283 _allocator->deallocate(this->memory_view());
284 }
285
286 template<typename Type, ice::ContainerLogic Logic>
287 inline auto Queue<Type, Logic>::operator=(Queue&& other) noexcept -> Queue&
288 {
289 if (this != &other)
290 {
291 this->set_capacity(0_count);
292
293 _capacity = ice::exchange(other._capacity, 0);
294 _count = ice::exchange(other._count, 0);
295 _offset = ice::exchange(other._offset, 0);
296 _data = ice::exchange(other._data, nullptr);
297 }
298 return *this;
299 }
300
301 template<typename Type, ice::ContainerLogic Logic>
302 inline auto Queue<Type, Logic>::operator=(Queue const& other) noexcept -> Queue&
303 requires std::copy_constructible<Type>
304 {
305 if (this != &other)
306 {
307 this->clear();
308 this->reserve(other.size());
309
310 if (other._count > 0)
311 {
312 if constexpr (Logic == ContainerLogic::Complex)
313 {
315 }
316 else
317 {
319 }
320 }
321
322 _count = other._count;
323 }
324 return *this;
325 }
326
327 template<typename Type, ice::ContainerLogic Logic>
328 inline constexpr void ice::Queue<Type, Logic>::set_capacity(ice::ncount new_capacity) noexcept
329 {
330 if (new_capacity == _capacity)
331 {
332 return;
333 }
334
335 if (new_capacity < _count)
336 {
337 if constexpr (Logic == ContainerLogic::Complex)
338 {
339 ice::queue::detail::destroy_tail_items(*this, _count - new_capacity);
340 }
341
342 _count = new_capacity.u32();
343 }
344
345 Type* new_data = nullptr;
346 if (new_capacity > 0)
347 {
348 ice::AllocResult new_buffer = _allocator->allocate(ice::meminfo_of<Type> * new_capacity);
349 if (_count > 0)
350 {
351 if constexpr (Logic == ContainerLogic::Complex)
352 {
354 }
355 else
356 {
358 }
359 }
360 new_data = reinterpret_cast<Type*>(new_buffer.memory);
361 }
362
363 _allocator->deallocate(this->memory_view());
364 _data = new_data;
365 _capacity = new_capacity.u32();
366 _offset = 0;
367 }
368
369 template<typename Type, ice::ContainerLogic Logic>
370 inline constexpr void ice::Queue<Type, Logic>::resize(ice::ncount new_size) noexcept
371 {
372 if (_capacity < new_size)
373 {
374 set_capacity(new_size);
375 }
376
377 // Even for trivial logic we construct items so at least the default ctor is called.
378 if (new_size > _count)
379 {
380 ice::ncount const missing_items = new_size - _count;
381 ice::nindex const start_idx = (_offset + _count) % _capacity;
382
383 ice::nindex const end_idx = ice::min<ice::nindex>(start_idx + missing_items, _capacity);
384 ice::nindex const wrapped_end_idx = missing_items - (end_idx - start_idx);
385
386 // Construct until we hit end of the queue buffer
388 Memory{
389 .location = _data + start_idx,
390 .size = ice::size_of<Type> * (end_idx - start_idx),
391 .alignment = ice::align_of<Type>
392 },
393 (end_idx - start_idx)
394 );
395 // Construct the rest wrapped around the buffer
397 Memory{
398 .location = _data,
399 .size = ice::size_of<Type> * wrapped_end_idx,
400 .alignment = ice::align_of<Type>
401 },
402 wrapped_end_idx
403 );
404 }
405 else if constexpr (Logic == ContainerLogic::Complex)
406 {
408 }
409
410 _count = new_size.u32();
411 }
412
413 template<typename Type, ice::ContainerLogic Logic>
414 constexpr void ice::Queue<Type, Logic>::clear() noexcept
415 {
416 if constexpr (Logic == ContainerLogic::Complex)
417 {
419 }
420
421 _count = 0;
422 _offset = 0;
423 }
424
425 template<typename Type, ice::ContainerLogic Logic>
426 template<typename ItemType> requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
427 inline constexpr void ice::Queue<Type, Logic>::push_front(ItemType&& item) noexcept
428 {
429 if (_count == _capacity)
430 {
431 this->grow();
432 }
433
434 if (_offset == 0)
435 {
437 }
438
439 _offset -= 1;
440
441 if constexpr (Logic == ContainerLogic::Complex)
442 {
445 ice::forward<Type>(item)
446 );
447 }
448 else
449 {
450 _data[_offset] = Type{ item };
451 }
452
453 _count += 1;
454 }
455
456 template<typename Type, ice::ContainerLogic Logic>
457 template<typename ItemType> requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
458 inline constexpr void ice::Queue<Type, Logic>::push_back(ItemType&& item) noexcept
459 {
460 if (_count == _capacity)
461 {
462 this->grow();
463 }
464
465 ice::u32 const item_idx = (_offset + _count) % _capacity;
466 if constexpr (Logic == ContainerLogic::Complex)
467 {
469 ice::ptr_add(this->memory_view(), ice::size_of<Type> * item_idx),
470 ice::forward<Type>(item)
471 );
472 }
473 else
474 {
475 _data[item_idx] = Type{ item };
476 }
477
478 _count += 1;
479 }
480
481 template<typename Type, ice::ContainerLogic Logic>
483 {
484 if constexpr (Logic == ContainerLogic::Complex)
485 {
487 }
488
489 if (_count > count)
490 {
491 _count -= count.u32();
492 _offset = (_offset + count.u32()) % _capacity;
493 }
494 else
495 {
496 _count = 0;
497 _offset = 0;
498 }
499 }
500
501 template<typename Type, ice::ContainerLogic Logic>
503 {
504 if constexpr (Logic == ContainerLogic::Complex)
505 {
507 }
508
509 if (_count > count)
510 {
511 _count -= count.u32();
512 }
513 else
514 {
515 _count = 0;
516 _offset = 0;
517 }
518 }
519
520 template<typename Type, ice::ContainerLogic Logic>
521 template<ice::concepts::ContiguousContainer ContainerT>
523 inline constexpr void ice::Queue<Type, Logic>::push_back(ContainerT const& other) noexcept
524 {
525 ice::ncount const other_count = other.size();
526 ice::ncount const required_capacity = _count + other_count;
527 if (required_capacity > _capacity)
528 {
529 this->grow(required_capacity);
530 }
531
532 ice::nindex const start_idx = (_offset + _count) % _capacity;
533 ice::nindex const end_idx = ice::min<nindex>(_capacity, start_idx + other_count);
534
535 // The space can we use before wrapping around the buffer.
536 ice::ncount const head_space = end_idx - start_idx;
537 // The space after the wrapped buffer we still need to allocate. Can be 0.
538 ice::ncount const tail_space = other_count - head_space;
539
540 if constexpr (Logic == ContainerLogic::Complex)
541 {
543 Memory{
544 .location = _data + start_idx,
545 .size = ice::size_of<Type> * head_space,
546 .alignment = ice::align_of<Type>
547 },
548 other.data(),
549 head_space
550 );
552 Memory{
553 .location = _data,
554 .size = ice::size_of<Type> * tail_space,
555 .alignment = ice::align_of<Type>
556 },
557 other.data() + head_space,
558 tail_space
559 );
560 }
561 else
562 {
564 Memory{
565 .location = _data + start_idx,
566 .size = ice::size_of<Type> * head_space,
567 .alignment = ice::align_of<Type>
568 },
569 Data{
570 .location = other.data(),
571 .size = ice::size_of<Type> * head_space,
572 .alignment = ice::align_of<Type>
573 }
574 );
576 Memory{
577 .location = _data,
578 .size = ice::size_of<Type> * tail_space,
579 .alignment = ice::align_of<Type>
580 },
581 Data{
582 .location = other.data() + head_space,
583 .size = ice::size_of<Type> * tail_space,
584 .alignment = ice::align_of<Type>
585 }
586 );
587 }
588
589 _count += other.size().u32();
590 }
591
592 template<typename Type, ice::ContainerLogic Logic>
593 template<typename Self>
594 inline constexpr auto Queue<Type, Logic>::front(this Self&& self) noexcept -> ice::container::ValueRef<Self>
595 {
596 return self._data[self._offset];
597 }
598
599 template<typename Type, ice::ContainerLogic Logic>
600 template<typename Self>
601 inline constexpr auto Queue<Type, Logic>::back(this Self&& self) noexcept -> ice::container::ValueRef<Self>
602 {
603 return self._data[((self._offset + self._count) - 1) % self._capacity];
604 }
605
606 template<typename Type, ice::ContainerLogic Logic>
607 template<typename Self, typename Fn>
608 inline constexpr void ice::Queue<Type, Logic>::for_each(this Self&& self, Fn&& fn) noexcept
609 {
610 if (self._count == 0)
611 {
612 return;
613 }
614
615 ice::u32 const first_part = ice::min(self._offset + self._count, self._capacity);
616 ice::u32 const second_part = (self._offset + self._count) - first_part;
617
618 for (ice::u32 idx = self._offset; idx < first_part; ++idx)
619 {
620 ice::forward<Fn>(fn)(self._data[idx]);
621 }
622
623 for (ice::u32 idx = 0; idx < second_part; ++idx)
624 {
625 ice::forward<Fn>(fn)(self._data[idx]);
626 }
627 }
628
629 template<typename Type, ice::ContainerLogic Logic>
630 template<typename Self, typename Fn>
631 inline constexpr void ice::Queue<Type, Logic>::for_each_reverse(this Self&& self, Fn&& fn) noexcept
632 {
633 if (self._count == 0)
634 {
635 return;
636 }
637
638 ice::u32 const first_part = ice::min(self._offset + self._count, self._capacity);
639 ice::u32 const second_part = (self._offset + self._count) - first_part;
640
641 if (second_part > 0)
642 {
643 for (ice::u32 idx = second_part - 1; idx > 0; --idx)
644 {
645 ice::forward<Fn>(fn)(self._data[idx]);
646 }
647
648 ice::forward<Fn>(fn)(self._data[0]);
649 }
650
651 for (ice::u32 idx = first_part - 1; idx > self._offset; --idx)
652 {
653 ice::forward<Fn>(fn)(self._data[idx]);
654 }
655
656 ice::forward<Fn>(fn)(self._data[self._offset]);
657 }
658
659 template<typename Type, ice::ContainerLogic Logic>
660 template<typename Self>
662 this Self&& self,
663 ice::Span<Type> out_values
664 ) noexcept -> ice::ncount
665 {
666 ice::ncount const taken_items = ice::min(out_values.size(), self.size());
667
668 // (offset, end][0, remaining)
669 ice::ncount const first_part = ice::min<ice::ncount>(self._offset + taken_items, self._capacity);
670 ice::ncount const second_part = (self._offset + taken_items) - first_part;
671 ice::ncount const first_part_count = first_part - self._offset;
672
673 if constexpr (Logic == ContainerLogic::Complex)
674 {
675 ice::mem_move_n_to(out_values.begin(), self._data + self._offset, first_part_count);
676 ice::mem_move_n_to(out_values.begin() + first_part_count, self._data, second_part);
677 }
678 else
679 {
680 ice::memcpy(out_values.begin(), self._data + self._offset, ice::size_of<Type> * first_part_count);
681 ice::memcpy(out_values.begin() + first_part_count, self._data, ice::size_of<Type> * second_part);
682 }
683
684 self.pop_front(taken_items);
685 return taken_items;
686 }
687
688 template<typename Type, ice::ContainerLogic Logic>
689 inline constexpr auto Queue<Type, Logic>::memory_view(this Queue& self) noexcept -> ice::Memory
690 {
691 return ice::Memory{
692 .location = self._data,
693 .size = self.capacity(),
694 .alignment = ice::align_of<ValueType>
695 };
696 }
697
698 template<typename Type, ice::ContainerLogic Logic>
699 template<typename Self>
701 this Self&& self, ice::nindex idx
703 {
704 return self._data[(idx + self._offset) % self._capacity];
705 }
706
707
708} // namespace ice
A concept that ensures only types that can be trivially copyable can be 'forced' to use trifial Logic...
Definition container_logic.hxx:25
Definition container_concepts.hxx:175
Definition container_concepts.hxx:12
Definition associative_container.hxx:8
ValueType< ContainerT > & ValueRef
Definition container_concepts.hxx:149
constexpr auto min(arr_t< Size, T > left, arr_t< Size, U > right) noexcept -> arr_t< Size, T >
Definition array_operations.hxx:60
Definition queue.hxx:111
void copy_items_to_new_location(ice::Memory dest, ice::Queue< Type, ContainerLogic::Complex > const &queue) noexcept
Definition queue.hxx:152
void move_items_to_new_location(ice::Memory dest, ice::Queue< Type, ContainerLogic::Complex > &queue) noexcept
Definition queue.hxx:166
void destroy_tail_items(ice::Queue< Type, ContainerLogic::Complex > &queue, ice::ncount destroy_count) noexcept
Definition queue.hxx:133
void destroy_head_items(ice::Queue< Type, ContainerLogic::Complex > &queue, ice::ncount destroy_count) noexcept
Definition queue.hxx:114
void copy_memory_to_new_location(ice::Memory dest, ice::Queue< Type, ContainerLogic::Trivial > const &queue) noexcept
Definition queue.hxx:184
Definition queue.hxx:111
SPDX-License-Identifier: MIT.
Definition array.hxx:12
auto mem_move_n_to(T *target_objects, T *objects, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:70
constexpr ice::usize size_of
Definition mem_info.hxx:12
auto mem_move_construct_n_at(ice::Memory memory, T *objects, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:58
@ Complex
The collection handles complex data types and properly implements copy and move semantics.
Definition container_logic.hxx:19
void mem_destruct_n_at(T *location, ice::u64 count) noexcept
Definition mem_initializers.hxx:113
auto alloc(ice::usize size) noexcept -> ice::AllocResult
constexpr ice::ualign align_of
Definition mem_info.hxx:15
auto mem_default_construct_n_at(ice::Memory memory, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:46
auto ptr_add(void *pointer, ice::usize offset) noexcept -> void *
Definition mem_arithmetic.hxx:34
auto mem_copy_construct_n_at(ice::Memory memory, T const *objects, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:80
constexpr auto count(T const (&)[Size]) noexcept -> ice::u32
Definition base.hxx:43
std::uint32_t u32
Definition types.hxx:26
constexpr ice::meminfo meminfo_of
Definition mem_info.hxx:18
ice::AllocatorBase< ice::build::is_debug||ice::build::is_develop > Allocator
Definition mem_types.hxx:25
auto mem_construct_at(void *memory_ptr, Args &&... args) noexcept -> T *
Definition mem_initializers.hxx:12
auto memcpy(void *dest, void const *source, ice::usize size) noexcept -> void *
Definition mem.hxx:44
void * memory
Definition mem.hxx:45
Definition mem_data.hxx:17
Definition mem_memory.hxx:13
A double ended queue, build on a circular buffer.
Definition queue.hxx:24
ice::ncount SizeType
Definition queue.hxx:36
constexpr auto take_front(this Self &&self, ice::Span< Type > out_values) noexcept -> ice::ncount
Definition queue.hxx:661
constexpr void for_each_reverse(this Self &&self, Fn &&fn) noexcept
Definition queue.hxx:631
ice::u32 _count
Definition queue.hxx:41
std::reverse_iterator< Type const * > ConstReverseIterator
Definition queue.hxx:35
auto operator=(Queue &&other) noexcept -> Queue &
Definition queue.hxx:287
Type * Iterator
Definition queue.hxx:32
Type const * ConstIterator
Definition queue.hxx:34
ice::u32 _capacity
Definition queue.hxx:40
~Queue() noexcept
Definition queue.hxx:264
constexpr auto back(this Self &&self) noexcept -> ice::container::ValueRef< Self >
Definition queue.hxx:601
constexpr void for_each(this Self &&self, Fn &&fn) noexcept
Definition queue.hxx:608
constexpr void clear() noexcept
Definition queue.hxx:414
constexpr void set_capacity(ice::ncount new_capacity) noexcept
Definition queue.hxx:328
Queue(ice::Allocator &alloc) noexcept
Definition queue.hxx:219
constexpr auto capacity() const noexcept -> ice::ncount
Definition queue.hxx:55
ice::u32 _offset
Definition queue.hxx:42
constexpr void pop_front(ice::ncount count=1_count) noexcept
Definition queue.hxx:482
ice::concepts::ContiguousContainerTag ContainerTag
Definition queue.hxx:37
constexpr auto front(this Self &&self) noexcept -> ice::container::ValueRef< Self >
Definition queue.hxx:594
constexpr void pop_back(ice::ncount count=1_count) noexcept
Definition queue.hxx:502
std::reverse_iterator< Type * > ReverseIterator
Definition queue.hxx:33
constexpr void resize(ice::ncount new_size) noexcept
Definition queue.hxx:370
Type * _data
Definition queue.hxx:43
Type ValueType
Definition queue.hxx:30
constexpr auto memory_view(this Queue &self) noexcept -> ice::Memory
Definition queue.hxx:689
ice::Allocator * _allocator
Definition queue.hxx:39
constexpr auto size() const noexcept -> ice::ncount
Definition queue.hxx:52
constexpr auto operator[](this Self &&self, ice::nindex idx) noexcept -> ice::container::ValueRef< Self >
Definition queue.hxx:700
Type const ConstContainerValueType
Definition queue.hxx:31
constexpr void push_back(ItemType &&item) noexcept
Definition queue.hxx:458
constexpr void push_front(ItemType &&item) noexcept
Definition queue.hxx:427
A view into an array of objects laid out in contiguous memory.
Definition span.hxx:17
Definition container_concepts.hxx:56
Definition basic_container.hxx:11
Definition resizable_container.hxx:11
constexpr void reserve(this Self &self, ice::ncount min_capacity) noexcept
Definition resizable_container.hxx:25
constexpr void grow(this Self &self, ice::ncount min_capacity=ice::ncount_none) noexcept
Definition resizable_container.hxx:34
Definition ncount.hxx:14
Definition nindex.hxx:13
Represents a unsigned size value on the given platform.
Definition mem_size_types.hxx:26
std::size_t base_type
Definition mem_size_types.hxx:28