18#include <initializer_list>
27#include "pw_assert/assert.h"
28#include "pw_containers/internal/deque_iterator.h"
29#include "pw_containers/internal/traits.h"
30#include "pw_numeric/checked_arithmetic.h"
31#include "pw_span/span.h"
33namespace pw::containers::internal {
36using EnableIfIterable =
37 std::enable_if_t<
true,
decltype(T().begin(), T().end())>;
48template <
typename CountAndCapacityType>
51 using size_type =
typename CountAndCapacityType::size_type;
55 [[nodiscard]]
constexpr bool empty()
const noexcept {
return size() == 0; }
58 constexpr size_type
size() const noexcept {
59 return count_and_capacity_.count();
63 constexpr size_type
capacity() const noexcept {
64 return count_and_capacity_.capacity();
70 CountAndCapacityType& count_and_capacity() noexcept {
71 return count_and_capacity_;
74 constexpr void MoveAssignIndices(GenericDequeBase& other)
noexcept {
75 count_and_capacity_ = std::move(other.count_and_capacity_);
76 head_ = std::exchange(other.head_, 0);
77 tail_ = std::exchange(other.tail_, 0);
80 void SwapIndices(GenericDequeBase& other)
noexcept {
81 std::swap(count_and_capacity_, other.count_and_capacity_);
82 std::swap(head_, other.head_);
83 std::swap(tail_, other.tail_);
88 bool CanExtendBuffer()
const {
return tail_ > head_ || tail_ == 0; }
91 bool CanShrinkBuffer()
const {
return head_ == 0; }
93 void HandleNewBuffer(size_type new_capacity) {
94 count_and_capacity_.SetCapacity(new_capacity);
96 tail_ =
size() == new_capacity
98 : count_and_capacity_.count();
101 void HandleExtendedBuffer(size_type new_capacity) {
102 count_and_capacity_.SetCapacity(new_capacity);
104 tail_ = head_ + count_and_capacity_.count();
108 void HandleShrunkBuffer(size_type new_capacity) {
109 count_and_capacity_.SetCapacity(new_capacity);
110 if (tail_ == new_capacity) {
117 template <
typename Derived,
typename ValueType,
typename S>
118 friend class GenericDeque;
120 explicit constexpr GenericDequeBase(size_type initial_capacity) noexcept
121 : count_and_capacity_(initial_capacity), head_(0), tail_(0) {}
123 constexpr void ClearIndices() {
124 count_and_capacity_.SetCount(0);
132 constexpr size_type AbsoluteIndex(
const size_type relative_index)
const {
133 const size_type absolute_index = head_ + relative_index;
135 return absolute_index;
141 constexpr size_type AbsoluteIndexChecked(
142 const size_type relative_index)
const {
143 PW_ASSERT(relative_index <
size());
144 return AbsoluteIndex(relative_index);
147 constexpr void PushBack(size_type count = 1) {
148 IncrementWithWrap(tail_, count);
149 count_and_capacity_.IncrementCount(count);
151 constexpr void PushFront(size_type count = 1) {
152 DecrementWithWrap(head_, count);
153 count_and_capacity_.IncrementCount(count);
155 constexpr void PopFront() {
156 IncrementWithWrap(head_, 1);
157 count_and_capacity_.DecrementCount();
159 constexpr void PopBack() {
160 DecrementWithWrap(tail_, 1);
161 count_and_capacity_.DecrementCount();
164 constexpr void IncrementWithWrap(size_type& index, size_type count)
const {
172 constexpr void DecrementWithWrap(size_type& index, size_type count)
const {
179 CountAndCapacityType count_and_capacity_;
188template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
194 using value_type = ValueType;
195 using size_type =
typename CountAndCapacityType::size_type;
196 using difference_type = ptrdiff_t;
197 using reference = value_type&;
198 using const_reference =
const value_type&;
199 using pointer = value_type*;
200 using const_pointer =
const value_type*;
201 using iterator = containers::internal::DequeIterator<Derived>;
202 using const_iterator = containers::internal::DequeIterator<const Derived>;
220 void assign(size_type count,
const value_type& value) {
226 template <
typename It,
228 typename = containers::internal::EnableIfInputIterator<It>>
232 void assign(
const std::initializer_list<value_type>& list) {
233 assign(list.begin(), list.end());
238 constexpr reference at(size_type index) {
239 return data()[Base::AbsoluteIndexChecked(index)];
241 constexpr const_reference at(size_type index)
const {
242 return data()[Base::AbsoluteIndexChecked(index)];
245 constexpr reference operator[](size_type index) {
246 PW_DASSERT(index <
size());
247 return data()[Base::AbsoluteIndex(index)];
249 constexpr const_reference operator[](size_type index)
const {
250 PW_DASSERT(index <
size());
251 return data()[Base::AbsoluteIndex(index)];
254 constexpr reference front() {
255 PW_DASSERT(!empty());
256 return data()[head()];
258 constexpr const_reference front()
const {
259 PW_DASSERT(!empty());
260 return data()[head()];
263 constexpr reference back() {
264 PW_DASSERT(!empty());
265 return data()[Base::AbsoluteIndex(
size() - 1)];
267 constexpr const_reference back()
const {
268 PW_DASSERT(!empty());
269 return data()[Base::AbsoluteIndex(
size() - 1)];
273 constexpr std::pair<span<const value_type>, span<const value_type>>
275 constexpr std::pair<span<value_type>, span<value_type>>
contiguous_data() {
276 auto [first, second] = std::as_const(*this).contiguous_data();
277 return {{
const_cast<pointer
>(first.data()), first.size()},
278 {
const_cast<pointer
>(second.data()), second.size()}};
283 constexpr iterator begin() noexcept {
288 return iterator(derived(), 0);
290 constexpr const_iterator begin() const noexcept {
return cbegin(); }
291 constexpr const_iterator cbegin() const noexcept {
295 return const_iterator(derived(), 0);
298 constexpr iterator end() noexcept {
return iterator(derived(),
size()); }
299 constexpr const_iterator end() const noexcept {
return cend(); }
300 constexpr const_iterator cend() const noexcept {
301 return const_iterator(derived(),
size());
307 if constexpr (!std::is_trivially_destructible_v<value_type>) {
308 std::destroy(begin(), end());
310 Base::ClearIndices();
314 iterator
erase(const_iterator pos) {
315 PW_DASSERT(pos.pos_ <
size());
316 return erase(pos, pos + 1);
321 iterator
erase(const_iterator first, const_iterator last);
323 void push_back(
const value_type& value) { PW_ASSERT(try_push_back(value)); }
325 void push_back(value_type&& value) {
326 PW_ASSERT(try_push_back(std::move(value)));
329 template <
typename... Args>
330 void emplace_back(Args&&... args) {
331 PW_ASSERT(try_emplace_back(std::forward<Args>(args)...));
336 void push_front(
const value_type& value) { PW_ASSERT(try_push_front(value)); }
338 void push_front(value_type&& value) {
339 PW_ASSERT(try_push_front(std::move(value)));
342 template <
typename... Args>
343 void emplace_front(Args&&... args) {
344 PW_ASSERT(try_emplace_front(std::forward<Args>(args)...));
353 template <
typename... Args>
354 iterator
emplace(const_iterator pos, Args&&... args) {
355 std::optional<iterator> result =
357 PW_ASSERT(result.has_value());
364 iterator
insert(const_iterator pos,
const value_type& value) {
365 std::optional<iterator> result =
try_insert(pos, value);
366 PW_ASSERT(result.has_value());
374 iterator
insert(const_iterator pos, value_type&& value) {
375 std::optional<iterator> result =
try_insert(pos, std::move(value));
376 PW_ASSERT(result.has_value());
386 const value_type& value) {
387 std::optional<iterator> result =
try_insert(pos, count, value);
388 PW_ASSERT(result.has_value());
396 template <
typename InputIt,
397 typename = containers::internal::EnableIfInputIterator<InputIt>>
398 iterator
insert(const_iterator pos, InputIt first, InputIt last);
403 iterator
insert(const_iterator pos, std::initializer_list<value_type> ilist) {
404 std::optional<iterator> result =
try_insert(pos, ilist);
405 PW_ASSERT(result.has_value());
409 void resize(size_type new_size) { resize(new_size, value_type()); }
411 void resize(size_type new_size,
const value_type& value) {
412 PW_ASSERT(try_resize(new_size, value));
416 explicit constexpr GenericDeque(size_type initial_capacity) noexcept
417 : GenericDequeBase<CountAndCapacityType>(initial_capacity) {}
422 Derived& operator=(
const std::initializer_list<value_type>& list) {
427 template <
typename T,
typename = containers::
internal::EnableIfIterable<T>>
428 Derived& operator=(
const T& other) {
429 assign(other.begin(), other.end());
439 [[nodiscard]]
bool try_assign(size_type count,
const value_type& value);
447 template <
typename It,
449 typename = containers::internal::EnableIfForwardIterator<It>>
454 [[nodiscard]]
bool try_assign(
const std::initializer_list<value_type>& list) {
465 template <
typename... Args>
466 [[nodiscard]] std::optional<iterator>
try_emplace(const_iterator pos,
474 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
475 const value_type& value) {
484 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
485 value_type&& value) {
494 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
496 const value_type& value);
503 template <
typename ForwardIt,
504 typename = containers::internal::EnableIfForwardIterator<ForwardIt>>
505 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
515 const_iterator pos, std::initializer_list<value_type> ilist) {
516 return try_insert(pos, ilist.begin(), ilist.end());
519 [[nodiscard]]
bool try_push_back(
const value_type& value) {
520 return try_emplace_back(value);
523 [[nodiscard]]
bool try_push_back(value_type&& value) {
524 return try_emplace_back(std::move(value));
527 template <
typename... Args>
528 [[nodiscard]]
bool try_emplace_back(Args&&... args);
530 [[nodiscard]]
bool try_push_front(
const value_type& value) {
531 return try_emplace_front(value);
534 [[nodiscard]]
bool try_push_front(value_type&& value) {
535 return try_emplace_front(std::move(value));
538 template <
typename... Args>
539 [[nodiscard]]
bool try_emplace_front(Args&&... args);
541 [[nodiscard]]
bool try_resize(size_type new_size) {
542 return try_resize(new_size, value_type());
545 [[nodiscard]]
bool try_resize(size_type new_size,
const value_type& value);
548 constexpr Derived& derived() {
return static_cast<Derived&
>(*this); }
549 constexpr const Derived& derived()
const {
550 return static_cast<const Derived&
>(*this);
553 constexpr size_type head()
const {
return Base::head_; }
554 constexpr size_type tail()
const {
return Base::tail_; }
557 constexpr pointer data() {
return derived().data(); }
558 constexpr const_pointer data()
const {
return derived().data(); }
561 bool ShiftForInsert(size_type insert_index, size_type new_items);
564 void ShiftLeft(size_type insert_index, size_type new_items);
565 void ShiftRight(size_type insert_index, size_type new_items);
568 bool CheckCapacityAdd(size_type count) {
570 return CheckedAdd(
size(), count, new_size) && CheckCapacity(new_size);
574 constexpr bool CheckCapacity(size_type new_size) {
575 if constexpr (Derived::kFixedCapacity) {
578 return derived().try_reserve(new_size);
583 template <
typename... Args>
584 void EmplaceBackUnchecked(Args&&... args) {
585 new (&data()[tail()]) value_type(std::forward<Args>(args)...);
592template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
593template <
typename It,
int&...,
typename>
597 if constexpr (Derived::kFixedCapacity ||
599 typename std::iterator_traits<It>::iterator_category,
600 std::input_iterator_tag>) {
602 while (start != finish) {
607 PW_ASSERT(try_assign(start, finish));
611template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
613 size_type count,
const value_type& value) {
614 if (!CheckCapacity(count)) {
618 Base::PushBack(count);
619 std::uninitialized_fill_n(data(), count, value);
623template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
624template <
typename It,
int&...,
typename>
626 It start, It finish) {
628 static_assert(std::is_convertible_v<
629 typename std::iterator_traits<It>::iterator_category,
630 std::forward_iterator_tag>);
631 const auto items = std::distance(start, finish);
632 PW_DASSERT(items >= 0);
633 if (
static_cast<std::make_unsigned_t<decltype(items)
>>(items) >
634 std::numeric_limits<size_type>::max()) {
637 const size_type count =
static_cast<size_type
>(items);
638 if (!CheckCapacity(count)) {
643 Base::PushBack(count);
644 std::uninitialized_move(start, finish, data());
648template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
649constexpr std::pair<span<const ValueType>, span<const ValueType>>
653 return {span<const value_type>(), span<const value_type>()};
655 if (tail() > head()) {
658 return {span<const value_type>(&data()[head()], size()),
659 span<const value_type>()};
664 return {span<const value_type>(&data()[head()], capacity() - head()),
665 span<const value_type>(&data()[0], tail())};
669template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
670template <
typename... Args>
673 if (!CheckCapacityAdd(1)) {
676 EmplaceBackUnchecked(std::forward<Args>(args)...);
680template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
681void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_back() {
683 if constexpr (!std::is_trivially_destructible_v<value_type>) {
684 std::destroy_at(&back());
689template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
690template <
typename... Args>
691bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_emplace_front(
693 if (!CheckCapacityAdd(1)) {
697 new (&data()[head()]) value_type(std::forward<Args>(args)...);
701template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
702void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_front() {
704 if constexpr (!std::is_trivially_destructible_v<value_type>) {
705 std::destroy_at(&front());
710template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
711bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_resize(
712 size_type new_size,
const value_type& value) {
713 if (size() < new_size) {
714 if (!CheckCapacity(new_size)) {
717 const size_type new_items = new_size - size();
718 for (size_type i = 0; i < new_items; ++i) {
719 EmplaceBackUnchecked(value);
722 while (size() > new_size) {
729template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
730typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
732 const_iterator first, const_iterator last) {
733 PW_DASSERT(first <= last);
734 const iterator first_it(derived(), first.pos_);
735 const iterator last_it(derived(), last.pos_);
737 const size_type items_to_erase =
static_cast<size_type
>(last - first);
738 if (items_to_erase == 0) {
742 const size_type items_after =
static_cast<size_type
>(size() - last.pos_);
744 if (first.pos_ < items_after) {
745 std::move_backward(begin(), first_it, last_it);
746 if constexpr (!std::is_trivially_destructible_v<value_type>) {
747 std::destroy(begin(), begin() + items_to_erase);
749 Base::head_ = Base::AbsoluteIndex(items_to_erase);
751 std::move(last_it, end(), first_it);
752 if constexpr (!std::is_trivially_destructible_v<value_type>) {
753 std::destroy(first_it + items_after, end());
755 Base::tail_ = Base::AbsoluteIndex(first.pos_ + items_after);
757 Base::count_and_capacity().SetCount(size() - items_to_erase);
761template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
762template <
typename... Args>
764 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
766 const_iterator pos, Args&&... args) {
768 if (!ShiftForInsert(pos.pos_, 1)) {
771 iterator it(derived(), pos.pos_);
772 new (std::addressof(*it)) value_type(std::forward<Args>(args)...);
776template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
777bool GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftForInsert(
778 const size_type insert_index, size_type new_items) {
779 if (!CheckCapacityAdd(new_items)) {
783 if (insert_index < size() / 2) {
784 ShiftLeft(insert_index, new_items);
786 ShiftRight(insert_index, new_items);
791template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
792void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftLeft(
793 const size_type insert_index, size_type new_items) {
794 Base::PushFront(new_items);
795 iterator original_begin(derived(), new_items);
797 const size_type move_to_new_slots = std::min(new_items, insert_index);
798 auto [next_src, next_dst] =
799 std::uninitialized_move_n(original_begin, move_to_new_slots, begin());
801 const size_type move_to_existing_slots = insert_index - move_to_new_slots;
802 std::move(next_src, next_src + move_to_existing_slots, next_dst);
807 if constexpr (!std::is_trivially_destructible_v<value_type>) {
809 iterator(derived(), std::max(insert_index, original_begin.pos_)),
810 iterator(derived(), insert_index + new_items));
814template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
815void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftRight(
816 const size_type insert_index, size_type new_items) {
817 const size_type items_after = size() - insert_index;
818 iterator original_end = end();
819 Base::PushBack(new_items);
821 const size_type move_to_new_slots = std::min(new_items, items_after);
822 std::uninitialized_move(original_end - move_to_new_slots,
824 end() - move_to_new_slots);
826 const size_type move_to_existing_slots = items_after - move_to_new_slots;
827 iterator pos(derived(), insert_index);
828 std::move_backward(pos, pos + move_to_existing_slots, original_end);
833 if constexpr (!std::is_trivially_destructible_v<value_type>) {
835 iterator(derived(), insert_index),
837 std::min(
static_cast<size_type
>(insert_index + new_items),
838 original_end.pos_)));
842template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
844 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
846 const_iterator pos, size_type count,
const value_type& value) {
848 return iterator(derived(), pos.pos_);
850 if (!ShiftForInsert(pos.pos_, count)) {
854 iterator it(derived(), pos.pos_);
855 std::uninitialized_fill_n(it, count, value);
859template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
860template <
typename InputIt,
typename>
861typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
863 const_iterator pos, InputIt first, InputIt last) {
865 if constexpr (std::is_same_v<
866 typename std::iterator_traits<InputIt>::iterator_category,
867 std::input_iterator_tag>) {
870 iterator insert_pos = iterator(derived(), pos.pos_);
871 while (first != last) {
872 insert_pos = emplace(insert_pos, *first);
876 return iterator(derived(), pos.pos_);
878 std::optional<iterator> result = try_insert(pos, first, last);
879 PW_ASSERT(result.has_value());
884template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
885template <
typename ForwardIt,
typename>
887 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
889 const_iterator pos, ForwardIt first, ForwardIt last) {
890 static_assert(std::is_convertible_v<
891 typename std::iterator_traits<ForwardIt>::iterator_category,
892 std::forward_iterator_tag>);
893 const auto distance = std::distance(first, last);
894 PW_DASSERT(distance >= 0);
895 const size_type count =
static_cast<size_type
>(distance);
897 const iterator it(derived(), pos.pos_);
901 if (!ShiftForInsert(pos.pos_, count)) {
904 std::uninitialized_move(first, last, it);
Definition: generic_deque.h:49
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:58
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:63
Definition: generic_deque.h:189
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:58
iterator insert(const_iterator pos, size_type count, const value_type &value)
Definition: generic_deque.h:384
constexpr std::pair< span< const value_type >, span< const value_type > > contiguous_data() const
Provides access to the valid data in a contiguous form.
Definition: generic_deque.h:650
std::optional< iterator > try_insert(const_iterator pos, std::initializer_list< value_type > ilist)
Definition: generic_deque.h:514
bool try_assign(size_type count, const value_type &value)
Definition: generic_deque.h:612
void assign(const std::initializer_list< value_type > &list)
Sets contents to copies of the items from the list. Crashes if cannot fit.
Definition: generic_deque.h:232
iterator insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:364
void assign(It start, It finish)
Definition: generic_deque.h:594
iterator erase(const_iterator first, const_iterator last)
Definition: generic_deque.h:731
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
bool try_assign(const std::initializer_list< value_type > &list)
Definition: generic_deque.h:454
iterator emplace(const_iterator pos, Args &&... args)
Definition: generic_deque.h:354
iterator erase(const_iterator pos)
Erases the item at pos, which must be a dereferenceable iterator.
Definition: generic_deque.h:314
iterator insert(const_iterator pos, InputIt first, InputIt last)
Definition: generic_deque.h:862
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:63
std::optional< iterator > try_insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:474
std::optional< iterator > try_insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:484
void assign(size_type count, const value_type &value)
Sets the contents to count copies of value. Crashes if cannot fit.
Definition: generic_deque.h:220
iterator insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:374
std::optional< iterator > try_insert(const_iterator pos, ForwardIt first, ForwardIt last)
iterator insert(const_iterator pos, std::initializer_list< value_type > ilist)
Definition: generic_deque.h:403
constexpr bool CheckedAdd(A a, B b, T &result)
Definition: checked_arithmetic.h:42