24#include "lib/stdcompat/utility.h"
25#include "pw_allocator/allocator.h"
26#include "pw_allocator/unique_ptr.h"
27#include "pw_assert/assert.h"
28#include "pw_containers/internal/count_and_capacity.h"
29#include "pw_containers/internal/generic_deque.h"
30#include "pw_containers/storage.h"
31#include "pw_polyfill/language_feature_macros.h"
32#include "pw_span/span.h"
56template <
typename T,
typename SizeType = u
int16_t>
60 containers::internal::CountAndCapacity<SizeType>> {
65 containers::internal::CountAndCapacity<SizeType>>;
68 using typename Base::const_iterator;
69 using typename Base::const_pointer;
70 using typename Base::const_reference;
71 using typename Base::difference_type;
72 using typename Base::iterator;
73 using typename Base::pointer;
74 using typename Base::reference;
75 using typename Base::size_type;
76 using typename Base::value_type;
85 :
Deque(Aligned::Align(unaligned_buffer)) {}
89 template <
size_t kAlignment,
size_t kSizeBytes>
92 :
Deque(Aligned(buffer.data(), buffer.size())) {
93 static_assert(kAlignment >=
alignof(value_type));
106 constexpr size_type max_size() const noexcept {
return Base::capacity(); }
111 template <
typename,
typename>
114 template <
typename,
size_t,
typename>
115 friend class FixedDeque;
117 static constexpr bool kFixedCapacity =
true;
123 static constexpr Aligned Align(span<std::byte> unaligned_buffer) {
124 Aligned buffer(unaligned_buffer.data(), unaligned_buffer.size());
126 if constexpr (
alignof(value_type) >
alignof(std::byte)) {
127 void* data_void = buffer.data_;
128 buffer.data_ =
static_cast<std::byte*
>(std::align(
129 alignof(value_type),
sizeof(value_type), data_void, buffer.size_));
130 if (buffer.data_ ==
nullptr) {
139 static constexpr Aligned Assert(std::byte* data,
size_t size) {
140 void* buffer_start = data;
141 PW_ASSERT(
reinterpret_cast<uintptr_t
>(buffer_start) %
alignof(T) == 0);
142 return Aligned(data,
size);
145 constexpr Aligned(std::byte* aligned_data,
size_t size_bytes)
146 : data_(aligned_data), size_(size_bytes) {}
148 constexpr std::byte* data()
const {
return data_; }
149 constexpr size_t capacity()
const {
return size_ /
sizeof(value_type); }
156 explicit constexpr Deque(Aligned buffer) noexcept
157 : Base(
static_cast<size_type
>(buffer.capacity())),
158 buffer_(buffer.data()) {}
160 constexpr void MoveBufferFrom(Deque& other)
noexcept {
162 buffer_ = cpp20::exchange(other.buffer_,
nullptr);
163 Base::MoveAssignIndices(other);
166 void MoveItemsFrom(Deque& other) {
167 this->
assign(std::make_move_iterator(other.begin()),
168 std::make_move_iterator(other.end()));
172 void SwapBufferWith(Deque& other)
noexcept {
173 Base::SwapIndices(other);
174 std::swap(buffer_, other.buffer_);
177 void SwapValuesWith(Deque& other);
179 pointer data() {
return std::launder(
reinterpret_cast<pointer
>(buffer_)); }
180 const_pointer data()
const {
181 return std::launder(
reinterpret_cast<const_pointer
>(buffer_));
205 typename S =
typename Deque<T>::size_type>
213 : containers::internal::ArrayStorage<T, kInlineCapacity>{},
231 template <
size_t kOtherCapacity,
232 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
237 template <
size_t kOtherCapacity,
238 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
247 template <
size_t kOtherCapacity>
249 this->SwapValuesWith(other);
257 kInlineCapacity <= std::numeric_limits<S>::max(),
258 "The capacity is too large for the size_type; use a larger size_type");
269template <
typename T,
typename S>
271 :
public Deque<T, S> {
292 std::byte* array =
static_cast<std::byte*
>(allocator.
Allocate(layout));
293 if (array ==
nullptr) {
294 return FixedDeque(Aligned(array, 0u),
nullptr);
296 return FixedDeque(Aligned(array, layout.size()), &allocator);
304 const size_t size = storage.size();
317 :
Deque<T, S>(unaligned_buffer), deallocator_(
nullptr) {}
323 template <
size_t kAlignment,
size_t kSizeBytes>
338 deallocator_(cpp20::exchange(other.deallocator_,
nullptr)) {
339 this->MoveBufferFrom(other);
343 if (
this == &other) {
346 T*
const data = this->data();
347 this->MoveBufferFrom(other);
349 if (deallocator_ !=
nullptr) {
350 deallocator_->Deallocate(data);
352 deallocator_ = cpp20::exchange(other.deallocator_,
nullptr);
360 if (deallocator_ !=
nullptr) {
361 deallocator_->Deallocate(this->data());
368 this->SwapBufferWith(other);
369 std::swap(deallocator_, other.deallocator_);
376 template <
size_t kInlineCapacity>
391 Deallocator* deallocator_;
394template <
typename T,
typename SizeType>
395void Deque<T, SizeType>::SwapValuesWith(Deque& other) {
399 if (this->size() < other.size()) {
407 const SizeType smaller_size = smaller->size();
409 std::swap_ranges(smaller->begin(), smaller->end(), larger->begin());
412 smaller->push_back(std::move(*it));
415 while (larger->size() > smaller_size) {
Definition: allocator.h:36
void * Allocate(Layout layout)
Definition: allocator.h:44
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: unique_ptr.h:43
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 FixedDeque()
Definition: deque.h:212
FixedDeque(const FixedDeque &)=delete
Copying is not supported since it can fail.
void swap(FixedDeque< T, kOtherCapacity, S > &other)
Definition: deque.h:248
constexpr Deallocator * deallocator() const
Definition: deque.h:383
Deque(const Deque &)=delete
Copying is not supported since it can fail.
constexpr Deallocator * deallocator() const
Returns nullptr; a FixedDeque with static storage never allocates.
Definition: deque.h:253
constexpr Deque(span< std::byte > unaligned_buffer) noexcept
Definition: deque.h:84
static FixedDeque Allocate(Allocator &allocator, const S capacity)
Definition: deque.h:278
constexpr FixedDeque(FixedDeque &&other) noexcept
Definition: deque.h:336
constexpr Deque(containers::Storage< kAlignment, kSizeBytes > &buffer) noexcept
Definition: deque.h:90
static FixedDeque WithStorage(UniquePtr< std::byte[]> &&storage)
Definition: deque.h:303
constexpr FixedDeque(containers::Storage< kAlignment, kSizeBytes > &buffer) noexcept
Definition: deque.h:324
Deque(Deque &&)=delete
Move is not supported to avoid confusion about deque/buffer pairings.
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
void swap(FixedDeque< T, kInlineCapacity, S > &other)
Definition: deque.h:377
static FixedDeque TryAllocate(Allocator &allocator, S capacity)
Definition: deque.h:290
void swap(FixedDeque &other) noexcept
Definition: deque.h:367
constexpr FixedDeque(span< std::byte > unaligned_buffer) noexcept
Definition: deque.h:316
constexpr size_t kExternalStorage
Reserved capacity value for container specializations with external storage.
Definition: storage.h:76
#define PW_CONSTEXPR_CPP20
Definition: language_feature_macros.h:27
The Pigweed namespace.
Definition: alignment.h:27