RPNX::DataStructures
Header-only C++ data structures and supporting utilities.
Loading...
Searching...
No Matches
segmented_dynar.hpp
1// Copyright (c) 2026 Ryan P. Nicholl <rnicholl@protonmail.com>
2// SPDX-License-Identifier: Apache-2.0
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef RPNX_SEGMENTED_DYNAR_HPP
16#define RPNX_SEGMENTED_DYNAR_HPP
17#include <bit>
18#include <cassert>
19#include <limits>
20#include <memory>
21#include <stdexcept>
22
23namespace rpnx
24{
43 template < typename T, typename Alloc = std::allocator< T > >
45 {
46 // Segmented Dynamic array using fixed-size segments of exponential sizes
47 private:
48 std::size_t m_size = 0;
49 std::size_t m_capacity = 0;
50 T** m_segments = nullptr;
51 [[no_unique_address]] Alloc m_alloc;
52
53 static constexpr std::size_t index_segment(std::size_t index) noexcept
54 {
55 if (index == 0 || index == 1)
56 {
57 return 0;
58 }
59
60 return std::bit_width(index) - 1;
61 }
62
63 static constexpr std::size_t index_subindex(std::size_t index) noexcept
64 {
65 if (index == 0 || index == 1)
66 {
67 return index;
68 }
69
70 std::size_t segment = index_segment(index);
71 std::size_t base_index = std::size_t{1} << segment;
72 return index - base_index;
73 }
74
75 static constexpr std::size_t capacity_segment_count(std::size_t capacity) noexcept
76 {
77 if (capacity == 0)
78 {
79 return 0;
80 }
81 if (capacity == 1)
82 {
83 return 1;
84 }
85 return std::bit_width(capacity - 1);
86 }
87
88 static_assert(capacity_segment_count(1) == 1);
89
90 static constexpr std::size_t segment_count_total_capacity(std::size_t segment_count) noexcept
91 {
92 if (segment_count == 0)
93 {
94 return 0;
95 }
96 return (std::size_t{1} << segment_count);
97 }
98
99 static constexpr std::size_t segment_size(std::size_t segment_index)
100 {
101 if (segment_index == 0 || segment_index == 1)
102 {
103 return 2;
104 }
105 return (std::size_t{1} << segment_index);
106 }
107
108 static_assert(segment_size(0) == 2);
109 static_assert(segment_size(1) == 2);
110 static_assert(segment_size(2) == 4);
111
112 static_assert(capacity_segment_count(0) == 0);
113 static_assert(segment_count_total_capacity(0) == 0);
114 static_assert(segment_size(0) == 2);
115
116 static_assert(capacity_segment_count(2) == 1);
117 static_assert(segment_count_total_capacity(1) == 2);
118 static_assert(segment_size(1) == 2);
119
120 static_assert(capacity_segment_count(4) == 2);
121 static_assert(segment_count_total_capacity(2) == 4);
122 static_assert(segment_size(2) == 4);
123
124 static_assert(capacity_segment_count(8) == 3);
125 static_assert(segment_count_total_capacity(3) == 8);
126 static_assert(segment_size(3) == 8);
127
128 static_assert(capacity_segment_count(16) == 4);
129 static_assert(segment_count_total_capacity(4) == 16);
130 static_assert(segment_size(4) == 16);
131
132 static_assert(index_segment(0) == 0);
133 static_assert(index_segment(1) == 0);
134 static_assert(index_segment(2) == 1);
135 static_assert(index_segment(3) == 1);
136 static_assert(index_segment(4) == 2);
137 static_assert(index_segment(5) == 2);
138 static_assert(index_segment(6) == 2);
139 static_assert(index_segment(7) == 2);
140 static_assert(index_segment(8) == 3);
141 static_assert(index_segment(9) == 3);
142 static_assert(index_segment(15) == 3);
143 static_assert(index_segment(16) == 4);
144
145 static_assert(index_subindex(0) == 0);
146 static_assert(index_subindex(1) == 1);
147 static_assert(index_subindex(2) == 0);
148 static_assert(index_subindex(3) == 1);
149 static_assert(index_subindex(4) == 0);
150 static_assert(index_subindex(5) == 1);
151
152 public:
154 segmented_dynar() = default;
155
157 explicit segmented_dynar(const Alloc& a) noexcept : m_alloc(a)
158 {
159 }
160
162 Alloc get_allocator() const noexcept
163 {
164 return m_alloc;
165 }
166
168 std::size_t capacity() const
169 {
170 return m_capacity;
171 }
172
174 std::size_t size() const
175 {
176 return m_size;
177 }
178
186 void reserve(std::size_t new_capacity)
187 {
188 using segment_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T* >;
189 using segment_alloc_traits = std::allocator_traits< segment_allocator_type >;
190 if (new_capacity <= m_capacity)
191 {
192 return;
193 }
194 if (new_capacity > (std::size_t{1} << (std::numeric_limits< std::size_t >::digits - 1)))
195 {
196 throw std::length_error("segmented_dynar::reserve: requested capacity is too large");
197 }
198 std::size_t old_segment_count = capacity_segment_count(m_capacity);
199 std::size_t new_segment_count = capacity_segment_count(new_capacity);
200 segment_allocator_type typed_allocator(m_alloc);
201 T** new_segments = segment_alloc_traits::allocate(typed_allocator, new_segment_count);
202
203 using element_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
204 using element_alloc_traits = std::allocator_traits< element_allocator_type >;
205 element_allocator_type elem_alloc(m_alloc);
206 try
207 {
208 for (std::size_t i = 0; i < old_segment_count; ++i)
209 {
210 new_segments[i] = m_segments[i];
211 }
212 for (std::size_t i = old_segment_count; i < new_segment_count; ++i)
213 {
214 new_segments[i] = nullptr;
215 }
216 for (std::size_t i = old_segment_count; i < new_segment_count; ++i)
217 {
218 new_segments[i] = element_alloc_traits::allocate(elem_alloc, segment_size(i));
219 }
220 if (m_segments != nullptr)
221 {
222 segment_alloc_traits::deallocate(typed_allocator, m_segments, old_segment_count);
223 }
224 }
225 catch (...)
226 {
227 for (std::size_t i = old_segment_count; i < new_segment_count; ++i)
228 {
229 if (new_segments[i] != nullptr)
230 {
231 element_alloc_traits::deallocate(elem_alloc, new_segments[i], segment_size(i));
232 }
233 }
234 segment_alloc_traits::deallocate(typed_allocator, new_segments, new_segment_count);
235 throw;
236 }
237 m_segments = new_segments;
238 m_capacity = segment_count_total_capacity(new_segment_count);
239 }
240
246 void push_back(T value)
247 {
248 if (size() >= capacity())
249 {
250 reserve(capacity() + 1);
251 }
252 std::size_t insertion_index = m_size;
253 assert(capacity() > insertion_index);
254 std::size_t segment_index = index_segment(insertion_index);
255 std::size_t sub_index = index_subindex(insertion_index);
256
257 using element_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
258 using element_alloc_traits = std::allocator_traits< element_allocator_type >;
259 element_allocator_type elem_alloc(m_alloc);
260 T*& segment = m_segments[segment_index];
261 assert(sub_index < segment_size(segment_index));
262 assert(segment != nullptr);
263 element_alloc_traits::construct(elem_alloc, &segment[sub_index], std::move(value));
264 ++m_size;
265 }
266
268 T& operator[](std::size_t index)
269 {
270 std::size_t segment_index = index_segment(index);
271 std::size_t sub_index = index_subindex(index);
272 return m_segments[segment_index][sub_index];
273 }
274
276 T const& operator[](std::size_t index) const
277 {
278 std::size_t segment_index = index_segment(index);
279 std::size_t sub_index = index_subindex(index);
280 return m_segments[segment_index][sub_index];
281 }
282
284 T& at(std::size_t index)
285 {
286 if (index >= size())
287 {
288 throw std::out_of_range("segmented_dynar::at: index out of range");
289 }
290 return (*this)[index];
291 }
292
294 T const& at(std::size_t index) const
295 {
296 if (index >= size())
297 {
298 throw std::out_of_range("segmented_dynar::at: index out of range");
299 }
300 return (*this)[index];
301 }
302
304 T& front()
305 {
306 return (*this)[0];
307 }
308
310 T const& front() const
311 {
312 return (*this)[0];
313 }
314
316 T& back()
317 {
318 return (*this)[m_size - 1];
319 }
320
322 T const& back() const
323 {
324 return (*this)[m_size - 1];
325 }
326
328 void assign(std::size_t count, const T& value)
329 {
330 clear();
331 reserve(count);
332 for (std::size_t i = 0; i < count; ++i)
333 {
334 push_back(value);
335 }
336 }
337
345 template < typename InputIt, typename = std::enable_if_t< !std::is_integral_v< InputIt > > >
346 void assign(InputIt first, InputIt last)
347 {
348 clear();
349 if constexpr (std::is_base_of_v< std::forward_iterator_tag, typename std::iterator_traits< InputIt >::iterator_category >)
350 {
351 reserve(std::distance(first, last));
352 }
353 for (; first != last; ++first)
354 {
355 push_back(*first);
356 }
357 }
358
360 void assign(std::initializer_list< T > ilist)
361 {
362 assign(ilist.begin(), ilist.end());
363 }
364
366 void pop_back()
367 {
368 --m_size;
369 std::size_t segment_index = index_segment(m_size);
370 std::size_t sub_index = index_subindex(m_size);
371 using element_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
372 using element_alloc_traits = std::allocator_traits< element_allocator_type >;
373 element_allocator_type elem_alloc(m_alloc);
374 T*& segment = m_segments[segment_index];
375 element_alloc_traits::destroy(elem_alloc, &segment[sub_index]);
376 }
377
383 {
384 std::size_t required_segment_count = capacity_segment_count(m_size);
385 if (required_segment_count < capacity_segment_count(m_capacity))
386 {
387 using segment_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T* >;
388 using segment_alloc_traits = std::allocator_traits< segment_allocator_type >;
389 segment_allocator_type segment_allocator(m_alloc);
390
391 using element_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
392 using element_alloc_traits = std::allocator_traits< element_allocator_type >;
393 element_allocator_type elem_alloc(m_alloc);
394
395 if (required_segment_count == 0)
396 {
397 for (std::size_t i = 0; i < capacity_segment_count(m_capacity); ++i)
398 {
399 elem_alloc.deallocate(m_segments[i], segment_size(i));
400 }
401 segment_allocator.deallocate(m_segments, capacity_segment_count(m_capacity));
402 m_segments = nullptr;
403 m_capacity = 0;
404 return;
405 }
406 T** new_segments = segment_alloc_traits::allocate(segment_allocator, required_segment_count);
407 for (std::size_t i = 0; i < required_segment_count; ++i)
408 {
409 new_segments[i] = m_segments[i];
410 }
411 for (std::size_t i = required_segment_count; i < capacity_segment_count(m_capacity); ++i)
412 {
413 elem_alloc.deallocate(m_segments[i], segment_size(i));
414 }
415 segment_allocator.deallocate(m_segments, capacity_segment_count(m_capacity));
416 m_segments = new_segments;
417 m_capacity = segment_count_total_capacity(required_segment_count);
418 }
419 }
420
422 void clear()
423 {
424 while (size() > 0)
425 {
426 pop_back();
427 }
428 }
429
431 void reset()
432 {
433 clear();
435 }
436
439 {
440 reset();
441 }
442
450 template < typename... Args >
451 T& emplace_back(Args&&... args)
452 {
453 if (size() >= capacity())
454 {
455 reserve(capacity() + 1);
456 }
457 std::size_t insertion_index = m_size;
458 assert(capacity() > insertion_index);
459 std::size_t segment_index = index_segment(insertion_index);
460 std::size_t sub_index = index_subindex(insertion_index);
461 using element_allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
462 using element_alloc_traits = std::allocator_traits< element_allocator_type >;
463 element_allocator_type elem_alloc(m_alloc);
464 T*& segment = m_segments[segment_index];
465 assert(sub_index < segment_size(segment_index));
466 assert(segment != nullptr);
467 element_alloc_traits::construct(elem_alloc, &segment[sub_index], std::forward< Args >(args)...);
468 ++m_size;
469 return segment[sub_index];
470 }
471
473 segmented_dynar(segmented_dynar&& other) noexcept : m_size(other.m_size), m_capacity(other.m_capacity), m_segments(other.m_segments), m_alloc(std::move(other.m_alloc))
474 {
475 other.m_size = 0;
476 other.m_capacity = 0;
477 other.m_segments = nullptr;
478 }
479
482 {
483 if (this != &other)
484 {
485 reset();
486 m_size = other.m_size;
487 m_capacity = other.m_capacity;
488 m_segments = other.m_segments;
489 m_alloc = std::move(other.m_alloc);
490
491 other.m_size = 0;
492 other.m_capacity = 0;
493 other.m_segments = nullptr;
494 }
495 return *this;
496 }
497
499 segmented_dynar(const segmented_dynar& other) : m_alloc(std::allocator_traits< Alloc >::select_on_container_copy_construction(other.m_alloc))
500 {
501 reserve(other.m_size);
502 for (std::size_t i = 0; i < other.m_size; ++i)
503 {
504 push_back(other[i]);
505 }
506 }
507
510 {
511 if (this != &other)
512 {
513 if constexpr (std::allocator_traits< Alloc >::propagate_on_container_copy_assignment::value)
514 {
515 if (m_alloc != other.m_alloc)
516 {
517 reset();
518 }
519 m_alloc = other.m_alloc;
520 }
521 clear();
522 reserve(other.m_size);
523 for (std::size_t i = 0; i < other.m_size; ++i)
524 {
525 push_back(other[i]);
526 }
527 }
528 return *this;
529 }
530
538 template < bool Const >
540 {
541 public:
543 using iterator_category = std::random_access_iterator_tag;
545 using difference_type = std::ptrdiff_t;
547 using value_type = T;
549 using pointer = std::conditional_t< Const, T const*, T* >;
551 using reference = std::conditional_t< Const, T const&, T& >;
553 using container_ptr = std::conditional_t< Const, const segmented_dynar*, segmented_dynar* >;
554
555 private:
556 container_ptr m_container = nullptr;
557 std::size_t m_global_index = 0;
558 pointer m_ptr = nullptr;
559 pointer m_seg_begin = nullptr;
560 pointer m_seg_end = nullptr;
561
562 void load_segment_cache()
563 {
564 if (m_global_index == m_container->size())
565 {
566 m_ptr = nullptr;
567 return;
568 }
569
570 std::size_t seg_idx = index_segment(m_global_index);
571 std::size_t sub_idx = index_subindex(m_global_index);
572
573 pointer segment_base = m_container->m_segments[seg_idx];
574 std::size_t seg_sz = segment_size(seg_idx);
575
576 m_ptr = segment_base + sub_idx;
577 m_seg_begin = segment_base;
578 m_seg_end = segment_base + seg_sz;
579 }
580
581 public:
583 iterator_impl() = default;
584
586 iterator_impl(container_ptr container, std::size_t index) : m_container(container), m_global_index(index)
587 {
588 if (container && index < container->size())
589 {
590 load_segment_cache();
591 }
592 }
593
595 template < bool Const2, typename = std::enable_if_t< Const && !Const2 > >
596 iterator_impl(const iterator_impl< Const2 >& other) : m_container(other.m_container), m_global_index(other.m_global_index), m_ptr(other.m_ptr), m_seg_begin(other.m_seg_begin), m_seg_end(other.m_seg_end)
597 {
598 }
599
602 {
603 return *m_ptr;
604 }
605
607 {
608 return m_ptr;
609 }
610
613 {
614 ++m_ptr;
615 ++m_global_index;
616 if (m_ptr == m_seg_end)
617 {
618 load_segment_cache();
619 }
620 return *this;
621 }
622
625 {
626 iterator_impl temp = *this;
627 ++(*this);
628 return temp;
629 }
630
633 {
634 if (m_ptr == m_seg_begin || m_global_index == m_container->size())
635 {
636 --m_global_index;
637 load_segment_cache();
638 }
639 else
640 {
641 --m_ptr;
642 --m_global_index;
643 }
644 return *this;
645 }
646
649 {
650 iterator_impl temp = *this;
651 --(*this);
652 return temp;
653 }
654
657 {
658 if (n == 0)
659 return *this;
660
661 if (m_ptr)
662 {
663 if (n > 0 && (m_ptr + n < m_seg_end))
664 {
665 m_ptr += n;
666 m_global_index += n;
667 return *this;
668 }
669 else if (n < 0 && (m_ptr + n >= m_seg_begin))
670 {
671 m_ptr += n;
672 m_global_index += n;
673 return *this;
674 }
675 }
676
677 m_global_index += n;
678 load_segment_cache();
679 return *this;
680 }
681
684 {
685 return *this += (-n);
686 }
687
690 {
691 iterator_impl temp = *this;
692 temp += n;
693 return temp;
694 }
695
698 {
699 iterator_impl temp = *this;
700 temp -= n;
701 return temp;
702 }
703
706 {
707 return static_cast< difference_type >(m_global_index) - static_cast< difference_type >(other.m_global_index);
708 }
709
712 {
713 return static_cast< difference_type >(m_global_index) - static_cast< difference_type >(other.m_global_index);
714 }
715
718 {
719 return *(*this + n);
720 }
721
723 bool operator==(const iterator_impl< true >& other) const
724 {
725 return m_global_index == other.m_global_index;
726 }
727
729 bool operator==(const iterator_impl< false >& other) const
730 {
731 return m_global_index == other.m_global_index;
732 }
733
735 bool operator!=(const iterator_impl< true >& other) const
736 {
737 return !(*this == other);
738 }
739
740 bool operator!=(const iterator_impl< false >& other) const
741 {
742 return !(*this == other);
743 }
744
745 bool operator<(const iterator_impl< true >& other) const
746 {
747 return m_global_index < other.m_global_index;
748 }
749
750 bool operator<(const iterator_impl< false >& other) const
751 {
752 return m_global_index < other.m_global_index;
753 }
754
755 bool operator>(const iterator_impl< true >& other) const
756 {
757 return m_global_index > other.m_global_index;
758 }
759
760 bool operator>(const iterator_impl< false >& other) const
761 {
762 return m_global_index > other.m_global_index;
763 }
764
765 bool operator<=(const iterator_impl< true >& other) const
766 {
767 return m_global_index <= other.m_global_index;
768 }
769
770 bool operator<=(const iterator_impl< false >& other) const
771 {
772 return m_global_index <= other.m_global_index;
773 }
774
775 bool operator>=(const iterator_impl< true >& other) const
776 {
777 return m_global_index >= other.m_global_index;
778 }
779
780 bool operator>=(const iterator_impl< false >& other) const
781 {
782 return m_global_index >= other.m_global_index;
783 }
784
785 friend class iterator_impl< !Const >;
786 friend class segmented_dynar;
787 };
788
793
796 {
797 return iterator(this, 0);
798 }
799
801 {
802 return iterator(this, m_size);
803 }
804
806 {
807 return const_iterator(this, 0);
808 }
809
811 {
812 return const_iterator(this, m_size);
813 }
814
816 {
817 return begin();
818 }
819
821 {
822 return end();
823 }
824 };
825} // namespace rpnx
826#endif
pointer operator->() const
Accesses the current element.
Definition segmented_dynar.hpp:606
iterator_impl(container_ptr container, std::size_t index)
Constructs an iterator at a logical index.
Definition segmented_dynar.hpp:586
std::conditional_t< Const, T const *, T * > pointer
Mutable or immutable element pointer type.
Definition segmented_dynar.hpp:549
iterator_impl & operator++()
Advances one element.
Definition segmented_dynar.hpp:612
bool operator>=(const iterator_impl< false > &other) const
Tests whether this index does not precede a mutable iterator.
Definition segmented_dynar.hpp:780
bool operator<=(const iterator_impl< true > &other) const
Tests whether this index does not follow an immutable iterator.
Definition segmented_dynar.hpp:765
iterator_impl & operator--()
Retreats one element.
Definition segmented_dynar.hpp:632
iterator_impl operator+(difference_type n) const
Returns an iterator moved by an offset.
Definition segmented_dynar.hpp:689
bool operator>=(const iterator_impl< true > &other) const
Tests whether this index does not precede an immutable iterator.
Definition segmented_dynar.hpp:775
iterator_impl operator--(int)
Retreats one element.
Definition segmented_dynar.hpp:648
iterator_impl(const iterator_impl< Const2 > &other)
Converts a mutable iterator to an immutable iterator.
Definition segmented_dynar.hpp:596
T value_type
Iterated element type.
Definition segmented_dynar.hpp:547
bool operator!=(const iterator_impl< false > &other) const
Compares with a mutable iterator for inequality.
Definition segmented_dynar.hpp:740
bool operator<(const iterator_impl< true > &other) const
Tests whether this index precedes an immutable iterator.
Definition segmented_dynar.hpp:745
std::conditional_t< Const, T const &, T & > reference
Mutable or immutable element reference type.
Definition segmented_dynar.hpp:551
bool operator==(const iterator_impl< false > &other) const
Compares with a mutable iterator for equality.
Definition segmented_dynar.hpp:729
bool operator<=(const iterator_impl< false > &other) const
Tests whether this index does not follow a mutable iterator.
Definition segmented_dynar.hpp:770
bool operator<(const iterator_impl< false > &other) const
Tests whether this index precedes a mutable iterator.
Definition segmented_dynar.hpp:750
reference operator*() const
Dereferences the current position.
Definition segmented_dynar.hpp:601
iterator_impl & operator+=(difference_type n)
Moves by a signed offset.
Definition segmented_dynar.hpp:656
std::conditional_t< Const, const segmented_dynar *, segmented_dynar * > container_ptr
Pointer to the mutable or immutable owning container.
Definition segmented_dynar.hpp:553
iterator_impl operator++(int)
Advances one element.
Definition segmented_dynar.hpp:624
bool operator>(const iterator_impl< false > &other) const
Tests whether this index follows a mutable iterator.
Definition segmented_dynar.hpp:760
bool operator!=(const iterator_impl< true > &other) const
Compares with an immutable iterator for inequality.
Definition segmented_dynar.hpp:735
std::ptrdiff_t difference_type
Signed iterator-distance type.
Definition segmented_dynar.hpp:545
iterator_impl()=default
Constructs a singular iterator.
bool operator>(const iterator_impl< true > &other) const
Tests whether this index follows an immutable iterator.
Definition segmented_dynar.hpp:755
difference_type operator-(const iterator_impl< false > &other) const
Computes distance from a mutable iterator.
Definition segmented_dynar.hpp:711
iterator_impl & operator-=(difference_type n)
Moves backward by a signed offset.
Definition segmented_dynar.hpp:683
bool operator==(const iterator_impl< true > &other) const
Compares with an immutable iterator for equality.
Definition segmented_dynar.hpp:723
reference operator[](difference_type n) const
Dereferences an offset position.
Definition segmented_dynar.hpp:717
iterator_impl operator-(difference_type n) const
Returns an iterator moved backward by an offset.
Definition segmented_dynar.hpp:697
difference_type operator-(const iterator_impl< true > &other) const
Computes distance from an immutable iterator.
Definition segmented_dynar.hpp:705
std::random_access_iterator_tag iterator_category
Iterator category for legacy algorithms.
Definition segmented_dynar.hpp:543
iterator_impl< true > const_iterator
Immutable random-access iterator type.
Definition segmented_dynar.hpp:792
void reserve(std::size_t new_capacity)
Ensures capacity for at least a requested number of elements.
Definition segmented_dynar.hpp:186
~segmented_dynar()
Destroys all elements and releases all segments.
Definition segmented_dynar.hpp:438
const_iterator cend() const
Returns an immutable iterator one past the final element.
Definition segmented_dynar.hpp:820
void clear()
Destroys all elements while retaining allocated segments.
Definition segmented_dynar.hpp:422
iterator begin()
Returns an iterator to the first element.
Definition segmented_dynar.hpp:795
const_iterator end() const
Returns an immutable iterator one past the final element.
Definition segmented_dynar.hpp:810
segmented_dynar & operator=(segmented_dynar &&other) noexcept
Move-assigns by taking ownership of all segments.
Definition segmented_dynar.hpp:481
T const & back() const
Returns the final element.
Definition segmented_dynar.hpp:322
T & front()
Returns the first element.
Definition segmented_dynar.hpp:304
iterator end()
Returns an iterator one past the final element.
Definition segmented_dynar.hpp:800
iterator_impl< false > iterator
Mutable random-access iterator type.
Definition segmented_dynar.hpp:790
void assign(std::initializer_list< T > ilist)
Replaces the contents from an initializer list.
Definition segmented_dynar.hpp:360
T & back()
Returns the final element.
Definition segmented_dynar.hpp:316
void reset()
Destroys all elements and releases all allocated storage.
Definition segmented_dynar.hpp:431
std::size_t size() const
Returns the number of constructed elements.
Definition segmented_dynar.hpp:174
T const & front() const
Returns the first element.
Definition segmented_dynar.hpp:310
segmented_dynar(segmented_dynar &&other) noexcept
Move-constructs by taking ownership of all segments.
Definition segmented_dynar.hpp:473
segmented_dynar & operator=(const segmented_dynar &other)
Copy-assigns every element subject to allocator propagation rules.
Definition segmented_dynar.hpp:509
T & operator[](std::size_t index)
Accesses an element without bounds checking.
Definition segmented_dynar.hpp:268
void pop_back()
Destroys the final element.
Definition segmented_dynar.hpp:366
segmented_dynar()=default
Constructs an empty container with a default-constructed allocator.
T const & at(std::size_t index) const
Accesses an element with bounds checking.
Definition segmented_dynar.hpp:294
segmented_dynar(const Alloc &a) noexcept
Constructs an empty container with an allocator.
Definition segmented_dynar.hpp:157
void assign(std::size_t count, const T &value)
Replaces the contents with repeated copies.
Definition segmented_dynar.hpp:328
std::size_t capacity() const
Returns the number of elements that fit in allocated segments.
Definition segmented_dynar.hpp:168
void push_back(T value)
Appends an element by value.
Definition segmented_dynar.hpp:246
segmented_dynar(const segmented_dynar &other)
Copy-constructs every element.
Definition segmented_dynar.hpp:499
T const & operator[](std::size_t index) const
Accesses an element without bounds checking.
Definition segmented_dynar.hpp:276
T & emplace_back(Args &&... args)
Constructs an element at the end of the container.
Definition segmented_dynar.hpp:451
void assign(InputIt first, InputIt last)
Replaces the contents with an iterator range.
Definition segmented_dynar.hpp:346
const_iterator cbegin() const
Returns an immutable iterator to the first element.
Definition segmented_dynar.hpp:815
Alloc get_allocator() const noexcept
Returns the allocator associated with the container.
Definition segmented_dynar.hpp:162
void shrink_to_fit()
Releases segments that are not needed for the current size.
Definition segmented_dynar.hpp:382
const_iterator begin() const
Returns an immutable iterator to the first element.
Definition segmented_dynar.hpp:805
T & at(std::size_t index)
Accesses an element with bounds checking.
Definition segmented_dynar.hpp:284
Containers, iterator adapters, callable wrappers, and value utilities.
Definition annex.hpp:14