• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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 <stdbool.h>
17 #include <stddef.h>
18 #include <stdint.h>
19 
20 #include "pw_preprocessor/util.h"
21 #include "pw_varint/varint.h"
22 
23 /// @file pw_containers/inline_var_len_entry_queue.h
24 ///
25 /// A `InlineVarLenEntryQueue` is a queue of inline variable-length binary
26 /// entries. It is implemented as a ring (circular) buffer and supports
27 /// operations to append entries and overwrite if necessary. Entries may be zero
28 /// bytes up to the maximum size supported by the queue.
29 ///
30 /// The `InlineVarLenEntryQueue` has a few interesting properties.
31 ///
32 /// - Data and metadata are stored inline in a contiguous block of
33 ///   `uint32_t`-aligned memory.
34 /// - The data structure is trivially copyable.
35 /// - All state changes are accomplished with a single update to a `uint32_t`.
36 ///   The memory is always in a valid state and may be parsed offline.
37 ///
38 /// This data structure is a much simpler version of
39 /// @cpp_class{pw::ring_buffer::PrefixedEntryRingBuffer}. Prefer this
40 /// sized-entry ring buffer to `PrefixedEntryRingBuffer` when:
41 /// - A simple ring buffer of variable-length entries is needed. Advanced
42 ///   features like multiple readers and a user-defined preamble are not
43 ///   required.
44 /// - A consistent, parsable, in-memory representation is required (e.g. to
45 ///   decode the buffer from a block of memory).
46 /// - C support is required.
47 ///
48 /// `InlineVarLenEntryQueue` is implemented in C and provides complete C and C++
49 /// APIs. The `InlineVarLenEntryQueue` C++ class is structured similarly to
50 /// `pw::InlineQueue` and `pw::Vector`.
51 
52 #ifdef __cplusplus
53 extern "C" {
54 #endif  // __cplusplus
55 
56 /// @defgroup inline_var_len_entry_queue_c_api InlineVarLenEntryQueue C API
57 /// @{
58 
59 /// Handle that refers to a `InlineVarLenEntryQueue`. In memory, the queue is a
60 /// `uint32_t` array.
61 typedef uint32_t* pw_InlineVarLenEntryQueue_Handle;
62 typedef const uint32_t* pw_InlineVarLenEntryQueue_ConstHandle;
63 
64 /// Declares and initializes a `InlineVarLenEntryQueue` that can hold up to
65 /// `max_size_bytes` bytes. `max_size_bytes` is the largest supported size for a
66 /// single entry; attempting to store larger entries is invalid and will fail an
67 /// assertion.
68 ///
69 /// @param variable variable name for the queue
70 /// @param max_size_bytes the capacity of the queue
71 #define PW_VARIABLE_LENGTH_ENTRY_QUEUE_DECLARE(variable, max_size_bytes) \
72   uint32_t variable[PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 +  \
73                     _PW_VAR_QUEUE_DATA_SIZE_UINT32(max_size_bytes)] = {  \
74       _PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes), /*head=*/0u, /*tail=*/0u}
75 
76 /// The size of the `InlineVarLenEntryQueue` header, in `uint32_t` elements.
77 /// This header stores the buffer length and head and tail offsets.
78 ///
79 /// The underlying `uint32_t` array of a `InlineVarLenEntryQueue` must be larger
80 /// than this size.
81 #define PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 (3)
82 
83 /// Initializes a `InlineVarLenEntryQueue` in place in a `uint32_t` array. The
84 /// array MUST be larger than
85 /// @c_macro{PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32} (3) elements.
86 static inline void pw_InlineVarLenEntryQueue_Init(uint32_t array[],
87                                                   size_t array_size_uint32);
88 
89 /// Empties the queue.
90 static inline void pw_InlineVarLenEntryQueue_Clear(
91     pw_InlineVarLenEntryQueue_Handle queue);
92 
93 /// Appends an entry to the end of the queue.
94 ///
95 /// @pre The entry MUST NOT be larger than `max_size_bytes()`.
96 /// @pre There must be sufficient space in the queue for this entry.
97 void pw_InlineVarLenEntryQueue_Push(pw_InlineVarLenEntryQueue_Handle queue,
98                                     const void* data,
99                                     uint32_t data_size_bytes);
100 
101 /// Appends an entry to the end of the queue, but only if there is sufficient
102 /// space for it.
103 ///
104 /// @returns true if the data was added to the queue; false if it did not fit
105 /// @pre The entry MUST NOT be larger than `max_size_bytes()`.
106 bool pw_InlineVarLenEntryQueue_TryPush(pw_InlineVarLenEntryQueue_Handle queue,
107                                        const void* data,
108                                        const uint32_t data_size_bytes);
109 
110 /// Appends an entry to the end of the queue, removing entries with `Pop`
111 /// as necessary to make room. Calling this function drops old entries to make
112 /// room for new; call `try_push()` to drop new entries instead.
113 ///
114 /// @pre The entry MUST NOT be larger than `max_size_bytes()`.
115 void pw_InlineVarLenEntryQueue_PushOverwrite(
116     pw_InlineVarLenEntryQueue_Handle queue,
117     const void* data,
118     uint32_t data_size_bytes);
119 
120 /// Removes the first entry from queue.
121 ///
122 /// @pre The queue MUST have at least one entry.
123 void pw_InlineVarLenEntryQueue_Pop(pw_InlineVarLenEntryQueue_Handle queue);
124 
125 /// Iterator object for a `InlineVarLenEntryQueue`. Iterators are checked for
126 /// equality with @cpp_func{pw_InlineVarLenEntryQueue_Iterator_Equal}.
127 ///
128 /// Iterators are invalidated by any operations that change the container or
129 /// its underlying data (push/pop/init).
130 typedef struct {
131   // Private: do not access these fields directly!
132   pw_InlineVarLenEntryQueue_ConstHandle _pw_queue;
133   uint32_t _pw_offset;
134 } pw_InlineVarLenEntryQueue_Iterator;
135 
136 /// An entry in the queue. Entries may be stored in up to two segments, so this
137 /// struct includes pointers to both portions of the entry.
138 typedef struct {
139   const uint8_t* data_1;
140   uint32_t size_1;
141   const uint8_t* data_2;
142   uint32_t size_2;
143 } pw_InlineVarLenEntryQueue_Entry;
144 
145 /// Returns an iterator to the start of the `InlineVarLenEntryQueue`.
146 static inline pw_InlineVarLenEntryQueue_Iterator
147 pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue);
148 
149 /// Returns an iterator that points past the end of the queue.
150 static inline pw_InlineVarLenEntryQueue_Iterator pw_InlineVarLenEntryQueue_End(
151     pw_InlineVarLenEntryQueue_ConstHandle queue);
152 
153 /// Advances an iterator to point to the next entry in the queue. It is
154 /// invalid to call `Advance` on an iterator equal to the `End` iterator.
155 void pw_InlineVarLenEntryQueue_Iterator_Advance(
156     pw_InlineVarLenEntryQueue_Iterator* iterator);
157 
158 /// Compares two iterators for equality.
159 static inline bool pw_InlineVarLenEntryQueue_Iterator_Equal(
160     const pw_InlineVarLenEntryQueue_Iterator* lhs,
161     const pw_InlineVarLenEntryQueue_Iterator* rhs);
162 
163 /// Dereferences an iterator, loading the entry it points to.
164 pw_InlineVarLenEntryQueue_Entry pw_InlineVarLenEntryQueue_GetEntry(
165     const pw_InlineVarLenEntryQueue_Iterator* iterator);
166 
167 /// Copies the contents of the entry to the provided buffer. The entry may be
168 /// split into two regions; this serializes it into one buffer.
169 ///
170 /// @param entry The entry whose contents to copy
171 /// @param dest The buffer into which to copy the serialized entry
172 /// @param count Copy up to this many bytes; must not be larger than the `dest`
173 ///     buffer, but may be larger than the entry
174 uint32_t pw_InlineVarLenEntryQueue_Entry_Copy(
175     const pw_InlineVarLenEntryQueue_Entry* entry, void* dest, uint32_t count);
176 
177 /// Returns the byte at the specified index in the entry. Asserts if index is
178 /// out-of-bounds.
179 static inline uint8_t pw_InlineVarLenEntryQueue_Entry_At(
180     const pw_InlineVarLenEntryQueue_Entry* entry, size_t index);
181 
182 /// Returns the number of variable-length entries in the queue. This is O(n) in
183 /// the number of entries in the queue.
184 uint32_t pw_InlineVarLenEntryQueue_Size(
185     pw_InlineVarLenEntryQueue_ConstHandle queue);
186 
187 /// Returns the maximum number of entries in the queue. This is only attainable
188 /// if all entries are empty.
189 static inline uint32_t pw_InlineVarLenEntryQueue_MaxSize(
190     pw_InlineVarLenEntryQueue_ConstHandle queue);
191 
192 /// Returns the combined size in bytes of all entries in the queue, excluding
193 /// metadata. This is O(n) in the number of entries in the queue.
194 uint32_t pw_InlineVarLenEntryQueue_SizeBytes(
195     pw_InlineVarLenEntryQueue_ConstHandle queue);
196 
197 /// Returns the the maximum number of bytes that can be stored in the queue.
198 /// This is largest possible value of `size_bytes()`, and the size of the
199 /// largest single entry that can be stored in this queue. Attempting to store a
200 /// larger entry is invalid and results in a crash.
201 static inline uint32_t pw_InlineVarLenEntryQueue_MaxSizeBytes(
202     pw_InlineVarLenEntryQueue_ConstHandle queue);
203 
204 /// Returns the size of the raw underlying `InlineVarLenEntryQueue` storage.
205 /// This size may be used to copy a `InlineVarLenEntryQueue` into another
206 /// 32-bit aligned memory location.
207 static inline uint32_t pw_InlineVarLenEntryQueue_RawStorageSizeBytes(
208     pw_InlineVarLenEntryQueue_ConstHandle queue);
209 
210 /// Returns true if the `InlineVarLenEntryQueue` is empty, false if it has at
211 /// least one entry.
212 static inline bool pw_InlineVarLenEntryQueue_Empty(
213     pw_InlineVarLenEntryQueue_ConstHandle queue);
214 
215 /// @}
216 
217 // Implementation details.
218 
219 #define _PW_VAR_QUEUE_DATA_SIZE_UINT32(max_size_bytes) \
220   ((_PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes) + 3 /* round up */) / 4)
221 
222 #define _PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes)              \
223   (PW_VARINT_ENCODED_SIZE_BYTES(max_size_bytes) + max_size_bytes + \
224    1 /*end byte*/)
225 
226 #define _PW_VAR_QUEUE_ARRAY_SIZE_BYTES queue[0]
227 #define _PW_VAR_QUEUE_HEAD queue[1]
228 #define _PW_VAR_QUEUE_TAIL queue[2]  // points after the last byte
229 #define _PW_VAR_QUEUE_DATA ((const uint8_t*)&queue[3])
230 
pw_InlineVarLenEntryQueue_Init(uint32_t array[],size_t array_size_uint32)231 static inline void pw_InlineVarLenEntryQueue_Init(uint32_t array[],
232                                                   size_t array_size_uint32) {
233   array[0] = (uint32_t)(array_size_uint32 -
234                         PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32) *
235              sizeof(uint32_t);
236   array[1] = 0;  // head
237   array[2] = 0;  // tail
238 }
239 
pw_InlineVarLenEntryQueue_Clear(pw_InlineVarLenEntryQueue_Handle queue)240 static inline void pw_InlineVarLenEntryQueue_Clear(
241     pw_InlineVarLenEntryQueue_Handle queue) {
242   _PW_VAR_QUEUE_HEAD = 0;  // head
243   _PW_VAR_QUEUE_TAIL = 0;  // tail
244 }
245 
246 static inline pw_InlineVarLenEntryQueue_Iterator
pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue)247 pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue) {
248   pw_InlineVarLenEntryQueue_Iterator begin = {queue, _PW_VAR_QUEUE_HEAD};
249   return begin;
250 }
251 
pw_InlineVarLenEntryQueue_End(pw_InlineVarLenEntryQueue_ConstHandle queue)252 static inline pw_InlineVarLenEntryQueue_Iterator pw_InlineVarLenEntryQueue_End(
253     pw_InlineVarLenEntryQueue_ConstHandle queue) {
254   pw_InlineVarLenEntryQueue_Iterator end = {queue, _PW_VAR_QUEUE_TAIL};
255   return end;
256 }
257 
pw_InlineVarLenEntryQueue_Iterator_Equal(const pw_InlineVarLenEntryQueue_Iterator * lhs,const pw_InlineVarLenEntryQueue_Iterator * rhs)258 static inline bool pw_InlineVarLenEntryQueue_Iterator_Equal(
259     const pw_InlineVarLenEntryQueue_Iterator* lhs,
260     const pw_InlineVarLenEntryQueue_Iterator* rhs) {
261   return lhs->_pw_offset == rhs->_pw_offset && lhs->_pw_queue == rhs->_pw_queue;
262 }
263 
264 // Private function that returns a pointer to the specified index in the Entry.
_pw_InlineVarLenEntryQueue_Entry_GetPointer(const pw_InlineVarLenEntryQueue_Entry * entry,size_t index)265 static inline const uint8_t* _pw_InlineVarLenEntryQueue_Entry_GetPointer(
266     const pw_InlineVarLenEntryQueue_Entry* entry, size_t index) {
267   if (index < entry->size_1) {
268     return &entry->data_1[index];
269   }
270   return &entry->data_2[index - entry->size_1];
271 }
272 
273 const uint8_t* _pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(
274     const pw_InlineVarLenEntryQueue_Entry* entry, size_t index);
275 
pw_InlineVarLenEntryQueue_Entry_At(const pw_InlineVarLenEntryQueue_Entry * entry,size_t index)276 static inline uint8_t pw_InlineVarLenEntryQueue_Entry_At(
277     const pw_InlineVarLenEntryQueue_Entry* entry, size_t index) {
278   return *_pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(entry, index);
279 }
280 
pw_InlineVarLenEntryQueue_RawStorageSizeBytes(pw_InlineVarLenEntryQueue_ConstHandle queue)281 static inline uint32_t pw_InlineVarLenEntryQueue_RawStorageSizeBytes(
282     pw_InlineVarLenEntryQueue_ConstHandle queue) {
283   return PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 * sizeof(uint32_t) +
284          _PW_VAR_QUEUE_ARRAY_SIZE_BYTES;
285 }
286 
pw_InlineVarLenEntryQueue_MaxSize(pw_InlineVarLenEntryQueue_ConstHandle queue)287 static inline uint32_t pw_InlineVarLenEntryQueue_MaxSize(
288     pw_InlineVarLenEntryQueue_ConstHandle queue) {
289   return _PW_VAR_QUEUE_ARRAY_SIZE_BYTES - 1;
290 }
291 
pw_InlineVarLenEntryQueue_MaxSizeBytes(pw_InlineVarLenEntryQueue_ConstHandle queue)292 static inline uint32_t pw_InlineVarLenEntryQueue_MaxSizeBytes(
293     pw_InlineVarLenEntryQueue_ConstHandle queue) {
294   return _PW_VAR_QUEUE_ARRAY_SIZE_BYTES - 1 -
295          (uint32_t)pw_varint_EncodedSizeBytes(_PW_VAR_QUEUE_ARRAY_SIZE_BYTES -
296                                               1);
297 }
298 
pw_InlineVarLenEntryQueue_Empty(pw_InlineVarLenEntryQueue_ConstHandle queue)299 static inline bool pw_InlineVarLenEntryQueue_Empty(
300     pw_InlineVarLenEntryQueue_ConstHandle queue) {
301   return _PW_VAR_QUEUE_HEAD == _PW_VAR_QUEUE_TAIL;
302 }
303 
304 // These macros are not part of the public API, so undefine them.
305 #undef _PW_VAR_QUEUE_ARRAY_SIZE_BYTES
306 #undef _PW_VAR_QUEUE_HEAD
307 #undef _PW_VAR_QUEUE_TAIL
308 #undef _PW_VAR_QUEUE_DATA
309 
310 #ifdef __cplusplus
311 }  // extern "C"
312 
313 #include <cstddef>
314 #include <limits>
315 #include <type_traits>
316 #include <utility>
317 
318 #include "pw_containers/internal/raw_storage.h"
319 #include "pw_span/span.h"
320 
321 namespace pw {
322 
323 // A`BasicInlineVarLenEntryQueue` with a known maximum size of a single entry.
324 // The member functions are immplemented in the generic-capacity base.
325 // TODO: b/303056683 - Add helper for calculating kMaxSizeBytes for N entries of
326 //     a particular size.
327 template <typename T,
328           size_t kMaxSizeBytes = containers::internal::kGenericSized>
329 class BasicInlineVarLenEntryQueue
330     : public BasicInlineVarLenEntryQueue<T,
331                                          containers::internal::kGenericSized> {
332  private:
333   using Base =
334       BasicInlineVarLenEntryQueue<T, containers::internal::kGenericSized>;
335 
336  public:
BasicInlineVarLenEntryQueue()337   constexpr BasicInlineVarLenEntryQueue() : Base(kMaxSizeBytes) {}
338 
339   // `BasicInlineVarLenEntryQueue` is trivially copyable.
340   BasicInlineVarLenEntryQueue(const BasicInlineVarLenEntryQueue&) = default;
341   BasicInlineVarLenEntryQueue& operator=(const BasicInlineVarLenEntryQueue&) =
342       default;
343 
344  private:
345   static_assert(kMaxSizeBytes <=
346                 std::numeric_limits<typename Base::size_type>::max());
347 
348   using Base::Init;  // Disallow Init since the size template param is not used.
349 
350   uint32_t data_[_PW_VAR_QUEUE_DATA_SIZE_UINT32(kMaxSizeBytes)];
351 };
352 
353 /// @defgroup inline_var_len_entry_queue_cpp_api
354 /// @{
355 
356 /// Variable-length entry queue class template for any byte type (e.g.
357 /// ``std::byte`` or ``uint8_t``).
358 ///
359 /// ``BasicInlineVarLenEntryQueue`` instances are declared with their capacity
360 /// / max single entry size (``BasicInlineVarLenEntryQueue<char, 64>``), but
361 /// may be referred to without the size
362 /// (``BasicInlineVarLenEntryQueue<char>&``).
363 template <typename T>
364 class BasicInlineVarLenEntryQueue<T, containers::internal::kGenericSized> {
365  public:
366   class Entry;
367 
368   using value_type = Entry;
369   using size_type = std::uint32_t;
370   using pointer = const value_type*;
371   using const_pointer = pointer;
372   using reference = const value_type&;
373   using const_reference = reference;
374 
375   // Refers to an entry in-place in the queue. Entries may not be contiguous.
376   class iterator;
377 
378   // Currently, iterators provide read-only access.
379   // TODO: b/303046109 - Provide a non-const iterator.
380   using const_iterator = iterator;
381 
382   /// @copydoc pw_InlineVarLenEntryQueue_Init
383   template <size_t kArraySize>
Init(uint32_t (& array)[kArraySize])384   static BasicInlineVarLenEntryQueue& Init(uint32_t (&array)[kArraySize]) {
385     static_assert(
386         kArraySize > PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32,
387         "InlineVarLenEntryQueue must be backed by an array with more than "
388         "PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 (3) elements");
389     return Init(array, kArraySize);
390   }
391 
392   /// @copydoc pw_InlineVarLenEntryQueue_Init
Init(uint32_t array[],size_t array_size_uint32)393   static BasicInlineVarLenEntryQueue& Init(uint32_t array[],
394                                            size_t array_size_uint32) {
395     pw_InlineVarLenEntryQueue_Init(array, array_size_uint32);
396     return *std::launder(reinterpret_cast<BasicInlineVarLenEntryQueue*>(array));
397   }
398 
399   /// Returns the first entry in the queue.
400   /// @pre The queue must NOT empty (`empty()` is false).
front()401   Entry front() const { return *begin(); }
402 
403   /// @copydoc pw_InlineVarLenEntryQueue_Begin
begin()404   const_iterator begin() const {
405     return const_iterator(pw_InlineVarLenEntryQueue_Begin(array_));
406   }
cbegin()407   const_iterator cbegin() const { return begin(); }
408 
409   /// @copydoc pw_InlineVarLenEntryQueue_End
end()410   const_iterator end() const {
411     return const_iterator(pw_InlineVarLenEntryQueue_End(array_));
412   }
cend()413   const_iterator cend() const { return end(); }
414 
415   /// @copydoc pw_InlineVarLenEntryQueue_Empty
empty()416   [[nodiscard]] bool empty() const {
417     return pw_InlineVarLenEntryQueue_Empty(array_);
418   }
419 
420   /// @copydoc pw_InlineVarLenEntryQueue_Size
size()421   size_type size() const { return pw_InlineVarLenEntryQueue_Size(array_); }
422 
423   /// @copydoc pw_InlineVarLenEntryQueue_MaxSize
max_size()424   size_type max_size() const {
425     return pw_InlineVarLenEntryQueue_MaxSize(array_);
426   }
427 
428   /// @copydoc pw_InlineVarLenEntryQueue_SizeBytes
size_bytes()429   size_type size_bytes() const {
430     return pw_InlineVarLenEntryQueue_SizeBytes(array_);
431   }
432 
433   /// @copydoc pw_InlineVarLenEntryQueue_MaxSizeBytes
max_size_bytes()434   size_type max_size_bytes() const {
435     return pw_InlineVarLenEntryQueue_MaxSizeBytes(array_);
436   }
437 
438   /// Underlying storage of the variable-length entry queue. May be used to
439   /// memcpy the queue.
raw_storage()440   span<const T> raw_storage() const {
441     return span<const T>(reinterpret_cast<const T*>(array_),
442                          pw_InlineVarLenEntryQueue_RawStorageSizeBytes(array_));
443   }
444 
445   /// @copydoc pw_InlineVarLenEntryQueue_Clear
clear()446   void clear() { pw_InlineVarLenEntryQueue_Clear(array_); }
447 
448   /// @copydoc pw_InlineVarLenEntryQueue_Push
push(span<const T> value)449   void push(span<const T> value) {
450     pw_InlineVarLenEntryQueue_Push(
451         array_, value.data(), static_cast<size_type>(value.size()));
452   }
453 
454   /// @copydoc pw_InlineVarLenEntryQueue_TryPush
try_push(span<const T> value)455   [[nodiscard]] bool try_push(span<const T> value) {
456     return pw_InlineVarLenEntryQueue_TryPush(
457         array_, value.data(), static_cast<size_type>(value.size()));
458   }
459 
460   /// @copydoc pw_InlineVarLenEntryQueue_PushOverwrite
push_overwrite(span<const T> value)461   void push_overwrite(span<const T> value) {
462     pw_InlineVarLenEntryQueue_PushOverwrite(
463         array_, value.data(), static_cast<size_type>(value.size()));
464   }
465 
466   /// @copydoc pw_InlineVarLenEntryQueue_Pop
pop()467   void pop() { pw_InlineVarLenEntryQueue_Pop(array_); }
468 
469  protected:
BasicInlineVarLenEntryQueue(uint32_t max_size_bytes)470   constexpr BasicInlineVarLenEntryQueue(uint32_t max_size_bytes)
471       : array_{_PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes), 0, 0} {}
472 
473   // Polymorphic-sized queues cannot be destroyed directly due to the lack of a
474   // virtual destructor.
475   ~BasicInlineVarLenEntryQueue() = default;
476 
477   BasicInlineVarLenEntryQueue(const BasicInlineVarLenEntryQueue&) = default;
478   BasicInlineVarLenEntryQueue& operator=(const BasicInlineVarLenEntryQueue&) =
479       default;
480 
481  private:
482   static_assert(std::is_integral_v<T> || std::is_same_v<T, std::byte>);
483   static_assert(sizeof(T) == sizeof(std::byte));
484 
485   uint32_t array_[PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32];
486 };
487 
488 /// Refers to an entry in-place in the queue. Entries may be discontiguous.
489 template <typename T>
490 class BasicInlineVarLenEntryQueue<T>::Entry {
491  public:
492   using value_type = T;
493   using size_type = std::uint32_t;
494   using pointer = const T*;
495   using const_pointer = pointer;
496   using reference = const T&;
497   using const_reference = reference;
498 
499   /// Iterator for the bytes in an Entry. Entries may be discontiguous, so a
500   /// pointer cannot serve as an iterator.
501   class iterator {
502    public:
503     using difference_type = std::ptrdiff_t;
504     using value_type = T;
505     using pointer = const T*;
506     using reference = const T&;
507     using iterator_category = std::forward_iterator_tag;
508 
iterator()509     constexpr iterator() : entry_(nullptr), index_(0) {}
510 
511     constexpr iterator(const iterator&) = default;
512     constexpr iterator& operator=(const iterator&) = default;
513 
514     constexpr iterator& operator++() {
515       index_ += 1;
516       return *this;
517     }
518     constexpr iterator operator++(int) {
519       iterator previous_value(*this);
520       operator++();
521       return previous_value;
522     }
523 
524     reference operator*() const { return *GetIndex(*entry_, index_); }
525     pointer operator->() const { return GetIndex(*entry_, index_); }
526 
527     bool operator==(const iterator& rhs) const {
528       return entry_->data_1 == rhs.entry_->data_1 && index_ == rhs.index_;
529     }
530     bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
531 
532    private:
533     friend class Entry;
534 
iterator(const pw_InlineVarLenEntryQueue_Entry & entry,size_t index)535     constexpr iterator(const pw_InlineVarLenEntryQueue_Entry& entry,
536                        size_t index)
537         : entry_(&entry), index_(index) {}
538 
539     const pw_InlineVarLenEntryQueue_Entry* entry_;
540     size_t index_;
541   };
542 
543   // TODO: b/303046109 - Provide mutable access to Entry contents.
544   using const_iterator = iterator;
545 
546   constexpr Entry(const Entry&) = default;
547   constexpr Entry& operator=(const Entry&) = default;
548 
at(size_t index)549   const_reference at(size_t index) const {
550     return *reinterpret_cast<const T*>(
551         _pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(&entry_, index));
552   }
553 
554   const_reference operator[](size_t index) const {
555     return *GetIndex(entry_, index);
556   }
557 
front()558   const_reference front() const { return *entry_.data_1; }
back()559   const_reference back() const { *GetIndex(entry_, size() - 1); }
560 
561   /// Entries may be stored in up to two segments, so this returns spans
562   /// refering to both portions of the entry. If the entry is contiguous, the
563   /// second span is empty.
contiguous_data()564   std::pair<span<const value_type>, span<const value_type>> contiguous_data()
565       const {
566     return std::make_pair(
567         span(reinterpret_cast<const_pointer>(entry_.data_1), entry_.size_1),
568         span(reinterpret_cast<const_pointer>(entry_.data_2), entry_.size_2));
569   }
570 
571   /// @copydoc pw_InlineVarLenEntryQueue_Entry_Copy
572   ///
573   /// Copying with `copy()` is likely more efficient than an iterator-based copy
574   /// with `std::copy()`, since `copy()` uses one or two `memcpy` calls instead
575   /// of copying byte-by-byte.
copy(T * dest,size_type count)576   size_type copy(T* dest, size_type count) const {
577     return pw_InlineVarLenEntryQueue_Entry_Copy(&entry_, dest, count);
578   }
579 
begin()580   const_iterator begin() const { return const_iterator(entry_, 0); }
cbegin()581   const_iterator cbegin() const { return begin(); }
582 
end()583   const_iterator end() const { return const_iterator(entry_, size()); }
cend()584   const_iterator cend() const { return cend(); }
585 
empty()586   [[nodiscard]] bool empty() const { return size() == 0; }
587 
size()588   size_type size() const { return entry_.size_1 + entry_.size_2; }
589 
590  private:
591   friend class BasicInlineVarLenEntryQueue;
592 
GetIndex(const pw_InlineVarLenEntryQueue_Entry & entry,size_t index)593   static const T* GetIndex(const pw_InlineVarLenEntryQueue_Entry& entry,
594                            size_t index) {
595     return reinterpret_cast<const T*>(
596         _pw_InlineVarLenEntryQueue_Entry_GetPointer(&entry, index));
597   }
598 
Entry(const pw_InlineVarLenEntryQueue_Entry & entry)599   explicit constexpr Entry(const pw_InlineVarLenEntryQueue_Entry& entry)
600       : entry_(entry) {}
601 
Entry()602   constexpr Entry() : entry_{} {}
603 
604   pw_InlineVarLenEntryQueue_Entry entry_;
605 };
606 
607 /// Iterator object for a `InlineVarLenEntryQueue`.
608 ///
609 /// Iterators are invalidated by any operations that change the container or
610 /// its underlying data (push/pop/init).
611 template <typename T>
612 class BasicInlineVarLenEntryQueue<T>::iterator {
613  public:
614   using difference_type = std::ptrdiff_t;
615   using value_type = Entry;
616   using pointer = const Entry*;
617   using reference = const Entry&;
618   using iterator_category = std::forward_iterator_tag;
619 
iterator()620   constexpr iterator() : iterator_{}, entry_{} {}
621 
622   constexpr iterator(const iterator&) = default;
623   constexpr iterator& operator=(const iterator&) = default;
624 
625   iterator& operator++() {
626     pw_InlineVarLenEntryQueue_Iterator_Advance(&iterator_);
627     entry_.entry_.data_1 = nullptr;  // mark the entry as unloaded
628     return *this;
629   }
630   iterator operator++(int) {
631     iterator previous_value(*this);
632     operator++();
633     return previous_value;
634   }
635 
636   reference operator*() const {
637     LoadEntry();
638     return entry_;
639   }
640   pointer operator->() const {
641     LoadEntry();
642     return &entry_;
643   }
644 
645   bool operator==(const iterator& rhs) const {
646     return pw_InlineVarLenEntryQueue_Iterator_Equal(&iterator_, &rhs.iterator_);
647   }
648   bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
649 
650  private:
651   friend class BasicInlineVarLenEntryQueue;
652 
iterator(const pw_InlineVarLenEntryQueue_Iterator & it)653   explicit constexpr iterator(const pw_InlineVarLenEntryQueue_Iterator& it)
654       : iterator_(it) {}
655 
LoadEntry()656   void LoadEntry() const {
657     if (entry_.entry_.data_1 == nullptr) {
658       entry_.entry_ = pw_InlineVarLenEntryQueue_GetEntry(&iterator_);
659     }
660   }
661 
662   pw_InlineVarLenEntryQueue_Iterator iterator_;
663   mutable Entry entry_;
664 };
665 
666 /// Variable-length entry queue that uses ``std::byte`` for the byte type.
667 template <size_t kMaxSizeBytes = containers::internal::kGenericSized>
668 using InlineVarLenEntryQueue =
669     BasicInlineVarLenEntryQueue<std::byte, kMaxSizeBytes>;
670 
671 /// @}
672 
673 }  // namespace pw
674 
675 #endif  // __cplusplus
676