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 : private containers::StorageBaseFor<T, kInlineCapacity>,
99 public Queue<T, SizeType> {
100 public:
103 constexpr FixedQueue()
104 : containers::StorageBaseFor<T, kInlineCapacity>{},
105 Queue<T, SizeType>(this->storage()) {}
106
107 FixedQueue(const FixedQueue&) = delete;
108 FixedQueue& operator=(const FixedQueue&) = delete;
109
110 constexpr FixedQueue(FixedQueue&& other) noexcept : FixedQueue() {
111 this->MoveItemsFrom(other);
112 }
113
114 constexpr FixedQueue& operator=(FixedQueue&& other) noexcept {
115 this->clear();
116 this->MoveItemsFrom(other);
117 return *this;
118 }
119
122 template <size_t kOtherCapacity,
123 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
124 FixedQueue(FixedQueue<T, kOtherCapacity>&& other) noexcept : FixedQueue() {
125 this->MoveItemsFrom(other);
126 }
127
128 template <size_t kOtherCapacity,
129 typename = std::enable_if_t<kOtherCapacity <= kInlineCapacity>>
130 FixedQueue& operator=(FixedQueue<T, kOtherCapacity>&& other) noexcept {
131 this->clear();
132 this->MoveItemsFrom(other);
133 return *this;
134 }
135
138 template <size_t kOtherCapacity>
140 this->SwapValuesWith(other);
141 }
142
144 constexpr Deallocator* deallocator() const { return nullptr; }
145};
146
150template <typename T, typename S>
151class FixedQueue<T, containers::kExternalStorage, S> final
152 : public Queue<T, S> {
153 public:
159 static FixedQueue Allocate(Allocator& allocator, const S capacity) {
160 FixedQueue queue = TryAllocate(allocator, capacity);
161 PW_ASSERT(queue.capacity() == capacity);
162 return queue;
163 }
164
171 static FixedQueue TryAllocate(Allocator& allocator, S capacity) {
172 const allocator::Layout layout = allocator::Layout::Of<T[]>(capacity);
173 std::byte* array = static_cast<std::byte*>(allocator.Allocate(layout));
174 if (array == nullptr) {
175 return FixedQueue(Aligned(array, 0u), nullptr);
176 }
177 return FixedQueue(Aligned(array, layout.size()), &allocator);
178 }
179
184 static FixedQueue WithStorage(UniquePtr<std::byte[]>&& storage) {
185 const size_t size = storage.size();
186 Deallocator* deallocator = storage.deallocator();
187 return FixedQueue(Aligned::Assert(storage.Release(), size), deallocator);
188 }
189
197 explicit constexpr FixedQueue(span<std::byte> unaligned_buffer) noexcept
198 : Queue<T, S>(unaligned_buffer), deallocator_(nullptr) {}
199
204 template <size_t kAlignment, size_t kSizeBytes>
205 explicit constexpr FixedQueue(
207 : Queue<T, S>(buffer), deallocator_(nullptr) {}
208
210 FixedQueue(const FixedQueue&) = delete;
211 FixedQueue& operator=(const FixedQueue&) = delete;
212
217 constexpr FixedQueue(FixedQueue&& other) noexcept
218 : Queue<T, S>({}),
219 deallocator_(cpp20::exchange(other.deallocator_, nullptr)) {
220 this->MoveBufferFrom(other);
221 }
222
223 constexpr FixedQueue& operator=(FixedQueue&& other) noexcept {
224 if (this == &other) {
225 return *this;
226 }
227 T* const data = this->data();
228 this->MoveBufferFrom(other);
229
230 if (deallocator_ != nullptr) {
231 deallocator_->Deallocate(data);
232 }
233 deallocator_ = cpp20::exchange(other.deallocator_, nullptr);
234 return *this;
235 }
236
237 ~FixedQueue() {
238 // Clear the queue so that the base `Queue` destructor will not need to
239 // access its buffer, which will be freed.
240 this->clear();
241 if (deallocator_ != nullptr) {
242 deallocator_->Deallocate(this->data());
243 }
244 }
245
248 void swap(FixedQueue& other) noexcept {
249 this->SwapBufferWith(other);
250 std::swap(deallocator_, other.deallocator_);
251 }
252
257 template <size_t kInlineCapacity>
259 other.swap(*this); // Use the swap impl for statically allocated queues.
260 }
261
264 constexpr Deallocator* deallocator() const { return deallocator_; }
265
266 private:
267 using Aligned = typename Queue<T, S>::Aligned;
268
269 constexpr FixedQueue(Aligned buffer, Deallocator* deallocator)
270 : Queue<T, S>(buffer), deallocator_(deallocator) {}
271
272 Deallocator* deallocator_;
273};
274
275} // 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:99
Definition: queue.h:38
Definition: unique_ptr.h:43
Definition: layout.h:58
Definition: storage.h:86
Definition: storage.h:39
Definition: generic_queue.h:25
Definition: span_impl.h:235
MoveItemsFrom(other)
constexpr FixedQueue(span< std::byte > unaligned_buffer) noexcept
Definition: queue.h:197
constexpr FixedQueue(containers::Storage< kAlignment, kSizeBytes > &buffer) noexcept
Definition: queue.h:205
constexpr FixedQueue()
Definition: queue.h:103
void swap(FixedQueue< T, kInlineCapacity, S > &other)
Definition: queue.h:258
FixedQueue(const FixedQueue &)=delete
Copying is not supported since it can fail.
static FixedQueue WithStorage(UniquePtr< std::byte[]> &&storage)
Definition: queue.h:184
static FixedQueue TryAllocate(Allocator &allocator, S capacity)
Definition: queue.h:171
void swap(FixedQueue &other) noexcept
Definition: queue.h:248
constexpr Deallocator * deallocator() const
Definition: queue.h:264
constexpr FixedQueue(FixedQueue &&other) noexcept
Definition: queue.h:217
constexpr Queue(containers::Storage< kAlignment, kSizeBytes > &storage) noexcept
Definition: queue.h:52
void swap(FixedQueue< T, kOtherCapacity, SizeType > &other)
Definition: queue.h:139
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:144
static FixedQueue Allocate(Allocator &allocator, const S capacity)
Definition: queue.h:159
constexpr size_t kExternalStorage
Reserved capacity value for container specializations with external storage.
Definition: storage.h:79
The Pigweed namespace.
Definition: alignment.h:27