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())>;
53template <
typename CountAndCapacityType>
56 using size_type =
typename CountAndCapacityType::size_type;
60 [[nodiscard]]
constexpr bool empty()
const noexcept {
return size() == 0; }
63 constexpr size_type
size() const noexcept {
64 return count_and_capacity_.count();
68 constexpr size_type
capacity() const noexcept {
69 return count_and_capacity_.capacity();
75 CountAndCapacityType& count_and_capacity() noexcept {
76 return count_and_capacity_;
79 constexpr void MoveAssignIndices(GenericDequeBase& other)
noexcept {
80 count_and_capacity_ = std::move(other.count_and_capacity_);
81 head_ = std::exchange(other.head_, 0);
82 tail_ = std::exchange(other.tail_, 0);
85 void SwapIndices(GenericDequeBase& other)
noexcept {
86 std::swap(count_and_capacity_, other.count_and_capacity_);
87 std::swap(head_, other.head_);
88 std::swap(tail_, other.tail_);
93 bool CanExtendBuffer()
const {
return tail_ > head_ || tail_ == 0; }
96 bool CanShrinkBuffer()
const {
return head_ == 0; }
98 void HandleNewBuffer(size_type new_capacity) {
99 count_and_capacity_.SetCapacity(new_capacity);
101 tail_ =
size() == new_capacity
103 : count_and_capacity_.count();
106 void HandleExtendedBuffer(size_type new_capacity) {
107 count_and_capacity_.SetCapacity(new_capacity);
109 tail_ = head_ + count_and_capacity_.count();
113 void HandleShrunkBuffer(size_type new_capacity) {
114 count_and_capacity_.SetCapacity(new_capacity);
115 if (tail_ == new_capacity) {
122 template <
typename Derived,
typename ValueType,
typename S>
123 friend class GenericDeque;
125 explicit constexpr GenericDequeBase(size_type initial_capacity) noexcept
126 : count_and_capacity_(initial_capacity), head_(0), tail_(0) {}
128 constexpr void ClearIndices() {
129 count_and_capacity_.SetCount(0);
137 constexpr size_type AbsoluteIndex(
const size_type relative_index)
const {
138 const size_type absolute_index = head_ + relative_index;
140 return absolute_index;
146 constexpr size_type AbsoluteIndexChecked(
147 const size_type relative_index)
const {
148 PW_ASSERT(relative_index <
size());
149 return AbsoluteIndex(relative_index);
152 constexpr void PushBack(size_type count = 1) {
153 IncrementWithWrap(tail_, count);
154 count_and_capacity_.IncrementCount(count);
156 constexpr void PushFront(size_type count = 1) {
157 DecrementWithWrap(head_, count);
158 count_and_capacity_.IncrementCount(count);
160 constexpr void PopFront() {
161 IncrementWithWrap(head_, 1);
162 count_and_capacity_.DecrementCount();
164 constexpr void PopBack() {
165 DecrementWithWrap(tail_, 1);
166 count_and_capacity_.DecrementCount();
169 constexpr void IncrementWithWrap(size_type& index, size_type count)
const {
177 constexpr void DecrementWithWrap(size_type& index, size_type count)
const {
184 CountAndCapacityType count_and_capacity_;
193template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
199 using value_type = ValueType;
200 using size_type =
typename CountAndCapacityType::size_type;
201 using difference_type = ptrdiff_t;
202 using reference = value_type&;
203 using const_reference =
const value_type&;
204 using pointer = value_type*;
205 using const_pointer =
const value_type*;
206 using iterator = containers::internal::DequeIterator<Derived>;
207 using const_iterator = containers::internal::DequeIterator<const Derived>;
225 void assign(size_type count,
const value_type& value) {
231 template <
typename It,
233 typename = containers::internal::EnableIfInputIterator<It>>
237 void assign(
const std::initializer_list<value_type>& list) {
238 assign(list.begin(), list.end());
243 constexpr reference at(size_type index) {
244 return data()[Base::AbsoluteIndexChecked(index)];
246 constexpr const_reference at(size_type index)
const {
247 return data()[Base::AbsoluteIndexChecked(index)];
250 constexpr reference operator[](size_type index) {
251 PW_DASSERT(index <
size());
252 return data()[Base::AbsoluteIndex(index)];
254 constexpr const_reference operator[](size_type index)
const {
255 PW_DASSERT(index <
size());
256 return data()[Base::AbsoluteIndex(index)];
259 constexpr reference front() {
260 PW_DASSERT(!empty());
261 return data()[head()];
263 constexpr const_reference front()
const {
264 PW_DASSERT(!empty());
265 return data()[head()];
268 constexpr reference back() {
269 PW_DASSERT(!empty());
270 return data()[Base::AbsoluteIndex(
size() - 1)];
272 constexpr const_reference back()
const {
273 PW_DASSERT(!empty());
274 return data()[Base::AbsoluteIndex(
size() - 1)];
278 constexpr std::pair<span<const value_type>, span<const value_type>>
281 auto [first, second] = std::as_const(*this).contiguous_data();
282 return {{
const_cast<pointer
>(first.data()), first.size()},
283 {
const_cast<pointer
>(second.data()), second.size()}};
288 constexpr iterator begin() noexcept {
293 return iterator(derived(), 0);
295 constexpr const_iterator begin() const noexcept {
return cbegin(); }
296 constexpr const_iterator cbegin() const noexcept {
300 return const_iterator(derived(), 0);
303 constexpr iterator end() noexcept {
return iterator(derived(),
size()); }
304 constexpr const_iterator end() const noexcept {
return cend(); }
305 constexpr const_iterator cend() const noexcept {
306 return const_iterator(derived(),
size());
312 if constexpr (!std::is_trivially_destructible_v<value_type>) {
313 std::destroy(begin(), end());
315 Base::ClearIndices();
319 iterator
erase(const_iterator pos) {
320 PW_DASSERT(pos.pos_ <
size());
321 return erase(pos, pos + 1);
326 iterator
erase(const_iterator first, const_iterator last);
328 void push_back(
const value_type& value) { PW_ASSERT(try_push_back(value)); }
330 void push_back(value_type&& value) {
331 PW_ASSERT(try_push_back(std::move(value)));
334 template <
typename... Args>
335 void emplace_back(Args&&... args) {
336 PW_ASSERT(try_emplace_back(std::forward<Args>(args)...));
341 void push_front(
const value_type& value) { PW_ASSERT(try_push_front(value)); }
343 void push_front(value_type&& value) {
344 PW_ASSERT(try_push_front(std::move(value)));
347 template <
typename... Args>
348 void emplace_front(Args&&... args) {
349 PW_ASSERT(try_emplace_front(std::forward<Args>(args)...));
358 template <
typename... Args>
359 iterator
emplace(const_iterator pos, Args&&... args) {
360 std::optional<iterator> result =
362 PW_ASSERT(result.has_value());
369 iterator
insert(const_iterator pos,
const value_type& value) {
370 std::optional<iterator> result =
try_insert(pos, value);
371 PW_ASSERT(result.has_value());
379 iterator
insert(const_iterator pos, value_type&& value) {
380 std::optional<iterator> result =
try_insert(pos, std::move(value));
381 PW_ASSERT(result.has_value());
391 const value_type& value) {
392 std::optional<iterator> result =
try_insert(pos, count, value);
393 PW_ASSERT(result.has_value());
401 template <
typename InputIt,
402 typename = containers::internal::EnableIfInputIterator<InputIt>>
403 iterator
insert(const_iterator pos, InputIt first, InputIt last);
408 iterator
insert(const_iterator pos, std::initializer_list<value_type> ilist) {
409 std::optional<iterator> result =
try_insert(pos, ilist);
410 PW_ASSERT(result.has_value());
414 void resize(size_type new_size) { resize(new_size, value_type()); }
416 void resize(size_type new_size,
const value_type& value) {
417 PW_ASSERT(try_resize(new_size, value));
421 explicit constexpr GenericDeque(size_type initial_capacity) noexcept
422 : GenericDequeBase<CountAndCapacityType>(initial_capacity) {}
427 Derived& operator=(
const std::initializer_list<value_type>& list) {
432 template <
typename T,
typename = containers::
internal::EnableIfIterable<T>>
433 Derived& operator=(
const T& other) {
434 assign(other.begin(), other.end());
444 [[nodiscard]]
bool try_assign(size_type count,
const value_type& value);
452 template <
typename It,
454 typename = containers::internal::EnableIfForwardIterator<It>>
459 [[nodiscard]]
bool try_assign(
const std::initializer_list<value_type>& list) {
470 template <
typename... Args>
471 [[nodiscard]] std::optional<iterator>
try_emplace(const_iterator pos,
479 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
480 const value_type& value) {
489 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
490 value_type&& value) {
499 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
501 const value_type& value);
508 template <
typename ForwardIt,
509 typename = containers::internal::EnableIfForwardIterator<ForwardIt>>
510 [[nodiscard]] std::optional<iterator>
try_insert(const_iterator pos,
520 const_iterator pos, std::initializer_list<value_type> ilist) {
521 return try_insert(pos, ilist.begin(), ilist.end());
524 [[nodiscard]]
bool try_push_back(
const value_type& value) {
525 return try_emplace_back(value);
528 [[nodiscard]]
bool try_push_back(value_type&& value) {
529 return try_emplace_back(std::move(value));
532 template <
typename... Args>
533 [[nodiscard]]
bool try_emplace_back(Args&&... args);
535 [[nodiscard]]
bool try_push_front(
const value_type& value) {
536 return try_emplace_front(value);
539 [[nodiscard]]
bool try_push_front(value_type&& value) {
540 return try_emplace_front(std::move(value));
543 template <
typename... Args>
544 [[nodiscard]]
bool try_emplace_front(Args&&... args);
546 [[nodiscard]]
bool try_resize(size_type new_size) {
547 return try_resize(new_size, value_type());
550 [[nodiscard]]
bool try_resize(size_type new_size,
const value_type& value);
552 template <
typename... Args>
553 [[nodiscard]] std::optional<iterator> try_emplace_shift_right(
554 const_iterator pos, Args&&... args);
556 [[nodiscard]] std::optional<iterator> try_insert_shift_right(
557 const_iterator pos, size_type count,
const value_type& value);
559 template <
typename ForwardIt,
560 typename = containers::internal::EnableIfForwardIterator<ForwardIt>>
561 [[nodiscard]] std::optional<iterator> try_insert_shift_right(
562 const_iterator pos, ForwardIt first, ForwardIt last);
565 constexpr Derived& derived() {
return static_cast<Derived&
>(*this); }
566 constexpr const Derived& derived()
const {
567 return static_cast<const Derived&
>(*this);
570 constexpr size_type head()
const {
return Base::head_; }
571 constexpr size_type tail()
const {
return Base::tail_; }
574 constexpr pointer data() {
return derived().data(); }
575 constexpr const_pointer data()
const {
return derived().data(); }
578 bool ShiftForInsert(size_type insert_index, size_type new_items);
581 void ShiftLeft(size_type insert_index, size_type new_items);
582 void ShiftRight(size_type insert_index, size_type new_items);
585 bool CheckCapacityAdd(size_type count) {
587 return CheckedAdd(
size(), count, new_size) && CheckCapacity(new_size);
591 constexpr bool CheckCapacity(size_type new_size) {
592 if constexpr (Derived::kFixedCapacity) {
595 return derived().try_reserve(new_size);
600 template <
typename... Args>
601 void EmplaceBackUnchecked(Args&&... args) {
602 new (&data()[tail()]) value_type(std::forward<Args>(args)...);
609template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
610template <
typename It,
int&...,
typename>
614 if constexpr (Derived::kFixedCapacity ||
616 typename std::iterator_traits<It>::iterator_category,
617 std::input_iterator_tag>) {
619 while (start != finish) {
624 PW_ASSERT(try_assign(start, finish));
628template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
630 size_type count,
const value_type& value) {
631 if (!CheckCapacity(count)) {
635 Base::PushBack(count);
636 std::uninitialized_fill_n(data(), count, value);
640template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
641template <
typename It,
int&...,
typename>
643 It start, It finish) {
645 static_assert(std::is_convertible_v<
646 typename std::iterator_traits<It>::iterator_category,
647 std::forward_iterator_tag>);
648 const auto items = std::distance(start, finish);
649 PW_DASSERT(items >= 0);
650 if (
static_cast<std::make_unsigned_t<decltype(items)
>>(items) >
651 std::numeric_limits<size_type>::max()) {
654 const size_type count =
static_cast<size_type
>(items);
655 if (!CheckCapacity(count)) {
660 Base::PushBack(count);
661 std::uninitialized_move(start, finish, data());
665template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
672 if (tail() > head()) {
686template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
687template <
typename... Args>
690 if (!CheckCapacityAdd(1)) {
693 EmplaceBackUnchecked(std::forward<Args>(args)...);
697template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
698void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_back() {
700 if constexpr (!std::is_trivially_destructible_v<value_type>) {
701 std::destroy_at(&back());
706template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
707template <
typename... Args>
708bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_emplace_front(
710 if (!CheckCapacityAdd(1)) {
714 new (&data()[head()]) value_type(std::forward<Args>(args)...);
718template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
719void GenericDeque<Derived, ValueType, CountAndCapacityType>::pop_front() {
721 if constexpr (!std::is_trivially_destructible_v<value_type>) {
722 std::destroy_at(&front());
727template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
728bool GenericDeque<Derived, ValueType, CountAndCapacityType>::try_resize(
729 size_type new_size,
const value_type& value) {
730 if (size() < new_size) {
731 if (!CheckCapacity(new_size)) {
734 const size_type new_items = new_size - size();
735 for (size_type i = 0; i < new_items; ++i) {
736 EmplaceBackUnchecked(value);
739 while (size() > new_size) {
746template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
747typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
749 const_iterator first, const_iterator last) {
750 PW_DASSERT(first <= last);
751 const iterator first_it(derived(), first.pos_);
752 const iterator last_it(derived(), last.pos_);
754 const size_type items_to_erase =
static_cast<size_type
>(last - first);
755 if (items_to_erase == 0) {
759 const size_type items_after =
static_cast<size_type
>(size() - last.pos_);
761 if (first.pos_ < items_after) {
762 std::move_backward(begin(), first_it, last_it);
763 if constexpr (!std::is_trivially_destructible_v<value_type>) {
764 std::destroy(begin(), begin() + items_to_erase);
766 Base::head_ = Base::AbsoluteIndex(items_to_erase);
768 std::move(last_it, end(), first_it);
769 if constexpr (!std::is_trivially_destructible_v<value_type>) {
770 std::destroy(first_it + items_after, end());
772 Base::tail_ = Base::AbsoluteIndex(first.pos_ + items_after);
774 Base::count_and_capacity().SetCount(size() - items_to_erase);
778template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
779template <
typename... Args>
781 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
783 const_iterator pos, Args&&... args) {
785 if (!ShiftForInsert(pos.pos_, 1)) {
788 iterator it(derived(), pos.pos_);
789 new (std::addressof(*it)) value_type(std::forward<Args>(args)...);
793template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
794bool GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftForInsert(
795 const size_type insert_index, size_type new_items) {
796 if (!CheckCapacityAdd(new_items)) {
800 if (insert_index < size() / 2) {
801 ShiftLeft(insert_index, new_items);
803 ShiftRight(insert_index, new_items);
808template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
809void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftLeft(
810 const size_type insert_index, size_type new_items) {
811 Base::PushFront(new_items);
812 iterator original_begin(derived(), new_items);
814 const size_type move_to_new_slots = std::min(new_items, insert_index);
815 auto [next_src, next_dst] =
816 std::uninitialized_move_n(original_begin, move_to_new_slots, begin());
818 const size_type move_to_existing_slots = insert_index - move_to_new_slots;
819 std::move(next_src, next_src + move_to_existing_slots, next_dst);
824 if constexpr (!std::is_trivially_destructible_v<value_type>) {
826 iterator(derived(), std::max(insert_index, original_begin.pos_)),
827 iterator(derived(), insert_index + new_items));
831template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
832void GenericDeque<Derived, ValueType, CountAndCapacityType>::ShiftRight(
833 const size_type insert_index, size_type new_items) {
834 const size_type items_after = size() - insert_index;
835 iterator original_end = end();
836 Base::PushBack(new_items);
838 const size_type move_to_new_slots = std::min(new_items, items_after);
839 std::uninitialized_move(original_end - move_to_new_slots,
841 end() - move_to_new_slots);
843 const size_type move_to_existing_slots = items_after - move_to_new_slots;
844 iterator pos(derived(), insert_index);
845 std::move_backward(pos, pos + move_to_existing_slots, original_end);
850 if constexpr (!std::is_trivially_destructible_v<value_type>) {
852 iterator(derived(), insert_index),
854 std::min(
static_cast<size_type
>(insert_index + new_items),
855 original_end.pos_)));
859template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
861 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
863 const_iterator pos, size_type count,
const value_type& value) {
865 return iterator(derived(), pos.pos_);
867 if (!ShiftForInsert(pos.pos_, count)) {
871 iterator it(derived(), pos.pos_);
872 std::uninitialized_fill_n(it, count, value);
876template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
877template <
typename InputIt,
typename>
878typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator
880 const_iterator pos, InputIt first, InputIt last) {
882 if constexpr (std::is_same_v<
883 typename std::iterator_traits<InputIt>::iterator_category,
884 std::input_iterator_tag>) {
887 iterator insert_pos = iterator(derived(), pos.pos_);
888 while (first != last) {
889 insert_pos = emplace(insert_pos, *first);
893 return iterator(derived(), pos.pos_);
895 std::optional<iterator> result = try_insert(pos, first, last);
896 PW_ASSERT(result.has_value());
901template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
902template <
typename ForwardIt,
typename>
904 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
906 const_iterator pos, ForwardIt first, ForwardIt last) {
907 static_assert(std::is_convertible_v<
908 typename std::iterator_traits<ForwardIt>::iterator_category,
909 std::forward_iterator_tag>);
910 const auto distance = std::distance(first, last);
911 PW_DASSERT(distance >= 0);
912 const size_type count =
static_cast<size_type
>(distance);
914 const iterator it(derived(), pos.pos_);
918 if (!ShiftForInsert(pos.pos_, count)) {
921 std::uninitialized_move(first, last, it);
925template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
926template <
typename... Args>
928 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
929GenericDeque<Derived, ValueType, CountAndCapacityType>::try_emplace_shift_right(
930 const_iterator pos, Args&&... args) {
931 if (!CheckCapacityAdd(1)) {
934 ShiftRight(pos.pos_, 1);
935 iterator it(derived(), pos.pos_);
936 new (std::addressof(*it)) value_type(std::forward<Args>(args)...);
940template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
942 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
943GenericDeque<Derived, ValueType, CountAndCapacityType>::try_insert_shift_right(
944 const_iterator pos, size_type count,
const value_type& value) {
946 return iterator(derived(), pos.pos_);
948 if (!CheckCapacityAdd(count)) {
952 ShiftRight(pos.pos_, count);
953 iterator it(derived(), pos.pos_);
954 std::uninitialized_fill_n(it, count, value);
958template <
typename Derived,
typename ValueType,
typename CountAndCapacityType>
959template <
typename ForwardIt,
typename>
961 typename GenericDeque<Derived, ValueType, CountAndCapacityType>::iterator>
962GenericDeque<Derived, ValueType, CountAndCapacityType>::try_insert_shift_right(
963 const_iterator pos, ForwardIt first, ForwardIt last) {
964 static_assert(std::is_convertible_v<
965 typename std::iterator_traits<ForwardIt>::iterator_category,
966 std::forward_iterator_tag>);
967 const auto distance = std::distance(first, last);
968 PW_DASSERT(distance >= 0);
969 const size_type count =
static_cast<size_type
>(distance);
971 const iterator it(derived(), pos.pos_);
975 if (!CheckCapacityAdd(count)) {
978 ShiftRight(pos.pos_, count);
979 std::uninitialized_move(first, last, it);
Definition: generic_deque.h:54
Definition: generic_deque.h:194
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:63
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:68
Definition: span_impl.h:235
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:63
iterator insert(const_iterator pos, size_type count, const value_type &value)
Definition: generic_deque.h:389
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:667
std::optional< iterator > try_insert(const_iterator pos, std::initializer_list< value_type > ilist)
Definition: generic_deque.h:519
bool try_assign(size_type count, const value_type &value)
Definition: generic_deque.h:629
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:237
iterator insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:369
void assign(It start, It finish)
Definition: generic_deque.h:611
iterator erase(const_iterator first, const_iterator last)
Definition: generic_deque.h:748
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
bool try_assign(const std::initializer_list< value_type > &list)
Definition: generic_deque.h:459
iterator emplace(const_iterator pos, Args &&... args)
Definition: generic_deque.h:359
iterator erase(const_iterator pos)
Erases the item at pos, which must be a dereferenceable iterator.
Definition: generic_deque.h:319
iterator insert(const_iterator pos, InputIt first, InputIt last)
Definition: generic_deque.h:879
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:68
std::optional< iterator > try_insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:479
std::optional< iterator > try_insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:489
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:225
iterator insert(const_iterator pos, value_type &&value)
Definition: generic_deque.h:379
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:408
constexpr bool CheckedAdd(A a, B b, T &result)
Definition: checked_arithmetic.h:70