18#include <initializer_list>
24#include "pw_allocator/allocator.h"
25#include "pw_assert/assert.h"
26#include "pw_containers/internal/generic_deque.h"
27#include "pw_numeric/saturating_arithmetic.h"
65template <
typename ValueType,
typename SizeType = u
int16_t>
67 :
public containers::internal::
68 GenericDeque<DynamicDeque<ValueType, SizeType>, ValueType, SizeType> {
70 using Base = containers::internal::
71 GenericDeque<DynamicDeque<ValueType, SizeType>, ValueType, SizeType>;
74 using typename Base::const_iterator;
75 using typename Base::const_pointer;
76 using typename Base::const_reference;
77 using typename Base::difference_type;
78 using typename Base::iterator;
79 using typename Base::pointer;
80 using typename Base::reference;
81 using typename Base::size_type;
82 using typename Base::value_type;
91 :
Base(0), allocator_(&allocator), buffer_(
nullptr) {}
100 :
Base(0), allocator_(other.allocator_), buffer_(other.buffer_) {
101 other.buffer_ =
nullptr;
102 Base::MoveAssignIndices(other);
112 using Base::try_emplace_back;
113 using Base::try_emplace_front;
115 using Base::try_push_back;
116 using Base::try_push_front;
117 using Base::try_resize;
122 template <
typename InputIt,
123 typename = containers::internal::EnableIfInputIterator<InputIt>>
124 iterator insert(const_iterator pos, InputIt first, InputIt last);
126 iterator insert(const_iterator pos,
const value_type& value) {
130 iterator insert(const_iterator pos, value_type&& value) {
134 iterator insert(const_iterator pos,
136 const value_type& value) {
140 iterator insert(const_iterator pos, std::initializer_list<value_type> ilist) {
169 return new_capacity <=
Base::capacity() || IncreaseCapacity(new_capacity);
195 constexpr size_type max_size() const noexcept {
196 return std::numeric_limits<size_type>::max();
204 Base::SwapIndices(other);
205 std::swap(allocator_, other.allocator_);
206 std::swap(buffer_, other.buffer_);
212 template <
typename,
typename>
215 static constexpr bool kFixedCapacity =
false;
220 pointer data() {
return std::launder(
reinterpret_cast<pointer
>(buffer_)); }
221 const_pointer data()
const {
222 return std::launder(
reinterpret_cast<const_pointer
>(buffer_));
225 [[nodiscard]]
bool IncreaseCapacity(size_type new_capacity);
227 size_type GetNewCapacity(
const size_type new_size) {
230 return std::max(size_type{4 *
sizeof(
void*) /
sizeof(value_type)},
237 bool ReallocateBuffer(size_type new_capacity);
239 void DeallocateBuffer() {
242 Base::HandleShrunkBuffer(0);
245 Allocator* allocator_;
249template <
typename ValueType,
typename SizeType>
250DynamicDeque<ValueType, SizeType>& DynamicDeque<ValueType, SizeType>::operator=(
251 DynamicDeque&& other)
noexcept {
253 allocator_->Deallocate(buffer_);
255 allocator_ = other.allocator_;
256 buffer_ = std::exchange(other.buffer_,
nullptr);
258 Base::MoveAssignIndices(other);
262template <
typename ValueType,
typename SizeType>
263DynamicDeque<ValueType, SizeType>::~DynamicDeque() {
265 allocator_->Deallocate(buffer_);
268template <
typename ValueType,
typename SizeType>
270 return new_capacity <= Base::capacity() ||
271 IncreaseCapacity(GetNewCapacity(new_capacity)) ||
272 IncreaseCapacity(new_capacity);
275template <
typename ValueType,
typename SizeType>
277 size_type new_capacity) {
279 if (buffer_ !=
nullptr && Base::CanExtendBuffer() &&
280 allocator_->Resize(buffer_, new_capacity *
sizeof(value_type))) {
281 Base::HandleExtendedBuffer(new_capacity);
286 return ReallocateBuffer(new_capacity);
289template <
typename ValueType,
typename SizeType>
291 if (Base::size() == Base::capacity()) {
304 if (Base::CanShrinkBuffer() &&
305 allocator_->Resize(buffer_, Base::size() *
sizeof(value_type))) {
306 Base::HandleShrunkBuffer(Base::size());
309 ReallocateBuffer(Base::size());
313template <
typename ValueType,
typename SizeType>
315 size_type new_capacity) {
316 std::byte* new_buffer =
static_cast<std::byte*
>(
317 allocator_->Allocate(allocator::Layout::Of<value_type[]>(new_capacity)));
318 if (new_buffer ==
nullptr) {
322 pointer dest = std::launder(
reinterpret_cast<pointer
>(new_buffer));
323 auto [data_1, data_2] = Base::contiguous_data();
325 if constexpr (std::is_move_constructible_v<value_type>) {
326 dest = std::uninitialized_move(data_1.begin(), data_1.end(), dest);
327 std::uninitialized_move(data_2.begin(), data_2.end(), dest);
329 dest = std::uninitialized_copy(data_1.begin(), data_1.end(), dest);
330 std::uninitialized_copy(data_2.begin(), data_2.end(), dest);
333 std::destroy(data_1.begin(), data_1.end());
334 std::destroy(data_2.begin(), data_2.end());
336 allocator_->Deallocate(buffer_);
337 buffer_ = new_buffer;
339 Base::HandleNewBuffer(new_capacity);
343template <
typename ValueType,
typename SizeType>
344template <
typename InputIt,
typename>
345typename DynamicDeque<ValueType, SizeType>::iterator
346DynamicDeque<ValueType, SizeType>::insert(const_iterator pos,
350 if constexpr (std::is_same_v<std::input_iterator_tag,
351 typename std::iterator_traits<
352 InputIt>::iterator_category>) {
356 DynamicDeque temp(*allocator_);
357 temp.assign(first, last);
358 return Base::insert(pos,
359 std::make_move_iterator(temp.data()),
360 std::make_move_iterator(temp.data() + temp.size()));
362 return Base::insert(pos, first, last);
Definition: allocator.h:42
Definition: dynamic_deque.h:68
Definition: dynamic_vector.h:63
Definition: generic_deque.h:178
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:72
void Deallocate(void *ptr)
Definition: deallocator.h:59
iterator insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:351
void reserve(size_type new_capacity)
Increases capacity() to at least new_capacity. Crashes on failure.
Definition: dynamic_deque.h:157
std::optional< iterator > try_insert(const_iterator pos, const value_type &value)
Definition: generic_deque.h:469
bool try_assign(size_type count, const value_type &value)
Definition: generic_deque.h:618
void reserve_exact(size_type new_capacity)
Increases capacity() to exactly new_capacity. Crashes on failure.
Definition: dynamic_deque.h:173
constexpr DynamicDeque(DynamicDeque &&other) noexcept
Definition: dynamic_deque.h:99
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
void swap(DynamicDeque &other) noexcept
Swaps the contents of two deques. No allocations occur.
Definition: dynamic_deque.h:203
bool try_reserve(size_type new_capacity)
Definition: dynamic_deque.h:269
void shrink_to_fit()
Definition: dynamic_deque.h:290
constexpr allocator_type & get_allocator() const
Returns the deque's allocator.
Definition: dynamic_deque.h:200
void reset()
Clears the deque and deallocates its buffer.
Definition: dynamic_deque.h:190
bool try_reserve_exact(size_type new_capacity)
Definition: dynamic_deque.h:168
constexpr DynamicDeque(Allocator &allocator) noexcept
Definition: dynamic_deque.h:90
constexpr T mul_sat(T lhs, T rhs) noexcept
Definition: saturating_arithmetic.h:75
The Pigweed namespace.
Definition: alignment.h:27