Pigweed
 
Loading...
Searching...
No Matches
inline_deque.h
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 <algorithm>
17#include <cstddef>
18#include <cstdint>
19#include <initializer_list>
20#include <iterator>
21#include <limits>
22#include <new>
23#include <type_traits>
24#include <utility>
25
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"
31
32namespace pw {
33namespace inline_circular_buffer_impl {
34
35enum Constness : bool { kMutable = false, kConst = true };
36
37template <typename ValueType, typename SizeType, Constness kIsConst>
38class InlineDequeIterator;
39
40} // namespace inline_circular_buffer_impl
41
42template <typename T, typename SizeType, size_t kCapacity>
43class BasicInlineDeque;
44
45// Storage for a queue's data and that ensures entries are `clear`'d before
46// the storage is removed.
47template <typename ValueType,
48 typename SizeType,
49 size_t kCapacity,
50 bool kIsTriviallyDestructible>
52
66template <typename T, size_t kCapacity = containers::internal::kGenericSized>
68
69template <typename ValueType,
70 typename SizeType,
71 size_t kCapacity = containers::internal::kGenericSized>
73 ValueType,
74 SizeType,
75 kCapacity,
76 std::is_trivially_destructible_v<ValueType>> {
77 private:
78 using Base = BasicInlineDeque<ValueType,
79 SizeType,
80 containers::internal::kGenericSized>;
81
82 public:
83 using typename Base::const_iterator;
84 using typename Base::const_pointer;
85 using typename Base::const_reference;
86 using typename Base::difference_type;
87 using typename Base::iterator;
88 using typename Base::pointer;
89 using typename Base::reference;
90 using typename Base::size_type;
91 using typename Base::value_type;
92
94 BasicInlineDeque() noexcept {}
95
96 // Explicit zero element constexpr constructor. Using this constructor will
97 // place the entire object in .data, which will increase ROM size. Use with
98 // caution if working with large capacity sizes.
99 constexpr BasicInlineDeque(ConstexprTag /*constexpr_tag*/) noexcept {}
100
102 BasicInlineDeque(size_type count, const_reference value) {
103 Base::assign(count, value);
104 }
105
107 explicit BasicInlineDeque(size_type count)
108 : BasicInlineDeque(count, value_type()) {}
109
111 template <
112 typename InputIterator,
113 typename = containers::internal::EnableIfInputIterator<InputIterator>>
114 BasicInlineDeque(InputIterator start, InputIterator finish) {
115 Base::assign(start, finish);
116 }
117
119 BasicInlineDeque(const BasicInlineDeque& other) { *this = other; }
120
124 template <size_t kOtherCapacity>
127 *this = other;
128 }
129
132 *this = std::move(other);
133 }
134
136 template <size_t kOtherCapacity>
139 *this = std::move(other);
140 }
141
143 BasicInlineDeque(const std::initializer_list<value_type>& list) {
144 *this = list;
145 }
146
148 template <typename T, typename = containers::internal::EnableIfIterable<T>>
149 BasicInlineDeque(const T& other) {
150 *this = other;
151 }
152
153 // Assignment operators
154 //
155 // These operators delegate to the base class implementations in order to
156 // maximize code reuse. The wrappers are required so that `operator=`
157 // returns the correct type of reference.
158 //
159 // The `static_cast`s below are unfortunately necessary: without them,
160 // overload resolution prefers to use the "iterable" operators rather than
161 // upcast the RHS.
162
164 BasicInlineDeque& operator=(const std::initializer_list<value_type>& list) {
165 Base::operator=(list);
166 return *this;
167 }
168
171 Base::operator=(static_cast<const Base&>(other));
172 return *this;
173 }
174
178 template <size_t kOtherCapacity>
181 Base::operator=(static_cast<const Base&>(other));
182 return *this;
183 }
184
187 Base::operator=(static_cast<Base&&>(std::move(other)));
188 return *this;
189 }
190
192 template <size_t kOtherCapacity>
195 Base::operator=(static_cast<Base&&>(std::move(other)));
196 return *this;
197 }
198
199 template <typename T, typename = containers::internal::EnableIfIterable<T>>
200 BasicInlineDeque& operator=(const T& other) {
201 Base::operator=(other);
202 return *this;
203 }
204
205 // Size
206
207 static constexpr size_type max_size() { return capacity(); }
208 static constexpr size_type capacity() { return kCapacity; }
209
210 // All other methods are implemented on the generic-sized base class.
211
212 private:
213 friend class BasicInlineDeque<value_type,
214 size_type,
215 containers::internal::kGenericSized>;
216
217 static_assert(kCapacity <= std::numeric_limits<size_type>::max());
218};
219
220// Specialization of ``BasicInlineDequeue`` for trivially-destructible
221// ``ValueType``. This specialization ensures that no destructor is generated.
222template <typename ValueType, typename SizeType, size_t kCapacity>
223class BasicInlineDequeStorage<ValueType, SizeType, kCapacity, true>
224 : public BasicInlineDeque<ValueType,
225 SizeType,
226 containers::internal::kGenericSized> {
227 // NOTE: no destructor is added, as `ValueType` is trivially-destructible.
228 private:
229 friend class BasicInlineDeque<ValueType, SizeType, kCapacity>;
230 friend class BasicInlineDeque<ValueType,
231 SizeType,
232 containers::internal::kGenericSized>;
233
234 using Base = BasicInlineDeque<ValueType,
235 SizeType,
236 containers::internal::kGenericSized>;
237
238 constexpr BasicInlineDequeStorage() : Base(kCapacity) {}
239
240 // The data() function is defined differently for the generic-sized and
241 // known-sized specializations. This data() implementation simply returns the
242 // RawStorage's data(). The generic-sized data() function casts *this to a
243 // known zero-sized specialization to access this exact function.
244 typename Base::pointer data() { return raw_storage_.data(); }
245 typename Base::const_pointer data() const { return raw_storage_.data(); }
246
247 // Note that this is offset and aligned the same for all possible
248 // kCapacity values for the same value_type.
249 containers::internal::RawStorage<ValueType, kCapacity> raw_storage_;
250};
251
252// Specialization of ``BasicInlineDequeue`` for non-trivially-destructible
253// ``ValueType``. This specialization ensures that the queue is cleared
254// during destruction prior to the invalidation of the `raw_storage_`.
255template <typename ValueType, typename SizeType, size_t kCapacity>
256class BasicInlineDequeStorage<ValueType, SizeType, kCapacity, false>
257 : public BasicInlineDeque<ValueType,
258 SizeType,
259 containers::internal::kGenericSized> {
260 public:
261 ~BasicInlineDequeStorage() { Base::clear(); }
262
263 private:
264 friend class BasicInlineDeque<ValueType, SizeType, kCapacity>;
265 friend class BasicInlineDeque<ValueType,
266 SizeType,
267 containers::internal::kGenericSized>;
268
269 using Base = BasicInlineDeque<ValueType,
270 SizeType,
271 containers::internal::kGenericSized>;
272
273 constexpr BasicInlineDequeStorage() : Base(kCapacity) {}
274
275 // The data() function is defined differently for the generic-sized and
276 // known-sized specializations. This data() implementation simply returns the
277 // RawStorage's data(). The generic-sized data() function casts *this to a
278 // known zero-sized specialization to access this exact function.
279 typename Base::pointer data() { return raw_storage_.data(); }
280 typename Base::const_pointer data() const { return raw_storage_.data(); }
281
282 // Note that this is offset and aligned the same for all possible
283 // kCapacity values for the same value_type.
284 containers::internal::RawStorage<ValueType, kCapacity> raw_storage_;
285};
286
287// Defines the generic-sized BasicInlineDeque<T> specialization, which
288// serves as the base class for BasicInlineDeque<T> of any capacity.
289//
290// Except for constructors and destructors, all other methods should be
291// implemented on this generic-sized specialization. Destructors must
292// only be written for the `BasicInlineDequeStorage` type in order to ensure
293// that `raw_storage_` is still valid at the time of destruction.
294//
295// NOTE: this size-polymorphic base class must not be used inside of
296// ``std::unique_ptr`` or ``delete``.
297template <typename ValueType, typename SizeType>
298class BasicInlineDeque<ValueType,
299 SizeType,
300 containers::internal::kGenericSized> {
301 public:
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<
310 value_type,
311 size_type,
312 inline_circular_buffer_impl::Constness::kMutable>;
313 using const_iterator = inline_circular_buffer_impl::InlineDequeIterator<
314 value_type,
315 size_type,
316 inline_circular_buffer_impl::Constness::kConst>;
317
318 // Polymorphic-sized `pw::InlineDeque<T>` may not be constructed directly.
319 BasicInlineDeque() = delete;
320
321 // Assignment
322 BasicInlineDeque& operator=(const std::initializer_list<value_type>& list) {
323 assign(list);
324 return *this;
325 }
326
327 BasicInlineDeque& operator=(const BasicInlineDeque& other) {
328 assign(other.begin(), other.end());
329 return *this;
330 }
331
332 BasicInlineDeque& operator=(BasicInlineDeque&& other) noexcept {
333 clear();
334 for (auto&& item : other) {
335 emplace_back(std::move(item));
336 }
337 other.clear();
338 return *this;
339 }
340
341 template <typename T, typename = containers::internal::EnableIfIterable<T>>
342 BasicInlineDeque& operator=(const T& other) {
343 assign(other.begin(), other.end());
344 return *this;
345 }
346
347 void assign(size_type count, const value_type& value) {
348 clear();
349 Append(count, value);
350 }
351
352 template <
353 typename InputIterator,
354 typename = containers::internal::EnableIfInputIterator<InputIterator>>
355 void assign(InputIterator start, InputIterator finish) {
356 clear();
357 CopyFrom(start, finish);
358 }
359
360 void assign(const std::initializer_list<value_type>& list) {
361 assign(list.begin(), list.end());
362 }
363
364 // Access
365
366 reference at(size_type index) {
367 PW_ASSERT(index < size());
368 return data()[AbsoluteIndex(index)];
369 }
370 const_reference at(size_type index) const {
371 PW_ASSERT(index < size());
372 return data()[AbsoluteIndex(index)];
373 }
374
375 reference operator[](size_type index) {
376 PW_DASSERT(index < size());
377 return data()[AbsoluteIndex(index)];
378 }
379 const_reference operator[](size_type index) const {
380 PW_DASSERT(index < size());
381 return data()[AbsoluteIndex(index)];
382 }
383
384 reference front() {
385 PW_DASSERT(!empty());
386 return data()[head_];
387 }
388 const_reference front() const {
389 PW_DASSERT(!empty());
390 return data()[head_];
391 }
392
393 reference back() {
394 PW_DASSERT(!empty());
395 return data()[AbsoluteIndex(size() - 1)];
396 }
397 const_reference back() const {
398 PW_DASSERT(!empty());
399 return data()[AbsoluteIndex(size() - 1)];
400 }
401
402 // Provides access to the valid data in a contiguous form.
403 std::pair<span<const value_type>, span<const value_type>> contiguous_data()
404 const;
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()));
411 }
412
413 // Iterate
414
415 iterator begin() noexcept {
416 if (empty()) {
417 return end();
418 }
419
420 return iterator(this, 0);
421 }
422 const_iterator begin() const noexcept { return cbegin(); }
423 const_iterator cbegin() const noexcept {
424 if (empty()) {
425 return cend();
426 }
427 return const_iterator(this, 0);
428 }
429
430 iterator end() noexcept {
431 return iterator(this, std::numeric_limits<size_type>::max());
432 }
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());
436 }
437
438 // Size
439
440 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
441
442 [[nodiscard]] bool full() const noexcept { return size() == max_size(); }
443
444 // Returns the number of elements in the `InlineDeque`. Disable MSAN since it
445 // thinks `count_` is uninitialized in the destructor.
446 size_type size() const noexcept PW_NO_SANITIZE("memory") { return count_; }
447
448 size_type max_size() const noexcept { return capacity(); }
449
450 // Returns the maximum number of elements in the `InlineDeque`. Disable MSAN
451 // since it thinks `capacity_` is uninitialized in the destructor.
452 size_type capacity() const noexcept PW_NO_SANITIZE("memory") {
453 return capacity_;
454 }
455
456 // Modify
457
458 void clear() noexcept;
459
460 void push_back(const value_type& value) { emplace_back(value); }
461
462 void push_back(value_type&& value) { emplace_back(std::move(value)); }
463
464 template <typename... Args>
465 void emplace_back(Args&&... args);
466
467 void pop_back();
468
469 void push_front(const value_type& value) { emplace_front(value); }
470
471 void push_front(value_type&& value) { emplace_front(std::move(value)); }
472
473 template <typename... Args>
474 void emplace_front(Args&&... args);
475
476 void pop_front();
477
478 void resize(size_type new_size) { resize(new_size, value_type()); }
479
480 void resize(size_type new_size, const value_type& value);
481
482 protected:
483 constexpr BasicInlineDeque(size_type capacity) noexcept
484 : capacity_(capacity), head_(0), tail_(0), count_(0) {}
485
486 // Polymorphic-sized `pw::InlineDeque<T>` may not be used with `unique_ptr`
487 // or `delete`. `delete` could be supported using C++20's destroying delete.
488 ~BasicInlineDeque() = default;
489
490 private:
491 friend class inline_circular_buffer_impl::InlineDequeIterator<
492 ValueType,
493 SizeType,
494 inline_circular_buffer_impl::Constness::kMutable>;
495 friend class inline_circular_buffer_impl::InlineDequeIterator<
496 ValueType,
497 SizeType,
498 inline_circular_buffer_impl::Constness::kConst>;
499
500 // The underlying RawStorage is not part of the generic-sized class. It is
501 // provided in the derived class from which this instance was constructed. To
502 // access the data, down-cast this to a known max size specialization, and
503 // return the RawStorage's data, which is the same for all sizes.
504 pointer data() {
505 return static_cast<BasicInlineDeque<value_type, size_type, 0>*>(this)
506 ->data();
507 }
508 const_pointer data() const {
509 return static_cast<const BasicInlineDeque<value_type, size_type, 0>*>(this)
510 ->data();
511 }
512
513 void IncrementWithWrap(size_type& index) const {
514 index++;
515 // Note: branch is faster than mod (%) on common embedded
516 // architectures.
517 if (index == max_size()) {
518 index = 0;
519 }
520 }
521
522 void DecrementWithWrap(size_type& index) const {
523 if (index == 0) {
524 index = max_size();
525 }
526 index--;
527 }
528
529 // Returns the absolute index based on the relative index beyond the
530 // head offset.
531 //
532 // Precondition: The relative index must be valid, i.e. < size().
533 //
534 // Disable MSAN since it thinks `head_` is uninitialized in the destructor.
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;
540 }
541 // Offset wrapped across the end of the circular buffer.
542 return absolute_index - max_size();
543 }
544
545 template <typename Iterator>
546 void CopyFrom(Iterator start, Iterator finish);
547
548 void Append(size_type count, const value_type& value);
549
550 const size_type capacity_;
551 size_type head_; // Non-inclusive offset for the front.
552 size_type tail_; // Non-inclusive offset for the back.
553 size_type count_;
554};
555
556// Function implementations
557
558template <typename ValueType, typename SizeType>
559std::pair<span<const ValueType>, span<const ValueType>>
560BasicInlineDeque<ValueType, SizeType>::contiguous_data() const {
561 if (empty()) {
562 return std::make_pair(span<const value_type>(), span<const value_type>());
563 }
564 if (tail_ > head_) {
565 // If the newest entry is after the oldest entry, we have not wrapped:
566 // [ |head_|...more_entries...|tail_| ]
567 return std::make_pair(span<const value_type>(&data()[head_], size()),
568 span<const value_type>());
569 } else {
570 // If the newest entry is before or at the oldest entry and we know we are
571 // not empty, ergo we have wrapped:
572 // [..more_entries...|tail_| |head_|...more_entries...]
573 return std::make_pair(
574 span<const value_type>(&data()[head_], max_size() - head_),
575 span<const value_type>(&data()[0], tail_));
576 }
577}
578
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) {
583 item.~value_type();
584 }
585 }
586 head_ = 0;
587 tail_ = 0;
588 count_ = 0;
589}
590
591template <typename ValueType, typename SizeType>
592template <typename... Args>
593void BasicInlineDeque<ValueType, SizeType>::emplace_back(Args&&... args) {
594 PW_ASSERT(!full());
595 PW_DASSERT(tail_ < capacity());
596 new (&data()[tail_]) value_type(std::forward<Args>(args)...);
597 IncrementWithWrap(tail_);
598 ++count_;
599}
600
601template <typename ValueType, typename SizeType>
602void BasicInlineDeque<ValueType, SizeType>::pop_back() {
603 PW_ASSERT(!empty());
604 PW_DASSERT(tail_ < capacity());
605 if constexpr (!std::is_trivially_destructible_v<value_type>) {
606 back().~value_type();
607 }
608 DecrementWithWrap(tail_);
609 --count_;
610}
611
612template <typename ValueType, typename SizeType>
613template <typename... Args>
614void BasicInlineDeque<ValueType, SizeType>::emplace_front(Args&&... args) {
615 PW_ASSERT(!full());
616 DecrementWithWrap(head_);
617 PW_DASSERT(head_ < capacity());
618 new (&data()[head_]) value_type(std::forward<Args>(args)...);
619 ++count_;
620}
621
622template <typename ValueType, typename SizeType>
623void BasicInlineDeque<ValueType, SizeType>::pop_front() {
624 PW_ASSERT(!empty());
625 PW_DASSERT(head_ < capacity());
626 if constexpr (!std::is_trivially_destructible_v<value_type>) {
627 front().~value_type();
628 }
629 IncrementWithWrap(head_);
630 --count_;
631}
632
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);
638 } else {
639 while (size() > new_size) {
640 pop_back();
641 }
642 }
643}
644
645template <typename ValueType, typename SizeType>
646template <typename Iterator>
647void BasicInlineDeque<ValueType, SizeType>::CopyFrom(Iterator start,
648 Iterator finish) {
649 while (start != finish) {
650 push_back(*start++);
651 }
652}
653
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) {
658 push_back(value);
659 }
660}
661
662namespace inline_circular_buffer_impl {
663
664// InlineDequeIterator meets the named requirements for
665// LegacyRandomAccessIterator
666template <typename ValueType, typename SizeType, Constness kIsConst>
667class InlineDequeIterator {
668 public:
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
678 reference;
679 typedef
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;
685
686 constexpr InlineDequeIterator() = default;
687 constexpr InlineDequeIterator(container_type* container, size_type pos)
688 : container_(container), pos_(pos) {}
689
690 constexpr InlineDequeIterator(const InlineDequeIterator& other) = default;
691 constexpr InlineDequeIterator& operator=(const InlineDequeIterator& other) =
692 default;
693
694 operator InlineDequeIterator<ValueType, SizeType, Constness::kConst>() const {
695 return {container_, pos_};
696 }
697
698 constexpr InlineDequeIterator& Incr(difference_type n) {
699 const difference_type new_pos =
700 n + (pos_ == kEnd ? container_->size() : pos_);
701
702 PW_DASSERT(new_pos >= 0);
703 PW_DASSERT(new_pos <= container_->size());
704
705 pos_ =
706 new_pos == container_->size() ? kEnd : static_cast<size_type>(new_pos);
707
708 return *this;
709 }
710
711 constexpr InlineDequeIterator& operator+=(difference_type n) {
712 return Incr(n);
713 }
714 constexpr InlineDequeIterator& operator-=(difference_type n) {
715 return Incr(-n);
716 }
717 constexpr InlineDequeIterator& operator++() { return Incr(1); }
718 constexpr InlineDequeIterator operator++(int) {
719 InlineDequeIterator it(*this);
720 operator++();
721 return it;
722 }
723
724 constexpr InlineDequeIterator& operator--() { return Incr(-1); }
725 constexpr InlineDequeIterator operator--(int) {
726 InlineDequeIterator it = *this;
727 operator--();
728 return it;
729 }
730
731 constexpr friend InlineDequeIterator operator+(InlineDequeIterator it,
732 difference_type n) {
733 return it += n;
734 }
735 constexpr friend InlineDequeIterator operator+(difference_type n,
736 InlineDequeIterator it) {
737 return it += n;
738 }
739
740 constexpr friend InlineDequeIterator operator-(InlineDequeIterator it,
741 difference_type n) {
742 return it -= n;
743 }
744
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()
748 : a.pos_) -
749 static_cast<difference_type>(b.pos_ == kEnd ? b.container_->size()
750 : b.pos_);
751 }
752
753 constexpr reference operator*() const {
754 PW_DASSERT(pos_ != kEnd);
755 PW_DASSERT(pos_ < container_->size());
756
757 return container_->at(pos_);
758 }
759
760 constexpr pointer operator->() const {
761 PW_DASSERT(pos_ != kEnd);
762 PW_DASSERT(pos_ < container_->size());
763
764 return &**this;
765 }
766
767 constexpr reference operator[](size_type n) { return *(*this + n); }
768
769 constexpr bool operator==(const InlineDequeIterator& other) const {
770 return container_ == other.container_ && pos_ == other.pos_;
771 }
772
773 constexpr bool operator!=(const InlineDequeIterator& other) const {
774 return !(*this == other);
775 }
776
777 constexpr friend bool operator<(InlineDequeIterator a,
778 InlineDequeIterator b) {
779 return b - a > 0;
780 }
781
782 constexpr friend bool operator>(InlineDequeIterator a,
783 InlineDequeIterator b) {
784 return b < a;
785 }
786
787 constexpr friend bool operator<=(InlineDequeIterator a,
789 return !(a > b);
790 }
791
792 constexpr friend bool operator>=(InlineDequeIterator a,
793 InlineDequeIterator b) {
794 return !(a < b);
795 }
796
797 private:
798 static constexpr size_type kEnd = std::numeric_limits<size_type>::max();
799 container_type* container_; // pointer to container this iterator is from
800 size_type pos_; // logical index of iterator
801};
802
803} // namespace inline_circular_buffer_impl
804} // namespace pw
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
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
Definition: constexpr_tag.h:46