18#include <initializer_list>
27#include "lib/stdcompat/utility.h"
28#include "pw_assert/assert.h"
29#include "pw_containers/internal/deque_iterator.h"
30#include "pw_containers/internal/traits.h"
31#include "pw_containers/internal/wrap.h"
32#include "pw_numeric/checked_arithmetic.h"
33#include "pw_span/span.h"
35namespace pw::containers::internal {
38using EnableIfIterable =
39 std::enable_if_t<
true,
decltype(T().begin(), T().end())>;
55template <
typename CountAndCapacityType>
58 using size_type =
typename CountAndCapacityType::size_type;
62 [[nodiscard]]
constexpr bool empty()
const noexcept {
return size() == 0; }
64 [[nodiscard]]
constexpr bool full()
const noexcept {
69 constexpr size_type
size() const noexcept {
70 return count_and_capacity_.count();
74 constexpr size_type
capacity() const noexcept {
75 return count_and_capacity_.capacity();
81 CountAndCapacityType& count_and_capacity() noexcept {
82 return count_and_capacity_;
85 constexpr void MoveAssignIndices(GenericDequeBase& other)
noexcept {
86 count_and_capacity_ = std::move(other.count_and_capacity_);
87 head_ = cpp20::exchange(other.head_, 0);
88 tail_ = cpp20::exchange(other.tail_, 0);
91 void SwapIndices(GenericDequeBase& other)
noexcept {
92 std::swap(count_and_capacity_, other.count_and_capacity_);
93 std::swap(head_, other.head_);
94 std::swap(tail_, other.tail_);
99 bool CanExtendBuffer()
const {
return tail_ > head_ || tail_ == 0; }
102 bool CanShrinkBuffer()
const {
return head_ == 0; }
104 void HandleNewBuffer(size_type new_capacity) {
105 count_and_capacity_.SetCapacity(new_capacity);
107 tail_ =
size() == new_capacity
109 : count_and_capacity_.count();
112 void HandleExtendedBuffer(size_type new_capacity) {
113 count_and_capacity_.SetCapacity(new_capacity);
115 tail_ = head_ + count_and_capacity_.count();
119 void HandleShrunkBuffer(size_type new_capacity) {
120 count_and_capacity_.SetCapacity(new_capacity);
121 if (tail_ == new_capacity) {
128 template <
typename Derived,
typename ValueType,
typename S>
129 friend class GenericDeque;
131 explicit constexpr GenericDequeBase(size_type initial_capacity) noexcept
132 : count_and_capacity_(initial_capacity), head_(0), tail_(0) {}
134 constexpr void ClearIndices() {
135 count_and_capacity_.SetCount(0);
143 constexpr size_type AbsoluteIndex(
const size_type relative_index)
const {
144 const size_type absolute_index = head_ + relative_index;
146 return absolute_index;
152 constexpr size_type AbsoluteIndexChecked(
153 const size_type relative_index)
const {
154 PW_ASSERT(relative_index <
size());
155 return AbsoluteIndex(relative_index);
158 constexpr void PushBack(size_type count = 1) {
159 IncrementWithWrap(tail_, count,
capacity());
160 count_and_capacity_.IncrementCount(count);
162 constexpr void PushFront(size_type count = 1) {
163 DecrementWithWrap(head_, count,
capacity());
164 count_and_capacity_.IncrementCount(count);
166 constexpr void PopFront() {
167 IncrementWithWrap(head_, size_type(1),
capacity());
168 count_and_capacity_.DecrementCount();
170 constexpr void PopBack() {
171 DecrementWithWrap(tail_, size_type(1),
capacity());
172 count_and_capacity_.DecrementCount();
175 CountAndCapacityType count_and_capacity_;
184template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
190 using value_type = ValueType;
191 using size_type =
typename CountAndCapacityType::size_type;
192 using difference_type = ptrdiff_t;
193 using reference = value_type&;
194 using const_reference =
const value_type&;
195 using pointer = value_type*;
196 using const_pointer =
const value_type*;
197 using iterator = containers::internal::DequeIterator<Derived>;
198 using const_iterator = containers::internal::DequeIterator<const Derived>;
216 void assign(size_type count,
const value_type& value) {
222 template <
typename It,
224 typename = containers::internal::EnableIfInputIterator<It>>
228 void assign(
const std::initializer_list<value_type>& list) {
229 assign(list.begin(), list.end());
234 constexpr reference at(size_type index) {
235 return data()[Base::AbsoluteIndexChecked(index)];
237 constexpr const_reference at(size_type index)
const {
238 return data()[Base::AbsoluteIndexChecked(index)];
241 constexpr reference operator[](size_type index) {
242 PW_DASSERT(index <
size());
243 return data()[Base::AbsoluteIndex(index)];
245 constexpr const_reference operator[](size_type index)
const {
246 PW_DASSERT(index <
size());
247 return data()[Base::AbsoluteIndex(index)];
250 constexpr reference front() {
251 PW_DASSERT(!empty());
252 return data()[head()];
254 constexpr const_reference front()
const {
255 PW_DASSERT(!empty());
256 return data()[head()];
259 constexpr reference back() {
260 PW_DASSERT(!empty());
261 return data()[Base::AbsoluteIndex(
size() - 1)];
263 constexpr const_reference back()
const {
264 PW_DASSERT(!empty());
265 return data()[Base::AbsoluteIndex(
size() - 1)];
269 constexpr std::pair<span<const value_type>, span<const value_type>>
272 auto [first, second] = std::as_const(*this).contiguous_data();
273 return {{
const_cast<pointer
>(first.data()), first.size()},
274 {
const_cast<pointer
>(second.data()), second.size()}};
279 constexpr iterator begin() noexcept {
284 return iterator(derived(), 0);
286 constexpr const_iterator begin() const noexcept {
return cbegin(); }
287 constexpr const_iterator cbegin() const noexcept {
291 return const_iterator(derived(), 0);
294 constexpr iterator end() noexcept {
return iterator(derived(),
size()); }
295 constexpr const_iterator end() const noexcept {
return cend(); }
296 constexpr const_iterator cend() const noexcept {
297 return const_iterator(derived(),
size());
302 constexpr void clear() {
304 Base::ClearIndices();
308 iterator
erase(const_iterator pos) {
309 PW_DASSERT(pos.pos_ <
size());
310 return erase(pos, pos + 1);
315 iterator
erase(const_iterator first, const_iterator last);
317 void push_back(
const value_type& value) { PW_ASSERT(try_push_back(value)); }
319 void push_back(value_type&& value) {
320 PW_ASSERT(try_push_back(std::move(value)));
323 template <
typename... Args>
324 void emplace_back(Args&&... args) {
325 PW_ASSERT(try_emplace_back(std::forward<Args>(args)...));
330 void push_front(
const value_type& value) { PW_ASSERT(try_push_front(value)); }
332 void push_front(value_type&& value) {
333 PW_ASSERT(try_push_front(std::move(value)));
336 template <
typename... Args>
337 void emplace_front(Args&&... args) {
338 PW_ASSERT(try_emplace_front(std::forward<Args>(args)...));
347 template <
typename... Args>
348 iterator
emplace(const_iterator pos, Args&&... args) {
349 std::optional<iterator> result =
351 PW_ASSERT(result.has_value());
358 iterator
insert(const_iterator pos,
const value_type& value) {
359 std::optional<iterator> result =
try_insert(pos, value);
360 PW_ASSERT(result.has_value());
368 iterator
insert(const_iterator pos, value_type&& value) {
369 std::optional<iterator> result =
try_insert(pos, std::move(value));
370 PW_ASSERT(result.has_value());
380 const value_type& value) {
381 std::optional<iterator> result =
try_insert(pos, count, value);
382 PW_ASSERT(result.has_value());
390 template <
typename InputIt,
391 typename = containers::internal::EnableIfInputIterator<InputIt>>
392 iterator
insert(const_iterator pos, InputIt first, InputIt last);
397 iterator
insert(const_iterator pos, std::initializer_list<value_type> ilist) {
398 std::optional<iterator> result =
try_insert(pos, ilist);
399 PW_ASSERT(result.has_value());
403 void resize(size_type new_size) { resize(new_size, value_type()); }
405 void resize(size_type new_size,
const value_type& value) {
406 PW_ASSERT(try_resize(new_size, value));
410 explicit constexpr GenericDeque(size_type initial_capacity) noexcept
411 : GenericDequeBase<CountAndCapacityType>(initial_capacity) {}
413 constexpr void DestroyAll() {
414 if constexpr (!std::is_trivially_destructible_v<value_type>) {
416 std::destroy(first.begin(), first.end());
417 std::destroy(second.begin(), second.end());
424 Derived& operator=(
const std::initializer_list<value_type>& list) {
429 template <
typename T,
typename = containers::
internal::EnableIfIterable<T>>
430 Derived& operator=(
const T& other) {
431 assign(other.begin(), other.end());
441 [[nodiscard]]
bool try_assign(size_type count,
const value_type& value);
449 template <
typename It,
451 typename = containers::internal::EnableIfForwardIterator<It>>
456 [[nodiscard]]
bool try_assign(
const std::initializer_list<value_type>& list) {
467 template <
typename... Args>
468 [[nodiscard]] std::optional<iterator>
try_emplace(const_iterator pos,
476 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
477 const value_type& value) {
486 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
487 value_type&& value) {
496 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
498 const value_type& value);
505 template <
typename ForwardIt,
506 typename = containers::internal::EnableIfForwardIterator<ForwardIt>>
507 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
517 const_iterator pos, std::initializer_list<value_type> ilist) {
518 return try_insert(pos, ilist.begin(), ilist.end());
521 [[nodiscard]]
bool try_push_back(
const value_type& value) {
522 return try_emplace_back(value);
525 [[nodiscard]]
bool try_push_back(value_type&& value) {
526 return try_emplace_back(std::move(value));
529 template <
typename... Args>
530 [[nodiscard]]
bool try_emplace_back(Args&&... args);
532 [[nodiscard]]
bool try_push_front(
const value_type& value) {
533 return try_emplace_front(value);
536 [[nodiscard]]
bool try_push_front(value_type&& value) {
537 return try_emplace_front(std::move(value));
540 template <
typename... Args>
541 [[nodiscard]]
bool try_emplace_front(Args&&... args);
543 [[nodiscard]]
bool try_resize(size_type new_size) {
544 return try_resize(new_size, value_type());
547 [[nodiscard]]
bool try_resize(size_type new_size,
const value_type& value);
549 template <
typename... Args>
550 [[nodiscard]] std::optional<iterator> try_emplace_shift_right(
551 const_iterator pos, Args&&... args);
553 [[nodiscard]] std::optional<iterator> try_insert_shift_right(
554 const_iterator pos, size_type count,
const value_type& value);
556 template <
typename ForwardIt,
557 typename = containers::internal::EnableIfForwardIterator<ForwardIt>>
558 [[nodiscard]] std::optional<iterator> try_insert_shift_right(
559 const_iterator pos, ForwardIt first, ForwardIt last);
562 constexpr Derived& derived() {
return static_cast<Derived&
>(*this); }
563 constexpr const Derived& derived()
const {
564 return static_cast<const Derived&
>(*this);
567 constexpr size_type head()
const {
return Base::head_; }
568 constexpr size_type tail()
const {
return Base::tail_; }
571 constexpr pointer data() {
return derived().data(); }
572 constexpr const_pointer data()
const {
return derived().data(); }
575 bool ShiftForInsert(size_type insert_index, size_type new_items);
578 void ShiftLeft(size_type insert_index, size_type new_items);
579 void ShiftRight(size_type insert_index, size_type new_items);
582 bool CheckCapacityAdd(size_type count) {
584 return CheckedAdd(
size(), count, new_size) && CheckCapacity(new_size);
588 constexpr bool CheckCapacity(size_type new_size) {
589 if constexpr (Derived::kFixedCapacity) {
592 return derived().try_reserve(new_size);
597 template <
typename... Args>
598 void EmplaceBackUnchecked(Args&&... args) {
599 new (&data()[tail()]) value_type(std::forward<Args>(args)...);
606template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
607template <
typename It,
int&...,
typename>
611 if constexpr (Derived::kFixedCapacity ||
613 typename std::iterator_traits<It>::iterator_category,
614 std::input_iterator_tag>) {
616 while (start != finish) {
621 PW_ASSERT(try_assign(start, finish));
625template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
627 size_type count,
const value_type& value) {
628 if (!CheckCapacity(count)) {
632 Base::PushBack(count);
633 std::uninitialized_fill_n(data(), count, value);
637template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
638template <
typename It,
int&...,
typename>
640 It start, It finish) {
642 static_assert(std::is_convertible_v<
643 typename std::iterator_traits<It>::iterator_category,
644 std::forward_iterator_tag>);
645 const auto items = std::distance(start, finish);
646 PW_DASSERT(items >= 0);
647 if (
static_cast<std::make_unsigned_t<decltype(items)
>>(items) >
648 std::numeric_limits<size_type>::max()) {
651 const size_type count =
static_cast<size_type
>(items);
652 if (!CheckCapacity(count)) {
657 Base::PushBack(count);
658 std::uninitialized_move(start, finish, data());
662template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
669 if (tail() > head()) {
683template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
684template <
typename... Args>
687 if (!CheckCapacityAdd(1)) {
690 EmplaceBackUnchecked(std::forward<Args>(args)...);
694template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
695void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_back() {
697 if constexpr (!std::is_trivially_destructible_v<value_type>) {
698 std::destroy_at(&back());
703template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
704template <
typename... Args>
705bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_emplace_front(
707 if (!CheckCapacityAdd(1)) {
711 new (&data()[head()]) value_type(std::forward<Args>(args)...);
715template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
716void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_front() {
718 if constexpr (!std::is_trivially_destructible_v<value_type>) {
719 std::destroy_at(&front());
724template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
725bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_resize(
726 size_type new_size,
const value_type& value) {
727 if (size() < new_size) {
728 if (!CheckCapacity(new_size)) {
731 const size_type new_items = new_size - size();
732 for (size_type i = 0; i < new_items; ++i) {
733 EmplaceBackUnchecked(value);
736 while (size() > new_size) {
743template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
744typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
746 const_iterator first, const_iterator last) {
747 PW_DASSERT(first <= last);
748 const iterator first_it(derived(), first.pos_);
749 const iterator last_it(derived(), last.pos_);
751 const size_type items_to_erase =
static_cast<size_type
>(last - first);
752 if (items_to_erase == 0) {
756 const size_type items_after =
static_cast<size_type
>(size() - last.pos_);
758 if (first.pos_ < items_after) {
759 std::move_backward(begin(), first_it, last_it);
760 if constexpr (!std::is_trivially_destructible_v<value_type>) {
761 std::destroy(begin(), begin() + items_to_erase);
763 Base::head_ = Base::AbsoluteIndex(items_to_erase);
765 std::move(last_it, end(), first_it);
766 if constexpr (!std::is_trivially_destructible_v<value_type>) {
767 std::destroy(first_it + items_after, end());
769 Base::tail_ = Base::AbsoluteIndex(first.pos_ + items_after);
771 Base::count_and_capacity().SetCount(size() - items_to_erase);
775template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
776template <
typename... Args>
778 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
780 const_iterator pos, Args&&... args) {
782 if (!ShiftForInsert(pos.pos_, 1)) {
785 iterator it(derived(), pos.pos_);
786 new (std::addressof(*it)) value_type(std::forward<Args>(args)...);
790template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
791bool GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftForInsert(
792 const size_type insert_index, size_type new_items) {
793 if (!CheckCapacityAdd(new_items)) {
797 if (insert_index < size() / 2) {
798 ShiftLeft(insert_index, new_items);
800 ShiftRight(insert_index, new_items);
805template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
806void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftLeft(
807 const size_type insert_index, size_type new_items) {
808 Base::PushFront(new_items);
809 iterator original_begin(derived(), new_items);
811 const size_type move_to_new_slots = std::min(new_items, insert_index);
812 auto [next_src, next_dst] =
813 std::uninitialized_move_n(original_begin, move_to_new_slots, begin());
815 const size_type move_to_existing_slots = insert_index - move_to_new_slots;
816 std::move(next_src, next_src + move_to_existing_slots, next_dst);
821 if constexpr (!std::is_trivially_destructible_v<value_type>) {
823 iterator(derived(), std::max(insert_index, original_begin.pos_)),
824 iterator(derived(), insert_index + new_items));
828template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
829void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftRight(
830 const size_type insert_index, size_type new_items) {
831 const size_type items_after = size() - insert_index;
832 iterator original_end = end();
833 Base::PushBack(new_items);
835 const size_type move_to_new_slots = std::min(new_items, items_after);
836 std::uninitialized_move(original_end - move_to_new_slots,
838 end() - move_to_new_slots);
840 const size_type move_to_existing_slots = items_after - move_to_new_slots;
841 iterator pos(derived(), insert_index);
842 std::move_backward(pos, pos + move_to_existing_slots, original_end);
847 if constexpr (!std::is_trivially_destructible_v<value_type>) {
849 iterator(derived(), insert_index),
851 std::min(
static_cast<size_type
>(insert_index + new_items),
852 original_end.pos_)));
856template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
858 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
860 const_iterator pos, size_type count,
const value_type& value) {
862 return iterator(derived(), pos.pos_);
864 if (!ShiftForInsert(pos.pos_, count)) {
868 iterator it(derived(), pos.pos_);
869 std::uninitialized_fill_n(it, count, value);
873template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
874template <
typename InputIt,
typename>
875typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
877 const_iterator pos, InputIt first, InputIt last) {
879 if constexpr (std::is_same_v<
880 typename std::iterator_traits<InputIt>::iterator_category,
881 std::input_iterator_tag>) {
884 iterator insert_pos = iterator(derived(), pos.pos_);
885 while (first != last) {
886 insert_pos = emplace(insert_pos, *first);
890 return iterator(derived(), pos.pos_);
892 std::optional<iterator> result = try_insert(pos, first, last);
893 PW_ASSERT(result.has_value());
898template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
899template <
typename ForwardIt,
typename>
901 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
903 const_iterator pos, ForwardIt first, ForwardIt last) {
904 static_assert(std::is_convertible_v<
905 typename std::iterator_traits<ForwardIt>::iterator_category,
906 std::forward_iterator_tag>);
907 const auto distance = std::distance(first, last);
908 PW_DASSERT(distance >= 0);
909 const size_type count =
static_cast<size_type
>(distance);
911 const iterator it(derived(), pos.pos_);
915 if (!ShiftForInsert(pos.pos_, count)) {
918 std::uninitialized_move(first, last, it);
922template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
923template <
typename... Args>
925 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
926GenericDeque<Derived, ValueType, CountAndCapacityType>::try_emplace_shift_right(
927 const_iterator pos, Args&&... args) {
928 if (!CheckCapacityAdd(1)) {
931 ShiftRight(pos.pos_, 1);
932 iterator it(derived(), pos.pos_);
933 new (std::addressof(*it)) value_type(std::forward<Args>(args)...);
937template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
939 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
940GenericDeque<Derived, ValueType, CountAndCapacityType>::try_insert_shift_right(
941 const_iterator pos, size_type count,
const value_type& value) {
943 return iterator(derived(), pos.pos_);
945 if (!CheckCapacityAdd(count)) {
949 ShiftRight(pos.pos_, count);
950 iterator it(derived(), pos.pos_);
951 std::uninitialized_fill_n(it, count, value);
955template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
956template <
typename ForwardIt,
typename>
958 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
959GenericDeque<Derived, ValueType, CountAndCapacityType>::try_insert_shift_right(
960 const_iterator pos, ForwardIt first, ForwardIt last) {
961 static_assert(std::is_convertible_v<
962 typename std::iterator_traits<ForwardIt>::iterator_category,
963 std::forward_iterator_tag>);
964 const auto distance = std::distance(first, last);
965 PW_DASSERT(distance >= 0);
966 const size_type count =
static_cast<size_type
>(distance);
968 const iterator it(derived(), pos.pos_);
972 if (!CheckCapacityAdd(count)) {
975 ShiftRight(pos.pos_, count);
976 std::uninitialized_move(first, last, it);
Definition: generic_deque.h:56
Definition: generic_deque.h:185
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:69
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:74
Definition: span_impl.h:235
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:69
iterator insert(const_iterator pos, size_type count, const value_type &value)
Definition: generic_deque.h:378
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:664
std::optional< iterator > try_insert(const_iterator pos, std::initializer_list< value_type > ilist)
Definition: generic_deque.h:516
bool try_assign(size_type count, const value_type &value)
Definition: generic_deque.h:626
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:228
iterator insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:358
void assign(It start, It finish)
Definition: generic_deque.h:608
iterator erase(const_iterator first, const_iterator last)
Definition: generic_deque.h:745
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
bool try_assign(const std::initializer_list< value_type > &list)
Definition: generic_deque.h:456
iterator emplace(const_iterator pos, Args &&... args)
Definition: generic_deque.h:348
iterator erase(const_iterator pos)
Erases the item at pos, which must be a dereferenceable iterator.
Definition: generic_deque.h:308
iterator insert(const_iterator pos, InputIt first, InputIt last)
Definition: generic_deque.h:876
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:74
std::optional< iterator > try_insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:476
std::optional< iterator > try_insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:486
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:216
iterator insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:368
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:397
constexpr bool CheckedAdd(A a, B b, T &result)
Definition: checked_arithmetic.h:70