C/C++ API Reference
Loading...
Searching...
No Matches
queue.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <utility>
17
18#include "pw_allocator/allocator.h"
19#include "pw_allocator/unique_ptr.h"
20#include "pw_containers/deque.h"
21#include "pw_containers/internal/generic_queue.h"
22#include "pw_containers/storage.h"
23
24namespace pw {
25
27
36template <typename T, typename SizeType = uint16_t>
37class Queue : public containers::internal::GenericQueue<Queue<T, SizeType>,
38 Deque<T, SizeType>> {
39 public:
46 explicit constexpr Queue(span<std::byte> unaligned_buffer) noexcept
47 : Queue(Aligned::Align(unaligned_buffer)) {}
48
51 template <size_t kAlignment, size_t kSizeBytes>
52 explicit constexpr Queue(
54 : deque_(storage) {}
55
56 // Disable copy and move since the queue does not own the buffer.
57 Queue(const Queue&) = delete;
58 Queue& operator=(const Queue&) = delete;
59
60 Queue(Queue&&) = delete;
61 Queue& operator=(Queue&&) = delete;
62
63 private:
64 template <typename, typename>
66
67 template <typename, size_t, typename>
68 friend class FixedQueue;
69
70 using Aligned = typename Deque<T, SizeType>::Aligned;
71
72 // Constructor for a buffer that is known to be aligned.
73 explicit constexpr Queue(Aligned buffer) noexcept : deque_(buffer) {}
74
75 void MoveItemsFrom(Queue& other) { deque_.MoveItemsFrom(other.deque_); }
76 void MoveBufferFrom(Queue& other) { deque_.MoveBufferFrom(other.deque_); }
77 void SwapValuesWith(Queue& other) { deque_.SwapValuesWith(other.deque_); }
78 void SwapBufferWith(Queue& other) { deque_.SwapBufferWith(other.deque_); }
79
80 T* data() { return deque_.data(); }
81
82 Deque<T, SizeType>& deque() { return deque_; }
83 const Deque<T, SizeType>& deque() const { return deque_; }
84
85 Deque<T, SizeType> deque_;
86};
87
95template <typename T,
96 size_t kInlineCapacity = containers::kExternalStorage,
97 typename SizeType = typename Queue<T>::size_type>
98class FixedQueue final
99 : private containers::internal::ArrayStorage<T, kInlineCapacity>,
100 public Queue<T, SizeType> {
101 public:
104 constexpr FixedQueue()
105 : containers::internal::ArrayStorage<T, kInlineCapacity>{},
106 Queue<T, SizeType>(this->storage_array) {}
107
108 FixedQueue(const FixedQueue&) = delete;
109 FixedQueue& operator=(const FixedQueue&) = delete;
110
111 constexpr FixedQueue(FixedQueue&& other) noexcept : FixedQueue() {
112 this->MoveItemsFrom(other);
113 }
114
115 constexpr FixedQueue& operator=(FixedQueue&& other) noexcept {
116 this->clear();
117 this->MoveItemsFrom(other);
118 return *this;
119 }
120
123 template <size_t kOtherCapacity,
124 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
125 FixedQueue(FixedQueue<T, kOtherCapacity>&& other) noexcept : FixedQueue() {
126 this->MoveItemsFrom(other);
127 }
128
129 template <size_t kOtherCapacity,
130 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
131 FixedQueue& operator=(FixedQueue<T, kOtherCapacity>&& other) noexcept {
132 this->clear();
133 this->MoveItemsFrom(other);
134 return *this;
135 }
136
139 template <size_t kOtherCapacity>
141 this->SwapValuesWith(other);
142 }
143
145 constexpr Deallocator* deallocator() const { return nullptr; }
146};
147
151template <typename T, typename S>
152class FixedQueue<T, containers::kExternalStorage, S> final
153 : public Queue<T, S> {
154 public:
160 static FixedQueue Allocate(Allocator& allocator, const S capacity) {
161 FixedQueue queue = TryAllocate(allocator, capacity);
162 PW_ASSERT(queue.capacity() == capacity);
163 return queue;
164 }
165
172 static FixedQueue TryAllocate(Allocator& allocator, S capacity) {
173 const allocator::Layout layout = allocator::Layout::Of<T[]>(capacity);
174 std::byte* array = static_cast<std::byte*>(allocator.Allocate(layout));
175 if (array == nullptr) {
176 return FixedQueue(Aligned(array, 0u), nullptr);
177 }
178 return FixedQueue(Aligned(array, layout.size()), &allocator);
179 }
180
185 static FixedQueue WithStorage(UniquePtr<std::byte[]>&& storage) {
186 const size_t size = storage.size();
187 Deallocator* deallocator = storage.deallocator();
188 return FixedQueue(Aligned::Assert(storage.Release(), size), deallocator);
189 }
190
198 explicit constexpr FixedQueue(span<std::byte> unaligned_buffer) noexcept
199 : Queue<T, S>(unaligned_buffer), deallocator_(nullptr) {}
200
205 template <size_t kAlignment, size_t kSizeBytes>
206 explicit constexpr FixedQueue(
208 : Queue<T, S>(buffer), deallocator_(nullptr) {}
209
211 FixedQueue(const FixedQueue&) = delete;
212 FixedQueue& operator=(const FixedQueue&) = delete;
213
218 constexpr FixedQueue(FixedQueue&& other) noexcept
219 : Queue<T, S>({}),
220 deallocator_(cpp20::exchange(other.deallocator_, nullptr)) {
221 this->MoveBufferFrom(other);
222 }
223
224 constexpr FixedQueue& operator=(FixedQueue&& other) noexcept {
225 if (this == &other) {
226 return *this;
227 }
228 T* const data = this->data();
229 this->MoveBufferFrom(other);
230
231 if (deallocator_ != nullptr) {
232 deallocator_->Deallocate(data);
233 }
234 deallocator_ = cpp20::exchange(other.deallocator_, nullptr);
235 return *this;
236 }
237
238 ~FixedQueue() {
239 // Clear the queue so that the base `Queue` destructor will not need to
240 // access its buffer, which will be freed.
241 this->clear();
242 if (deallocator_ != nullptr) {
243 deallocator_->Deallocate(this->data());
244 }
245 }
246
249 void swap(FixedQueue& other) noexcept {
250 this->SwapBufferWith(other);
251 std::swap(deallocator_, other.deallocator_);
252 }
253
258 template <size_t kInlineCapacity>
260 other.swap(*this); // Use the swap impl for statically allocated queues.
261 }
262
265 constexpr Deallocator* deallocator() const { return deallocator_; }
266
267 private:
268 using Aligned = typename Queue<T, S>::Aligned;
269
270 constexpr FixedQueue(Aligned buffer, Deallocator* deallocator)
271 : Queue<T, S>(buffer), deallocator_(deallocator) {}
272
273 Deallocator* deallocator_;
274};
275
276} // namespace pw
Definition: allocator.h:36
void * Allocate(Layout layout)
Definition: allocator.h:44
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: deque.h:60
Definition: queue.h:100
Definition: queue.h:38
Definition: unique_ptr.h:43
Definition: layout.h:58
Definition: storage.h:36
Definition: generic_queue.h:25
Definition: span_impl.h:235
MoveItemsFrom(other)
constexpr FixedQueue(span< std::byte > unaligned_buffer) noexcept
Definition: queue.h:198
constexpr FixedQueue(containers::Storage< kAlignment, kSizeBytes > &buffer) noexcept
Definition: queue.h:206
constexpr FixedQueue()
Definition: queue.h:104
void swap(FixedQueue< T, kInlineCapacity, S > &other)
Definition: queue.h:259
FixedQueue(const FixedQueue &)=delete
Copying is not supported since it can fail.
static FixedQueue WithStorage(UniquePtr< std::byte[]> &&storage)
Definition: queue.h:185
static FixedQueue TryAllocate(Allocator &allocator, S capacity)
Definition: queue.h:172
void swap(FixedQueue &other) noexcept
Definition: queue.h:249
constexpr Deallocator * deallocator() const
Definition: queue.h:265
constexpr FixedQueue(FixedQueue &&other) noexcept
Definition: queue.h:218
constexpr Queue(containers::Storage< kAlignment, kSizeBytes > &storage) noexcept
Definition: queue.h:52
void swap(FixedQueue< T, kOtherCapacity, SizeType > &other)
Definition: queue.h:140
constexpr Queue(span< std::byte > unaligned_buffer) noexcept
Definition: queue.h:46
constexpr Deallocator * deallocator() const
Returns nullptr; a FixedQueue with static storage never allocates.
Definition: queue.h:145
static FixedQueue Allocate(Allocator &allocator, const S capacity)
Definition: queue.h:160
constexpr size_t kExternalStorage
Reserved capacity value for container specializations with external storage.
Definition: storage.h:76
The Pigweed namespace.
Definition: alignment.h:27