19#include <initializer_list>
26#include "pw_assert/assert.h"
27#include "pw_containers/internal/raw_storage.h"
28#include "pw_preprocessor/compiler.h"
29#include "pw_span/span.h"
30#include "pw_toolchain/constexpr_tag.h"
33namespace inline_circular_buffer_impl {
35enum Constness :
bool { kMutable =
false, kConst =
true };
37template <
typename ValueType,
typename SizeType, Constness kIsConst>
38class InlineDequeIterator;
42template <
typename T,
typename SizeType,
size_t kCapacity>
43class BasicInlineDeque;
47template <
typename ValueType,
50 bool kIsTriviallyDestructible>
66template <
typename T,
size_t kCapacity = containers::
internal::kGenericSized>
69template <
typename ValueType,
71 size_t kCapacity = containers::internal::kGenericSized>
76 std::is_trivially_destructible_v<ValueType>> {
80 containers::internal::kGenericSized>;
84 using typename Base::const_pointer;
85 using typename Base::const_reference;
86 using typename Base::difference_type;
88 using typename Base::pointer;
89 using typename Base::reference;
90 using typename Base::size_type;
91 using typename Base::value_type;
103 Base::assign(count, value);
112 typename InputIterator,
113 typename = containers::internal::EnableIfInputIterator<InputIterator>>
115 Base::assign(start, finish);
124 template <
size_t kOtherCapacity>
132 *
this = std::move(other);
136 template <
size_t kOtherCapacity>
139 *
this = std::move(other);
148 template <
typename T,
typename = containers::
internal::EnableIfIterable<T>>
165 Base::operator=(list);
171 Base::operator=(
static_cast<const Base&
>(other));
178 template <
size_t kOtherCapacity>
181 Base::operator=(
static_cast<const Base&
>(other));
187 Base::operator=(
static_cast<Base&&
>(std::move(other)));
192 template <
size_t kOtherCapacity>
195 Base::operator=(
static_cast<Base&&
>(std::move(other)));
199 template <
typename T,
typename = containers::
internal::EnableIfIterable<T>>
201 Base::operator=(other);
207 static constexpr size_type max_size() {
return capacity(); }
208 static constexpr size_type capacity() {
return kCapacity; }
215 containers::internal::kGenericSized>;
217 static_assert(kCapacity <= std::numeric_limits<size_type>::max());
222template <typename ValueType, typename SizeType, size_t kCapacity>
223class BasicInlineDequeStorage<ValueType, SizeType, kCapacity, true>
224 : public BasicInlineDeque<ValueType,
226 containers::internal::kGenericSized> {
229 friend class BasicInlineDeque<ValueType, SizeType, kCapacity>;
230 friend class BasicInlineDeque<ValueType,
232 containers::internal::kGenericSized>;
234 using Base = BasicInlineDeque<ValueType,
236 containers::internal::kGenericSized>;
238 constexpr BasicInlineDequeStorage() : Base(kCapacity) {}
244 typename Base::pointer data() { return raw_storage_.data(); }
245 typename Base::const_pointer data() const { return raw_storage_.data(); }
249 containers::internal::RawStorage<ValueType, kCapacity> raw_storage_;
255template <typename ValueType, typename SizeType, size_t kCapacity>
256class BasicInlineDequeStorage<ValueType, SizeType, kCapacity, false>
257 : public BasicInlineDeque<ValueType,
259 containers::internal::kGenericSized> {
261 ~BasicInlineDequeStorage() { Base::clear(); }
264 friend class BasicInlineDeque<ValueType, SizeType, kCapacity>;
265 friend class BasicInlineDeque<ValueType,
267 containers::internal::kGenericSized>;
269 using Base = BasicInlineDeque<ValueType,
271 containers::internal::kGenericSized>;
273 constexpr BasicInlineDequeStorage() : Base(kCapacity) {}
279 typename Base::pointer data() { return raw_storage_.data(); }
280 typename Base::const_pointer data() const { return raw_storage_.data(); }
284 containers::internal::RawStorage<ValueType, kCapacity> raw_storage_;
297template <typename ValueType, typename SizeType>
298class BasicInlineDeque<ValueType,
300 containers::internal::kGenericSized> {
302 using value_type = ValueType;
303 using size_type = SizeType;
304 using difference_type = ptrdiff_t;
305 using reference = value_type&;
306 using const_reference = const value_type&;
307 using pointer = value_type*;
308 using const_pointer = const value_type*;
309 using iterator = inline_circular_buffer_impl::InlineDequeIterator<
312 inline_circular_buffer_impl::Constness::kMutable>;
313 using const_iterator = inline_circular_buffer_impl::InlineDequeIterator<
316 inline_circular_buffer_impl::Constness::kConst>;
319 BasicInlineDeque() = delete;
322 BasicInlineDeque& operator=(const std::initializer_list<value_type>& list) {
327 BasicInlineDeque& operator=(const BasicInlineDeque& other) {
328 assign(other.begin(), other.end());
332 BasicInlineDeque& operator=(BasicInlineDeque&& other) noexcept {
334 for (auto&& item : other) {
335 emplace_back(std::move(item));
341 template <typename T, typename = containers::internal::EnableIfIterable<T>>
342 BasicInlineDeque& operator=(const T& other) {
343 assign(other.begin(), other.end());
347 void assign(size_type count, const value_type& value) {
349 Append(count, value);
353 typename InputIterator,
354 typename = containers::internal::EnableIfInputIterator<InputIterator>>
355 void assign(InputIterator start, InputIterator finish) {
357 CopyFrom(start, finish);
360 void assign(const std::initializer_list<value_type>& list) {
361 assign(list.begin(), list.end());
366 reference at(size_type index) {
367 PW_ASSERT(index < size());
368 return data()[AbsoluteIndex(index)];
370 const_reference at(size_type index) const {
371 PW_ASSERT(index < size());
372 return data()[AbsoluteIndex(index)];
375 reference operator[](size_type index) {
376 PW_DASSERT(index < size());
377 return data()[AbsoluteIndex(index)];
379 const_reference operator[](size_type index) const {
380 PW_DASSERT(index < size());
381 return data()[AbsoluteIndex(index)];
385 PW_DASSERT(!empty());
386 return data()[head_];
388 const_reference front() const {
389 PW_DASSERT(!empty());
390 return data()[head_];
394 PW_DASSERT(!empty());
395 return data()[AbsoluteIndex(size() - 1)];
397 const_reference back() const {
398 PW_DASSERT(!empty());
399 return data()[AbsoluteIndex(size() - 1)];
403 std::pair<span<const value_type>, span<const value_type>> contiguous_data()
405 std::pair<span<value_type>, span<value_type>> contiguous_data() {
406 auto [first, second] =
407 static_cast<const BasicInlineDeque&>(*this).contiguous_data();
408 return std::make_pair(
409 span<value_type>(const_cast<pointer>(first.data()), first.size()),
410 span<value_type>(const_cast<pointer>(second.data()), second.size()));
415 iterator begin() noexcept {
420 return iterator(this, 0);
422 const_iterator begin() const noexcept { return cbegin(); }
423 const_iterator cbegin() const noexcept {
427 return const_iterator(this, 0);
430 iterator end() noexcept {
431 return iterator(this, std::numeric_limits<size_type>::max());
433 const_iterator end() const noexcept { return cend(); }
434 const_iterator cend() const noexcept {
435 return const_iterator(this, std::numeric_limits<size_type>::max());
440 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
442 [[nodiscard]] bool full() const noexcept { return size() == max_size(); }
446 size_type size() const noexcept PW_NO_SANITIZE("memory") { return count_; }
448 size_type max_size() const noexcept { return capacity(); }
452 size_type capacity() const noexcept PW_NO_SANITIZE("memory") {
458 void clear() noexcept;
460 void push_back(const value_type& value) { emplace_back(value); }
462 void push_back(value_type&& value) { emplace_back(std::move(value)); }
464 template <typename... Args>
465 void emplace_back(Args&&... args);
469 void push_front(const value_type& value) { emplace_front(value); }
471 void push_front(value_type&& value) { emplace_front(std::move(value)); }
473 template <typename... Args>
474 void emplace_front(Args&&... args);
478 void resize(size_type new_size) { resize(new_size, value_type()); }
480 void resize(size_type new_size, const value_type& value);
483 constexpr BasicInlineDeque(size_type capacity) noexcept
484 : capacity_(capacity), head_(0), tail_(0), count_(0) {}
488 ~BasicInlineDeque() = default;
491 friend class inline_circular_buffer_impl::InlineDequeIterator<
494 inline_circular_buffer_impl::Constness::kMutable>;
495 friend class inline_circular_buffer_impl::InlineDequeIterator<
498 inline_circular_buffer_impl::Constness::kConst>;
505 return static_cast<BasicInlineDeque<value_type, size_type, 0>*>(this)
508 const_pointer data() const {
509 return static_cast<const BasicInlineDeque<value_type, size_type, 0>*>(this)
513 void IncrementWithWrap(size_type& index) const {
517 if (index == max_size()) {
522 void DecrementWithWrap(size_type& index) const {
535 size_type AbsoluteIndex(const size_type relative_index) const
536 PW_NO_SANITIZE("memory") {
537 const size_type absolute_index = head_ + relative_index;
538 if (absolute_index < max_size()) {
539 return absolute_index;
542 return absolute_index - max_size();
545 template <typename Iterator>
546 void CopyFrom(Iterator start, Iterator finish);
548 void Append(size_type count, const value_type& value);
550 const size_type capacity_;
558template <typename ValueType, typename SizeType>
559std::pair<span<const ValueType>, span<const ValueType>>
560BasicInlineDeque<ValueType, SizeType>::contiguous_data() const {
562 return std::make_pair(span<const value_type>(), span<const value_type>());
567 return std::make_pair(span<const value_type>(&data()[head_], size()),
568 span<const value_type>());
573 return std::make_pair(
574 span<const value_type>(&data()[head_], max_size() - head_),
575 span<const value_type>(&data()[0], tail_));
579template <typename ValueType, typename SizeType>
580void BasicInlineDeque<ValueType, SizeType>::clear() noexcept {
581 if constexpr (!std::is_trivially_destructible_v<value_type>) {
582 for (auto& item : *this) {
591template <typename ValueType, typename SizeType>
592template <typename... Args>
593void BasicInlineDeque<ValueType, SizeType>::emplace_back(Args&&... args) {
595 PW_DASSERT(tail_ < capacity());
596 new (&data()[tail_]) value_type(std::forward<Args>(args)...);
597 IncrementWithWrap(tail_);
601template <typename ValueType, typename SizeType>
602void BasicInlineDeque<ValueType, SizeType>::pop_back() {
604 PW_DASSERT(tail_ < capacity());
605 if constexpr (!std::is_trivially_destructible_v<value_type>) {
606 back().~value_type();
608 DecrementWithWrap(tail_);
612template <typename ValueType, typename SizeType>
613template <typename... Args>
614void BasicInlineDeque<ValueType, SizeType>::emplace_front(Args&&... args) {
616 DecrementWithWrap(head_);
617 PW_DASSERT(head_ < capacity());
618 new (&data()[head_]) value_type(std::forward<Args>(args)...);
622template <typename ValueType, typename SizeType>
623void BasicInlineDeque<ValueType, SizeType>::pop_front() {
625 PW_DASSERT(head_ < capacity());
626 if constexpr (!std::is_trivially_destructible_v<value_type>) {
627 front().~value_type();
629 IncrementWithWrap(head_);
633template <typename ValueType, typename SizeType>
634void BasicInlineDeque<ValueType, SizeType>::resize(size_type new_size,
635 const value_type& value) {
636 if (size() < new_size) {
637 Append(std::min(max_size(), new_size) - size(), value);
639 while (size() > new_size) {
645template <typename ValueType, typename SizeType>
646template <typename Iterator>
647void BasicInlineDeque<ValueType, SizeType>::CopyFrom(Iterator start,
649 while (start != finish) {
654template <typename ValueType, typename SizeType>
655void BasicInlineDeque<ValueType, SizeType>::Append(size_type count,
656 const value_type& value) {
657 for (size_type i = 0; i < count; ++i) {
662namespace inline_circular_buffer_impl {
666template <typename ValueType, typename SizeType, Constness kIsConst>
667class InlineDequeIterator {
669 using container_type =
670 typename std::conditional<kIsConst,
671 const BasicInlineDeque<ValueType, SizeType>,
672 BasicInlineDeque<ValueType, SizeType>>::type;
673 using value_type = ValueType;
674 using size_type = SizeType;
675 typedef typename std::conditional<kIsConst,
676 typename container_type::const_reference,
677 typename container_type::reference>::type
680 typename std::conditional<kIsConst,
681 typename container_type::const_pointer,
682 typename container_type::pointer>::type pointer;
683 using difference_type = std::ptrdiff_t;
684 using iterator_category = std::forward_iterator_tag;
686 constexpr InlineDequeIterator() = default;
687 constexpr InlineDequeIterator(container_type* container, size_type pos)
688 : container_(container), pos_(pos) {}
690 constexpr InlineDequeIterator(const InlineDequeIterator& other) = default;
691 constexpr InlineDequeIterator& operator=(const InlineDequeIterator& other) =
694 operator InlineDequeIterator<ValueType, SizeType, Constness::kConst>() const {
695 return {container_, pos_};
698 constexpr InlineDequeIterator& Incr(difference_type n) {
699 const difference_type new_pos =
700 n + (pos_ == kEnd ? container_->size() : pos_);
702 PW_DASSERT(new_pos >= 0);
703 PW_DASSERT(new_pos <= container_->size());
706 new_pos == container_->size() ? kEnd : static_cast<size_type>(new_pos);
711 constexpr InlineDequeIterator& operator+=(difference_type n) {
714 constexpr InlineDequeIterator& operator-=(difference_type n) {
717 constexpr InlineDequeIterator& operator++() { return Incr(1); }
718 constexpr InlineDequeIterator operator++(int) {
719 InlineDequeIterator it(*this);
724 constexpr InlineDequeIterator& operator--() { return Incr(-1); }
725 constexpr InlineDequeIterator operator--(int) {
726 InlineDequeIterator it = *this;
731 constexpr friend InlineDequeIterator operator+(InlineDequeIterator it,
735 constexpr friend InlineDequeIterator operator+(difference_type n,
736 InlineDequeIterator it) {
740 constexpr friend InlineDequeIterator operator-(InlineDequeIterator it,
745 constexpr friend difference_type operator-(const InlineDequeIterator& a,
746 const InlineDequeIterator& b) {
747 return static_cast<difference_type>(a.pos_ == kEnd ? a.container_->size()
749 static_cast<difference_type>(b.pos_ == kEnd ? b.container_->size()
753 constexpr reference operator*() const {
754 PW_DASSERT(pos_ != kEnd);
755 PW_DASSERT(pos_ < container_->size());
757 return container_->at(pos_);
760 constexpr pointer operator->() const {
761 PW_DASSERT(pos_ != kEnd);
762 PW_DASSERT(pos_ < container_->size());
767 constexpr reference operator[](size_type n) { return *(*this + n); }
769 constexpr bool operator==(const InlineDequeIterator& other) const {
770 return container_ == other.container_ && pos_ == other.pos_;
773 constexpr bool operator!=(const InlineDequeIterator& other) const {
774 return !(*this == other);
777 constexpr friend bool operator<(InlineDequeIterator a,
778 InlineDequeIterator b) {
782 constexpr friend bool operator>(InlineDequeIterator a,
783 InlineDequeIterator b) {
792 constexpr friend bool operator>=(InlineDequeIterator a,
793 InlineDequeIterator b) {
798 static constexpr size_type kEnd = std::numeric_limits<size_type>::max();
799 container_type* container_;
Definition: inline_deque.h:300
Definition: inline_deque.h:76
BasicInlineDeque(const T &other)
Copy constructor for arbitrary iterables.
Definition: inline_deque.h:149
BasicInlineDeque() noexcept
Constructs with zero elements.
Definition: inline_deque.h:94
BasicInlineDeque & operator=(const BasicInlineDeque< ValueType, SizeType, kOtherCapacity > &other)
Definition: inline_deque.h:179
BasicInlineDeque(BasicInlineDeque &&other) noexcept
Move constructs for matching capacity.
Definition: inline_deque.h:131
BasicInlineDeque & operator=(const std::initializer_list< value_type > &list)
Copy assigns from list.
Definition: inline_deque.h:164
BasicInlineDeque(size_type count)
Constructs with count default-initialized elements.
Definition: inline_deque.h:107
BasicInlineDeque(const BasicInlineDeque &other)
Copy constructs for matching capacity.
Definition: inline_deque.h:119
BasicInlineDeque & operator=(BasicInlineDeque &&other) noexcept
Move assigns for matching capacity.
Definition: inline_deque.h:186
BasicInlineDeque(BasicInlineDeque< ValueType, SizeType, kOtherCapacity > &&other) noexcept
Move constructs for mismatched capacity.
Definition: inline_deque.h:137
BasicInlineDeque(const BasicInlineDeque< ValueType, SizeType, kOtherCapacity > &other)
Definition: inline_deque.h:125
BasicInlineDeque(size_type count, const_reference value)
Constructs with count copies of value.
Definition: inline_deque.h:102
BasicInlineDeque & operator=(const BasicInlineDeque &other)
Copy assigns for matching capacity.
Definition: inline_deque.h:170
BasicInlineDeque & operator=(BasicInlineDeque< ValueType, SizeType, kOtherCapacity > &&other) noexcept
Move assigns for mismatched capacity.
Definition: inline_deque.h:193
BasicInlineDeque(InputIterator start, InputIterator finish)
Copy constructs from an iterator.
Definition: inline_deque.h:114
BasicInlineDeque(const std::initializer_list< value_type > &list)
Copy constructs from an initializer list.
Definition: inline_deque.h:143
Definition: inline_deque.h:51
Definition: inline_deque.h:667
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
Definition: constexpr_tag.h:46