Pigweed
 
Loading...
Searching...
No Matches
inline_var_len_entry_queue.h
Go to the documentation of this file.
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#ifdef __cplusplus
17
18#include <cstddef>
19#include <cstdint>
20
21#include "pw_toolchain/constexpr_tag.h"
22
23#else
24
25#include <stdbool.h>
26#include <stddef.h>
27#include <stdint.h>
28
29#endif // __cplusplus
30
31#include "pw_preprocessor/util.h"
32#include "pw_varint/varint.h"
33
62
63#ifdef __cplusplus
64extern "C" {
65#endif // __cplusplus
66
69
73typedef const uint32_t* pw_InlineVarLenEntryQueue_ConstHandle;
74
82#define PW_VARIABLE_LENGTH_ENTRY_QUEUE_DECLARE(variable, max_size_bytes) \
83 uint32_t variable[PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 + \
84 _PW_VAR_QUEUE_DATA_SIZE_UINT32(max_size_bytes)] = { \
85 _PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes), /*head=*/0u, /*tail=*/0u}
86
92#define PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 (3)
93
97static inline void pw_InlineVarLenEntryQueue_Init(uint32_t array[],
98 size_t array_size_uint32);
99
101static inline void pw_InlineVarLenEntryQueue_Clear(
103
109 const void* data,
110 uint32_t data_size_bytes);
111
118 const void* data,
119 const uint32_t data_size_bytes);
120
128 const void* data,
129 uint32_t data_size_bytes);
130
135
141typedef struct {
142 // Private: do not access these fields directly!
143 pw_InlineVarLenEntryQueue_ConstHandle _pw_queue;
144 uint32_t _pw_offset;
146
149typedef struct {
150 const uint8_t* data_1;
151 uint32_t size_1;
152 const uint8_t* data_2;
153 uint32_t size_2;
155
158pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue);
159
162 pw_InlineVarLenEntryQueue_ConstHandle queue);
163
168
173
176 const pw_InlineVarLenEntryQueue_Iterator* iterator);
177
186 const pw_InlineVarLenEntryQueue_Entry* entry, void* dest, uint32_t count);
187
190static inline uint8_t pw_InlineVarLenEntryQueue_Entry_At(
191 const pw_InlineVarLenEntryQueue_Entry* entry, size_t index);
192
196 pw_InlineVarLenEntryQueue_ConstHandle queue);
197
200static inline uint32_t pw_InlineVarLenEntryQueue_MaxSize(
201 pw_InlineVarLenEntryQueue_ConstHandle queue);
202
206 pw_InlineVarLenEntryQueue_ConstHandle queue);
207
212static inline uint32_t pw_InlineVarLenEntryQueue_MaxSizeBytes(
213 pw_InlineVarLenEntryQueue_ConstHandle queue);
214
219 pw_InlineVarLenEntryQueue_ConstHandle queue);
220
223static inline bool pw_InlineVarLenEntryQueue_Empty(
224 pw_InlineVarLenEntryQueue_ConstHandle queue);
225
227
228// Implementation details.
229
230#define _PW_VAR_QUEUE_DATA_SIZE_UINT32(max_size_bytes) \
231 ((_PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes) + 3 /* round up */) / 4)
232
233#define _PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes) \
234 (PW_VARINT_ENCODED_SIZE_BYTES(max_size_bytes) + max_size_bytes + \
235 1 /*end byte*/)
236
237#define _PW_VAR_QUEUE_ARRAY_SIZE_BYTES queue[0]
238#define _PW_VAR_QUEUE_HEAD queue[1]
239#define _PW_VAR_QUEUE_TAIL queue[2] // points after the last byte
240#define _PW_VAR_QUEUE_DATA ((const uint8_t*)&queue[3])
241
242static inline void pw_InlineVarLenEntryQueue_Init(uint32_t array[],
243 size_t array_size_uint32) {
244 array[0] = (uint32_t)(array_size_uint32 -
246 sizeof(uint32_t);
247 array[1] = 0; // head
248 array[2] = 0; // tail
249}
250
253 _PW_VAR_QUEUE_HEAD = 0; // head
254 _PW_VAR_QUEUE_TAIL = 0; // tail
255}
256
258pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue) {
259 pw_InlineVarLenEntryQueue_Iterator begin = {queue, _PW_VAR_QUEUE_HEAD};
260 return begin;
261}
262
264 pw_InlineVarLenEntryQueue_ConstHandle queue) {
265 pw_InlineVarLenEntryQueue_Iterator end = {queue, _PW_VAR_QUEUE_TAIL};
266 return end;
267}
268
272 return lhs->_pw_offset == rhs->_pw_offset && lhs->_pw_queue == rhs->_pw_queue;
273}
274
275// Private function that returns a pointer to the specified index in the Entry.
276static inline const uint8_t* _pw_InlineVarLenEntryQueue_Entry_GetPointer(
277 const pw_InlineVarLenEntryQueue_Entry* entry, size_t index) {
278 if (index < entry->size_1) {
279 return &entry->data_1[index];
280 }
281 return &entry->data_2[index - entry->size_1];
282}
283
284const uint8_t* _pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(
285 const pw_InlineVarLenEntryQueue_Entry* entry, size_t index);
286
288 const pw_InlineVarLenEntryQueue_Entry* entry, size_t index) {
289 return *_pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(entry, index);
290}
291
293 pw_InlineVarLenEntryQueue_ConstHandle queue) {
294 return PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 * sizeof(uint32_t) +
295 _PW_VAR_QUEUE_ARRAY_SIZE_BYTES;
296}
297
299 pw_InlineVarLenEntryQueue_ConstHandle queue) {
300 return _PW_VAR_QUEUE_ARRAY_SIZE_BYTES - 1;
301}
302
304 pw_InlineVarLenEntryQueue_ConstHandle queue) {
305 return _PW_VAR_QUEUE_ARRAY_SIZE_BYTES - 1 -
306 (uint32_t)pw_varint_EncodedSizeBytes(_PW_VAR_QUEUE_ARRAY_SIZE_BYTES -
307 1);
308}
309
311 pw_InlineVarLenEntryQueue_ConstHandle queue) {
312 return _PW_VAR_QUEUE_HEAD == _PW_VAR_QUEUE_TAIL;
313}
314
315// These macros are not part of the public API, so undefine them.
316#undef _PW_VAR_QUEUE_ARRAY_SIZE_BYTES
317#undef _PW_VAR_QUEUE_HEAD
318#undef _PW_VAR_QUEUE_TAIL
319#undef _PW_VAR_QUEUE_DATA
320
321#ifdef __cplusplus
322} // extern "C"
323
324#include <cstddef>
325#include <limits>
326#include <type_traits>
327#include <utility>
328
329#include "pw_containers/internal/raw_storage.h"
330#include "pw_span/span.h"
331
332namespace pw {
333
334// A`BasicInlineVarLenEntryQueue` with a known maximum size of a single entry.
335// The member functions are immplemented in the generic-capacity base.
336// TODO: b/303056683 - Add helper for calculating kMaxSizeBytes for N entries of
337// a particular size.
338template <typename T,
339 size_t kMaxSizeBytes = containers::internal::kGenericSized>
342 containers::internal::kGenericSized> {
343 private:
344 using Base =
346
347 public:
348 BasicInlineVarLenEntryQueue() : Base(kMaxSizeBytes) {}
349
350 // Explicit zero element constexpr constructor. Using this constructor will
351 // place the entire object in .data, which will increase ROM size. Use with
352 // caution if working with large capacity sizes.
354 : Base(kMaxSizeBytes), data_{} {}
355
356 // `BasicInlineVarLenEntryQueue` is trivially copyable.
359 default;
360
361 private:
362 static_assert(kMaxSizeBytes <=
363 std::numeric_limits<typename Base::size_type>::max());
364
365 using Base::Init; // Disallow Init since the size template param is not used.
366
367 uint32_t data_[_PW_VAR_QUEUE_DATA_SIZE_UINT32(kMaxSizeBytes)];
368};
369
372
380template <typename T>
381class BasicInlineVarLenEntryQueue<T, containers::internal::kGenericSized> {
382 public:
383 class Entry;
384
385 using value_type = Entry;
386 using size_type = std::uint32_t;
387 using pointer = const value_type*;
388 using const_pointer = pointer;
389 using reference = const value_type&;
390 using const_reference = reference;
391
392 // Refers to an entry in-place in the queue. Entries may not be contiguous.
393 class iterator;
394
395 // Currently, iterators provide read-only access.
396 // TODO: b/303046109 - Provide a non-const iterator.
397 using const_iterator = iterator;
398
400 template <size_t kArraySize>
401 static BasicInlineVarLenEntryQueue& Init(uint32_t (&array)[kArraySize]) {
402 static_assert(
404 "InlineVarLenEntryQueue must be backed by an array with more than "
405 "PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32 (3) elements");
406 return Init(array, kArraySize);
407 }
408
410 static BasicInlineVarLenEntryQueue& Init(uint32_t array[],
411 size_t array_size_uint32) {
412 pw_InlineVarLenEntryQueue_Init(array, array_size_uint32);
413 return *std::launder(reinterpret_cast<BasicInlineVarLenEntryQueue*>(array));
414 }
415
418 Entry front() const { return *begin(); }
419
421 const_iterator begin() const {
422 return const_iterator(pw_InlineVarLenEntryQueue_Begin(array_));
423 }
424 const_iterator cbegin() const { return begin(); }
425
427 const_iterator end() const {
428 return const_iterator(pw_InlineVarLenEntryQueue_End(array_));
429 }
430 const_iterator cend() const { return end(); }
431
433 [[nodiscard]] bool empty() const {
434 return pw_InlineVarLenEntryQueue_Empty(array_);
435 }
436
438 size_type size() const { return pw_InlineVarLenEntryQueue_Size(array_); }
439
441 size_type max_size() const {
443 }
444
446 size_type size_bytes() const {
448 }
449
451 size_type max_size_bytes() const {
453 }
454
457 span<const T> raw_storage() const {
458 return span<const T>(reinterpret_cast<const T*>(array_),
460 }
461
464
466 void push(span<const T> value) {
468 array_, value.data(), static_cast<size_type>(value.size()));
469 }
470
472 [[nodiscard]] bool try_push(span<const T> value) {
474 array_, value.data(), static_cast<size_type>(value.size()));
475 }
476
478 void push_overwrite(span<const T> value) {
480 array_, value.data(), static_cast<size_type>(value.size()));
481 }
482
485
486 protected:
487 constexpr BasicInlineVarLenEntryQueue(uint32_t max_size_bytes)
488 : array_{_PW_VAR_QUEUE_DATA_SIZE_BYTES(max_size_bytes), 0, 0} {}
489
490 // Polymorphic-sized queues cannot be destroyed directly due to the lack of a
491 // virtual destructor.
492 ~BasicInlineVarLenEntryQueue() = default;
493
494 BasicInlineVarLenEntryQueue(const BasicInlineVarLenEntryQueue&) = default;
495 BasicInlineVarLenEntryQueue& operator=(const BasicInlineVarLenEntryQueue&) =
496 default;
497
498 private:
499 static_assert(std::is_integral_v<T> || std::is_same_v<T, std::byte>);
500 static_assert(sizeof(T) == sizeof(std::byte));
501
503};
504
506template <typename T>
508 public:
509 using value_type = T;
510 using size_type = std::uint32_t;
511 using pointer = const T*;
512 using const_pointer = pointer;
513 using reference = const T&;
514 using const_reference = reference;
515
518 class iterator {
519 public:
520 using difference_type = std::ptrdiff_t;
521 using value_type = T;
522 using pointer = const T*;
523 using reference = const T&;
524 using iterator_category = std::forward_iterator_tag;
525
526 constexpr iterator() : entry_(nullptr), index_(0) {}
527
528 constexpr iterator(const iterator&) = default;
529 constexpr iterator& operator=(const iterator&) = default;
530
531 constexpr iterator& operator++() {
532 index_ += 1;
533 return *this;
534 }
535 constexpr iterator operator++(int) {
536 iterator previous_value(*this);
537 operator++();
538 return previous_value;
539 }
540
541 reference operator*() const { return *GetIndex(*entry_, index_); }
542 pointer operator->() const { return GetIndex(*entry_, index_); }
543
544 bool operator==(const iterator& rhs) const {
545 return entry_->data_1 == rhs.entry_->data_1 && index_ == rhs.index_;
546 }
547 bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
548
549 private:
550 friend class Entry;
551
552 constexpr iterator(const pw_InlineVarLenEntryQueue_Entry& entry,
553 size_t index)
554 : entry_(&entry), index_(index) {}
555
557 size_t index_;
558 };
559
560 // TODO: b/303046109 - Provide mutable access to Entry contents.
561 using const_iterator = iterator;
562
563 constexpr Entry(const Entry&) = default;
564 constexpr Entry& operator=(const Entry&) = default;
565
566 const_reference at(size_t index) const {
567 return *reinterpret_cast<const T*>(
568 _pw_InlineVarLenEntryQueue_Entry_GetPointerChecked(&entry_, index));
569 }
570
571 const_reference operator[](size_t index) const {
572 return *GetIndex(entry_, index);
573 }
574
575 const_reference front() const { return *entry_.data_1; }
576 const_reference back() const { *GetIndex(entry_, size() - 1); }
577
581 std::pair<span<const value_type>, span<const value_type>> contiguous_data()
582 const {
583 return std::make_pair(
584 span(reinterpret_cast<const_pointer>(entry_.data_1), entry_.size_1),
585 span(reinterpret_cast<const_pointer>(entry_.data_2), entry_.size_2));
586 }
587
593 size_type copy(T* dest, size_type count) const {
594 return pw_InlineVarLenEntryQueue_Entry_Copy(&entry_, dest, count);
595 }
596
597 const_iterator begin() const { return const_iterator(entry_, 0); }
598 const_iterator cbegin() const { return begin(); }
599
600 const_iterator end() const { return const_iterator(entry_, size()); }
601 const_iterator cend() const { return cend(); }
602
603 [[nodiscard]] bool empty() const { return size() == 0; }
604
605 size_type size() const { return entry_.size_1 + entry_.size_2; }
606
607 private:
608 friend class BasicInlineVarLenEntryQueue;
609
610 static const T* GetIndex(const pw_InlineVarLenEntryQueue_Entry& entry,
611 size_t index) {
612 return reinterpret_cast<const T*>(
613 _pw_InlineVarLenEntryQueue_Entry_GetPointer(&entry, index));
614 }
615
616 explicit constexpr Entry(const pw_InlineVarLenEntryQueue_Entry& entry)
617 : entry_(entry) {}
618
619 constexpr Entry() : entry_{} {}
620
622};
623
628template <typename T>
630 public:
631 using difference_type = std::ptrdiff_t;
632 using value_type = Entry;
633 using pointer = const Entry*;
634 using reference = const Entry&;
635 using iterator_category = std::forward_iterator_tag;
636
637 constexpr iterator() : iterator_{}, entry_{} {}
638
639 constexpr iterator(const iterator&) = default;
640 constexpr iterator& operator=(const iterator&) = default;
641
642 iterator& operator++() {
644 entry_.entry_.data_1 = nullptr; // mark the entry as unloaded
645 return *this;
646 }
647 iterator operator++(int) {
648 iterator previous_value(*this);
649 operator++();
650 return previous_value;
651 }
652
653 reference operator*() const {
654 LoadEntry();
655 return entry_;
656 }
657 pointer operator->() const {
658 LoadEntry();
659 return &entry_;
660 }
661
662 bool operator==(const iterator& rhs) const {
663 return pw_InlineVarLenEntryQueue_Iterator_Equal(&iterator_, &rhs.iterator_);
664 }
665 bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
666
667 private:
668 friend class BasicInlineVarLenEntryQueue;
669
670 explicit constexpr iterator(const pw_InlineVarLenEntryQueue_Iterator& it)
671 : iterator_(it) {}
672
673 void LoadEntry() const {
674 if (entry_.entry_.data_1 == nullptr) {
675 entry_.entry_ = pw_InlineVarLenEntryQueue_GetEntry(&iterator_);
676 }
677 }
678
680 mutable Entry entry_;
681};
682
684template <size_t kMaxSizeBytes = containers::internal::kGenericSized>
687
689
690} // namespace pw
691
692#endif // __cplusplus
Definition: inline_var_len_entry_queue.h:518
Refers to an entry in-place in the queue. Entries may be discontiguous.
Definition: inline_var_len_entry_queue.h:507
size_type copy(T *dest, size_type count) const
Definition: inline_var_len_entry_queue.h:593
std::pair< span< const value_type >, span< const value_type > > contiguous_data() const
Definition: inline_var_len_entry_queue.h:581
Definition: inline_var_len_entry_queue.h:629
Definition: inline_var_len_entry_queue.h:381
void pop()
Definition: inline_var_len_entry_queue.h:484
bool try_push(span< const T > value)
Definition: inline_var_len_entry_queue.h:472
span< const T > raw_storage() const
Definition: inline_var_len_entry_queue.h:457
const_iterator end() const
Returns an iterator that points past the end of the queue.
Definition: inline_var_len_entry_queue.h:427
static BasicInlineVarLenEntryQueue & Init(uint32_t array[], size_t array_size_uint32)
Definition: inline_var_len_entry_queue.h:410
Entry front() const
Definition: inline_var_len_entry_queue.h:418
size_type size_bytes() const
Definition: inline_var_len_entry_queue.h:446
size_type max_size() const
Definition: inline_var_len_entry_queue.h:441
static BasicInlineVarLenEntryQueue & Init(uint32_t(&array)[kArraySize])
Definition: inline_var_len_entry_queue.h:401
void push_overwrite(span< const T > value)
Definition: inline_var_len_entry_queue.h:478
bool empty() const
Definition: inline_var_len_entry_queue.h:433
size_type size() const
Definition: inline_var_len_entry_queue.h:438
const_iterator begin() const
Returns an iterator to the start of the InlineVarLenEntryQueue.
Definition: inline_var_len_entry_queue.h:421
void push(span< const T > value)
Definition: inline_var_len_entry_queue.h:466
size_type max_size_bytes() const
Definition: inline_var_len_entry_queue.h:451
void clear()
Empties the queue.
Definition: inline_var_len_entry_queue.h:463
Definition: inline_var_len_entry_queue.h:342
pw_InlineVarLenEntryQueue_Entry pw_InlineVarLenEntryQueue_GetEntry(const pw_InlineVarLenEntryQueue_Iterator *iterator)
Dereferences an iterator, loading the entry it points to.
static void pw_InlineVarLenEntryQueue_Init(uint32_t array[], size_t array_size_uint32)
Definition: inline_var_len_entry_queue.h:242
void pw_InlineVarLenEntryQueue_Push(pw_InlineVarLenEntryQueue_Handle queue, const void *data, uint32_t data_size_bytes)
uint32_t pw_InlineVarLenEntryQueue_Entry_Copy(const pw_InlineVarLenEntryQueue_Entry *entry, void *dest, uint32_t count)
bool pw_InlineVarLenEntryQueue_TryPush(pw_InlineVarLenEntryQueue_Handle queue, const void *data, const uint32_t data_size_bytes)
static uint32_t pw_InlineVarLenEntryQueue_MaxSize(pw_InlineVarLenEntryQueue_ConstHandle queue)
Definition: inline_var_len_entry_queue.h:298
static bool pw_InlineVarLenEntryQueue_Iterator_Equal(const pw_InlineVarLenEntryQueue_Iterator *lhs, const pw_InlineVarLenEntryQueue_Iterator *rhs)
Compares two iterators for equality.
Definition: inline_var_len_entry_queue.h:269
static uint32_t pw_InlineVarLenEntryQueue_MaxSizeBytes(pw_InlineVarLenEntryQueue_ConstHandle queue)
Definition: inline_var_len_entry_queue.h:303
uint32_t pw_InlineVarLenEntryQueue_Size(pw_InlineVarLenEntryQueue_ConstHandle queue)
void pw_InlineVarLenEntryQueue_PushOverwrite(pw_InlineVarLenEntryQueue_Handle queue, const void *data, uint32_t data_size_bytes)
void pw_InlineVarLenEntryQueue_Pop(pw_InlineVarLenEntryQueue_Handle queue)
static bool pw_InlineVarLenEntryQueue_Empty(pw_InlineVarLenEntryQueue_ConstHandle queue)
Definition: inline_var_len_entry_queue.h:310
static pw_InlineVarLenEntryQueue_Iterator pw_InlineVarLenEntryQueue_Begin(pw_InlineVarLenEntryQueue_ConstHandle queue)
Returns an iterator to the start of the InlineVarLenEntryQueue.
Definition: inline_var_len_entry_queue.h:258
#define PW_VARIABLE_LENGTH_ENTRY_QUEUE_HEADER_SIZE_UINT32
Definition: inline_var_len_entry_queue.h:92
static uint8_t pw_InlineVarLenEntryQueue_Entry_At(const pw_InlineVarLenEntryQueue_Entry *entry, size_t index)
Definition: inline_var_len_entry_queue.h:287
uint32_t * pw_InlineVarLenEntryQueue_Handle
Definition: inline_var_len_entry_queue.h:72
static pw_InlineVarLenEntryQueue_Iterator pw_InlineVarLenEntryQueue_End(pw_InlineVarLenEntryQueue_ConstHandle queue)
Returns an iterator that points past the end of the queue.
Definition: inline_var_len_entry_queue.h:263
void pw_InlineVarLenEntryQueue_Iterator_Advance(pw_InlineVarLenEntryQueue_Iterator *iterator)
static void pw_InlineVarLenEntryQueue_Clear(pw_InlineVarLenEntryQueue_Handle queue)
Empties the queue.
Definition: inline_var_len_entry_queue.h:251
uint32_t pw_InlineVarLenEntryQueue_SizeBytes(pw_InlineVarLenEntryQueue_ConstHandle queue)
static uint32_t pw_InlineVarLenEntryQueue_RawStorageSizeBytes(pw_InlineVarLenEntryQueue_ConstHandle queue)
Definition: inline_var_len_entry_queue.h:292
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
Definition: constexpr_tag.h:46
Definition: inline_var_len_entry_queue.h:149
Definition: inline_var_len_entry_queue.h:141
size_t pw_varint_EncodedSizeBytes(uint64_t integer)
Returns the size of a uint64_t when encoded as a varint (LEB128).