HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
lean_vector.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
8#pragma once
9
10#include "utility/module.hpp"
11#include <bit>
12#include <new>
13#include <cstddef>
14#include <memory>
15#include <algorithm>
16#include <iterator>
17
18hi_warning_push();
19// C26450: You called an STL function '' with raw pointer... (stl.1)
20// Using an iterator requires a lot of code which will not make it safer.
21hi_warning_ignore_msvc(26459);
22
23namespace hi { inline namespace v1 {
24
29template<typename T>
31public:
32 using value_type = T;
33 using pointer = value_type *;
34 using const_pointer = value_type const *;
35 using reference = value_type&;
36 using const_reference = value_type const&;
37 using iterator = value_type *;
38 using const_iterator = value_type const *;
39 using reverse_iterator = std::reverse_iterator<iterator>;
40 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
41 using size_type = std::size_t;
42 using difference_type = std::ptrdiff_t;
43 using allocator_type = std::allocator<value_type>;
44
45 constexpr static size_t value_alignment = alignof(value_type);
46
49 constexpr allocator_type get_allocator() const noexcept
50 {
52 return allocator_type{};
53 }
54
57 constexpr lean_vector() noexcept = default;
58
62 {
63 clear();
65 }
66
75 {
76 hilet other_size = other.size();
77 hilet update = _reserve<false>(other_size);
78 std::uninitialized_copy_n(other.begin(), other_size, update.ptr);
79 _reserve_update(update, other_size);
80 }
81
89 lean_vector(lean_vector&& other) noexcept(std::is_nothrow_move_constructible_v<value_type>)
90 {
91 if (other._is_short()) {
92 hilet other_size = other._short_size();
93 std::uninitialized_move_n(other.begin(), other_size, begin());
94 other._set_short_size(0);
95 _set_short_size(other_size);
96
97 } else {
98 _ptr = std::exchange(other._ptr, nullptr);
99 _end = std::exchange(other._end, nullptr);
100 _cap = std::exchange(other._cap, nullptr);
101 }
102 }
103
112 {
113 hi_return_on_self_assignment(other);
114
115 hilet other_size = other.size();
116
117 clear();
118 hilet update = _reserve<false>(other_size);
119 std::uninitialized_copy_n(other.begin(), other_size, update.ptr);
120 _reserve_update(update, other_size);
121
122 return *this;
123 }
124
134 {
135 hi_return_on_self_assignment(other);
136
137 if (not _is_short() and not other._is_short()) {
138 std::swap(_ptr, other._ptr);
139 std::swap(_end, other._end);
140 std::swap(_cap, other._cap);
141
142 } else {
143 clear();
145
146 if (other._is_short()) {
147 hilet other_size = other._short_size();
148 std::uninitialized_move_n(other.begin(), other_size, _short_data());
149 _set_short_size(other_size);
150
151 } else {
152 _ptr = std::exchange(other._ptr, nullptr);
153 _end = std::exchange(other._end, nullptr);
154 _cap = std::exchange(other._cap, nullptr);
155 }
156 }
157
158 return *this;
159 }
160
161 void swap(lean_vector& other) noexcept
162 {
163 hilet this_is_short = this->_is_short();
164 hilet other_is_short = other._is_short();
165 if (this_is_short) {
166 // By moving other to tmp, we make other short.
168 other = std::move(*this);
169 *this = std::move(tmp);
170
171 } else if (other_is_short) {
172 // By moving this to tmp, we make this short.
173 lean_vector tmp = std::move(*this);
174 *this = std::move(other);
175 other = std::move(tmp);
176
177 } else {
178 std::swap(this->_ptr, other._ptr);
179 std::swap(this->_end, other._end);
180 std::swap(this->_cap, other._cap);
181 }
182 }
183
184 explicit lean_vector(size_type count)
185 {
186 if (count <= short_capacity()) {
187 std::uninitialized_value_construct_n(_short_data(), count);
188 _set_short_size(count);
189
190 } else {
191 hilet update = _reserve<false>(count);
192 std::uninitialized_value_construct_n(update.ptr, count);
193 _reserve_update(update, count);
194 }
195 }
196
197 lean_vector(size_type count, value_type const& value)
198 {
199 if (count <= short_capacity()) {
200 std::uninitialized_fill_n(_short_data(), count, value);
201 _set_short_size(count);
202
203 } else {
204 hilet update = _reserve<false>(count);
205 std::uninitialized_fill_n(update.ptr, count, value);
206 _reserve_update(update, count);
207 }
208 }
209
215 lean_vector(std::input_iterator auto first, std::input_iterator auto last)
216 {
217 insert(_short_data(), first, last);
218 }
219
225 {
226 insert(_short_data(), list.begin(), list.end());
227 }
228
234 void assign(size_type count, value_type const& value)
235 {
236 clear();
237 insert(begin(), count, value);
238 }
239
245 void assign(std::input_iterator auto first, std::input_iterator auto last)
246 {
247 clear();
248 insert(begin(), first, last);
249 }
250
256 {
257 clear();
258 insert(begin(), list.begin(), list.end());
259 }
260
265 [[nodiscard]] pointer data() noexcept
266 {
267 if (_is_short()) {
268 if (_short_size() == 0) {
269 return nullptr;
270 } else {
271 return _short_data();
272 }
273 } else {
274 if (_ptr == _end) {
275 return nullptr;
276 } else {
277 return _long_data();
278 }
279 }
280 }
281
286 [[nodiscard]] const_pointer data() const noexcept
287 {
288 return const_cast<lean_vector *>(this)->data();
289 }
290
296 [[nodiscard]] constexpr bool empty() const noexcept
297 {
298 if (_is_short()) {
299 return _short_size() == 0;
300 } else {
301 return _ptr == _end;
302 }
303 }
304
309 [[nodiscard]] constexpr size_type size() const noexcept
310 {
311 if (_is_short()) {
312 return _short_size();
313 } else {
314 hi_axiom(_ptr <= _end);
315 return truncate<size_type>(_long_size());
316 }
317 }
318
319 [[nodiscard]] constexpr size_type max_size() const noexcept
320 {
321 auto a = get_allocator();
323 }
324
327 [[nodiscard]] constexpr size_t short_capacity() const noexcept
328 {
329 if constexpr (std::endian::native == std::endian::little) {
330 // The first alignment can not be used.
331 return (sizeof(pointer) * 3 - alignof(value_type)) / sizeof(value_type);
332 } else {
333 // The last byte can not be used to store values.
334 return (sizeof(pointer) * 3 - 1) / sizeof(value_type);
335 }
336 }
337
342 [[nodiscard]] size_t capacity() const noexcept
343 {
344 if (_is_short()) {
345 return short_capacity();
346 } else {
347 return _long_capacity();
348 }
349 }
350
357 [[nodiscard]] reference at(size_type index)
358 {
359 hilet is_short = _is_short();
360 hilet size_ = is_short ? _short_size() : _long_size();
361 if (index < size_) {
362 return _begin_data(is_short)[index];
363 } else {
364 throw std::out_of_range("lean_vector::at()");
365 }
366 }
367
374 [[nodiscard]] const_reference at(size_type index) const
375 {
376 return const_cast<lean_vector *>(this)->at(index);
377 }
378
385 [[nodiscard]] reference operator[](size_type index) noexcept
386 {
387 hi_axiom(index < size());
388 return _begin_data(_is_short())[index];
389 }
390
397 [[nodiscard]] const_reference operator[](size_type index) const noexcept
398 {
399 return const_cast<lean_vector *>(this)->operator[](index);
400 }
401
407 [[nodiscard]] reference front() noexcept
408 {
409 hi_axiom(not empty());
410 return *_begin_data(_is_short());
411 }
412
418 [[nodiscard]] const_reference front() const noexcept
419 {
420 return const_cast<lean_vector *>(this)->front();
421 }
422
428 [[nodiscard]] reference back() noexcept
429 {
430 hi_axiom(not empty());
431 return *(_end_data(_is_short()) - 1);
432 }
433
439 [[nodiscard]] const_reference back() const noexcept
440 {
441 return const_cast<lean_vector *>(this)->back();
442 }
443
448 [[nodiscard]] iterator begin() noexcept
449 {
450 return _begin_data(_is_short());
451 }
452
457 [[nodiscard]] const_iterator begin() const noexcept
458 {
459 return _begin_data(_is_short());
460 }
461
466 [[nodiscard]] const_iterator cbegin() const noexcept
467 {
468 return begin();
469 }
470
475 [[nodiscard]] iterator end() noexcept
476 {
477 return _end_data(_is_short());
478 }
479
484 [[nodiscard]] const_iterator end() const noexcept
485 {
486 return const_cast<lean_vector *>(this)->end();
487 }
488
493 [[nodiscard]] const_iterator cend() const noexcept
494 {
495 return end();
496 }
497
502 void clear() noexcept
503 {
504 hilet is_short = _is_short();
505 std::destroy(_begin_data(is_short), _end_data(is_short));
506 _set_size(0, is_short);
507 }
508
517 void reserve(size_type new_capacity)
518 {
519 hilet update = _reserve<false>(new_capacity);
520 _reserve_update(update);
521 }
522
532 {
533 if (_is_short()) {
534 return;
535 }
536
537 hilet old_ptr = _ptr;
538 hilet old_size = size();
539 hilet old_capacity = capacity();
540
541 if (old_size <= short_capacity()) {
542 _set_short_size(old_size);
543 } else {
544 auto a = get_allocator();
546 _end = _ptr + old_size;
547 _cap = _ptr + old_size;
548 }
549
550 std::uninitialized_move_n(old_ptr, old_size, begin());
551 std::destroy_n(old_ptr, old_size);
552 auto a = get_allocator();
554 }
555
565 template<typename... Args>
566 iterator emplace(const_iterator pos, Args&&...args)
567 {
568 hilet index = pos - begin();
569 hilet new_size = size() + 1;
570
571 hilet update = _reserve<true>(new_size);
572 std::construct_at(update.end, std::forward<Args>(args)...);
573 _reserve_update(update, new_size);
574
575 hilet new_pos = begin() + index;
576 std::rotate(new_pos, end() - 1, end());
577 return new_pos;
578 }
579
589 iterator insert(const_iterator pos, value_type const& value)
590 {
591 hilet index = pos - begin();
592 hilet new_size = size() + 1;
593
594 hilet update = _reserve<true>(new_size);
595 std::uninitialized_copy_n(std::addressof(value), 1, update.end);
596 _reserve_update(update, new_size);
597
598 hilet new_pos = begin() + index;
599 std::rotate(new_pos, end() - 1, end());
600 return new_pos;
601 }
602
612 iterator insert(const_iterator pos, value_type&& value)
613 {
614 hilet index = pos - begin();
615 hilet new_size = size() + 1;
616
617 hilet update = _reserve<true>(new_size);
618 std::uninitialized_move_n(std::addressof(value), 1, update.end);
619 _reserve_update(update, new_size);
620
621 hilet new_pos = begin() + index;
622 std::rotate(new_pos, end() - 1, end());
623 return new_pos;
624 }
625
636 iterator insert(const_iterator pos, size_type count, value_type const& value)
637 {
638 hilet index = pos - begin();
639 hilet new_size = size() + count;
640
641 hilet update = _reserve<true>(new_size);
642 std::uninitialized_fill_n(update.end, count, value);
643 _reserve_update(update, new_size);
644
645 hilet new_pos = begin() + index;
646 std::rotate(new_pos, end() - count, end());
647 return new_pos;
648 }
649
660 iterator insert(const_iterator pos, std::input_iterator auto first, std::input_iterator auto last)
661 {
662 if constexpr (requires { std::distance(first, last); }) {
663 hilet n = std::distance(first, last);
664
665 hilet index = pos - begin();
666 hilet new_size = size() + n;
667
668 hilet update = _reserve<true>(new_size);
669 std::uninitialized_move_n(first, n, update.end);
670 _reserve_update(update, new_size);
671
672 hilet new_pos = begin() + index;
673 std::rotate(new_pos, end() - n, end());
674 return new_pos;
675
676 } else {
677 for (auto it = first; it != last; ++it) {
678 pos = insert(pos, *it) + 1;
679 }
680 }
681 }
682
692 iterator insert(const_iterator pos, std::initializer_list<value_type> list)
693 {
694 return insert(pos, list.begin(), list.end());
695 }
696
709 iterator erase(const_iterator pos)
710 {
711 hi_axiom(pos >= begin() and pos <= end());
712 hilet new_pos = begin() + std::distance(cbegin(), pos);
713 std::move(new_pos + 1, end(), new_pos);
714
715 hilet is_short = _is_short();
716 _set_size(size() - 1, is_short);
717 std::destroy_at(_end_data(is_short));
718 return new_pos;
719 }
720
733 iterator erase(const_iterator first, const_iterator last)
734 {
735 hilet first_ = begin() + std::distance(cbegin(), first);
736 hilet last_ = begin() + std::distance(cbegin(), last);
737 hilet n = std::distance(first_, last_);
738 std::move(last_, end(), first_);
739 std::destroy(end() - n, end());
740 _set_size(size() - n, _is_short());
741 return first_;
742 }
743
751 template<typename... Args>
752 reference emplace_back(Args&&...args)
753 {
754 hilet new_size = size() + 1;
755
756 hilet update = _reserve<true>(new_size);
757 hilet obj = std::construct_at(update.end, std::forward<Args>(args)...);
758 _reserve_update(update, new_size);
759
760 return *obj;
761 }
762
767 void push_back(value_type const& value)
768 {
769 hilet new_size = size() + 1;
770
771 hilet update = _reserve<true>(new_size);
772 std::uninitialized_copy_n(std::addressof(value), 1, update.end);
773 _reserve_update(update, new_size);
774 }
775
780 void push_back(value_type&& value)
781 {
782 hilet new_size = size() + 1;
783
784 hilet update = _reserve<true>(new_size);
785 std::uninitialized_move_n(std::addressof(value), 1, update.end);
786 _reserve_update(update, new_size);
787 }
788
795 void pop_back()
796 {
797 hi_axiom(not empty());
798
799 hilet is_short = _is_short();
800 _set_size(size() - 1, is_short);
801 std::destroy_at(_end_data(is_short));
802 }
803
814 void resize(size_type new_size)
815 {
816 if (hilet old_size = size(); new_size > old_size) {
817 hilet n = new_size - old_size;
818
819 hilet update = _reserve<true>(new_size);
820 std::uninitialized_value_construct_n(update.end, n);
821 _reserve_update(update, new_size);
822
823 } else {
824 hilet is_short = _is_short();
825 hilet n = old_size - new_size;
826 std::destroy(_end_data(is_short) - n, _end_data(is_short));
827 _set_size(new_size, is_short);
828 }
829 }
830
842 void resize(size_type new_size, value_type const& value)
843 {
844 if (hilet old_size = size(); new_size > old_size) {
845 hilet n = new_size - old_size;
846
847 hilet update = _reserve<true>(new_size);
848 std::uninitialized_fill_n(update.end, n, value);
849 _reserve_update(update, new_size);
850
851 } else {
852 hilet is_short = _is_short();
853 hilet n = old_size - new_size;
854 std::destroy(end() - n, end());
855 _set_size(new_size, is_short);
856 }
857 }
858
865 friend bool operator==(lean_vector const& lhs, lean_vector const& rhs) noexcept
866 {
867 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
868 }
869
876 friend auto operator<=>(lean_vector const& lhs, lean_vector const& rhs) noexcept
877 {
878 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
879 }
880
887 friend size_type erase(lean_vector& c, value_type const& value)
888 {
889 auto it = std::remove(c.begin(), c.end(), value);
890 auto r = std::distance(it, c.end());
891 c.erase(it, c.end());
892 return r;
893 }
894
901 template<typename Pred>
902 friend size_type erase(lean_vector& c, Pred pred)
903 {
904 auto it = std::remove(c.begin(), c.end(), pred);
905 auto r = std::distance(it, c.end());
906 c.erase(it, c.end());
907 return r;
908 }
909
910 friend void swap(lean_vector& lhs, lean_vector& rhs) noexcept
911 {
912 lhs.swap(rhs);
913 }
914
915private:
916 pointer _ptr = nullptr;
917 pointer _end = nullptr;
918 pointer _cap = nullptr;
919
920 [[nodiscard]] constexpr bool _is_short() const noexcept
921 {
922 if constexpr (std::endian::native == std::endian::little) {
923 if (_ptr == nullptr) {
924 return true;
925 } else {
926 return to_bool(to_int(_ptr) & 1);
927 }
928 } else {
929 if (_cap == nullptr) {
930 return true;
931 } else {
932 return to_bool(to_int(_cap) & 1);
933 }
934 }
935 }
936
937 [[nodiscard]] pointer _short_data() const noexcept
938 {
939 static_assert(alignof(value_type) <= alignof(pointer));
940
941 void *p = const_cast<lean_vector *>(this);
942 if constexpr (std::endian::native == std::endian::little) {
943 p = ceil(advance_bytes(p, 1), alignof(value_type));
944 }
945 return std::launder(static_cast<pointer>(p));
946 }
947
948 [[nodiscard]] pointer _long_data() const noexcept
949 {
950 return _ptr;
951 }
952
953 [[nodiscard]] constexpr size_type _short_size() const noexcept
954 {
955 if constexpr (std::endian::native == std::endian::little) {
956 if (_ptr == nullptr) {
957 return 0;
958 } else {
959 return (to_int(_ptr) >> 1) & 0x1f;
960 }
961 } else {
962 if (_cap == nullptr) {
963 return 0;
964 } else {
965 return (to_int(_cap) >> 1) & 0x1f;
966 }
967 }
968 }
969
970 [[nodiscard]] constexpr size_type _long_size() const noexcept
971 {
972 hi_axiom(_ptr <= _end);
973 return _end - _ptr;
974 }
975
976 [[nodiscard]] constexpr size_type _long_capacity() const noexcept
977 {
978 hi_axiom(_ptr <= _cap);
979 return _cap - _ptr;
980 }
981
982 void _set_short_size(size_t new_size) noexcept
983 {
984 constexpr auto mask = ~intptr_t{0xff};
985
986 new_size <<= 1;
987 new_size |= 1;
988 if constexpr (std::endian::native == std::endian::little) {
989 _ptr = to_ptr<pointer>((to_int(_ptr) & mask) | new_size);
990 } else {
991 _cap = to_ptr<pointer>((to_int(_cap) & mask) | new_size);
992 }
993 }
994
995 void _set_size(size_t new_size, bool is_short) noexcept
996 {
997 if (is_short) {
998 hi_axiom(new_size <= short_capacity());
999 _set_short_size(new_size);
1000 } else {
1001 _end = _ptr + new_size;
1002 }
1003 }
1004
1005 [[nodiscard]] pointer _begin_data(bool is_short) const noexcept
1006 {
1007 if (is_short) {
1008 return _short_data();
1009 } else {
1010 return _long_data();
1011 }
1012 }
1013
1014 [[nodiscard]] pointer _end_data(bool is_short) const noexcept
1015 {
1016 if (is_short) {
1017 return _short_data() + _short_size();
1018 } else {
1019 return _end;
1020 }
1021 }
1022
1023 struct _reserve_type {
1024 pointer ptr;
1025 pointer end;
1026 pointer cap;
1027 bool resized;
1028 bool is_short;
1029 };
1030
1035 template<bool ForInsert>
1036 [[nodiscard]] _reserve_type _reserve(size_type new_capacity) const
1037 {
1038 hilet is_short = _is_short();
1039 hilet capacity = is_short ? short_capacity() : _long_capacity();
1040 if (new_capacity <= capacity) {
1041 [[likely]] return {_begin_data(is_short), _end_data(is_short), nullptr, false, is_short};
1042 }
1043
1044 if constexpr (ForInsert) {
1045 auto next_capacity = capacity + capacity / 2;
1046 if (new_capacity > next_capacity) {
1047 next_capacity = new_capacity + new_capacity / 2;
1048 }
1049 new_capacity = next_capacity;
1050 }
1051
1052 auto a = get_allocator();
1053 hilet new_ptr = std::allocator_traits<allocator_type>::allocate(a, new_capacity);
1054
1055 hilet size_ = is_short ? _short_size() : _long_size();
1056 return {new_ptr, new_ptr + size_, new_ptr + new_capacity, true, false};
1057 }
1058
1059 void _reserve_update(_reserve_type update)
1060 {
1061 if (not update.resized) {
1062 return;
1063 }
1064
1065 hilet is_short = _is_short();
1066 hilet old_size = is_short ? _short_size() : _long_size();
1067 hilet old_ptr = is_short ? _short_data() : _long_data();
1068
1069 std::uninitialized_move_n(old_ptr, old_size, update.ptr);
1070 std::destroy_n(old_ptr, old_size);
1071
1072 if (not is_short) {
1073 auto a = get_allocator();
1074 std::allocator_traits<allocator_type>::deallocate(a, _long_data(), _long_capacity());
1075 }
1076
1077 _ptr = update.ptr;
1078 _end = update.end;
1079 _cap = update.cap;
1080 }
1081
1082 void _reserve_update(_reserve_type update, size_type new_size)
1083 {
1084 _reserve_update(update);
1085 _set_size(new_size, update.is_short);
1086 }
1087};
1088
1089template<std::input_iterator It, std::input_iterator ItEnd>
1090lean_vector(It first, ItEnd last) -> lean_vector<typename std::iterator_traits<It>::value_type>;
1091
1092}} // namespace hi::v1
1093
1094hi_warning_pop();
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
void * advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
Advance a pointer by a number of bytes.
Definition memory.hpp:191
geometry/margins.hpp
Definition cache.hpp:11
Lean-vector with (SVO) short-vector-optimization.
Definition lean_vector.hpp:30
lean_vector(lean_vector const &other)
Copy-construct a vector.
Definition lean_vector.hpp:74
iterator insert(const_iterator pos, std::input_iterator auto first, std::input_iterator auto last)
Insert new items.
Definition lean_vector.hpp:660
const_reference front() const noexcept
Get a const-reference to the first item in the vector.
Definition lean_vector.hpp:418
size_t capacity() const noexcept
Get the current capacity of the vector.
Definition lean_vector.hpp:342
reference back() noexcept
Get a reference to the last item in the vector.
Definition lean_vector.hpp:428
void push_back(value_type &&value)
Move an item to the end of the vector.
Definition lean_vector.hpp:780
const_iterator end() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:484
lean_vector & operator=(lean_vector &&other) noexcept
Move-assign a vector.
Definition lean_vector.hpp:133
void clear() noexcept
Remove all items from the vector.
Definition lean_vector.hpp:502
void push_back(value_type const &value)
Copy an item to the end of the vector.
Definition lean_vector.hpp:767
constexpr size_t short_capacity() const noexcept
The maximum number of items that can fit without allocation.
Definition lean_vector.hpp:327
lean_vector(std::initializer_list< value_type > list)
Construct a vector with the given initializer list.
Definition lean_vector.hpp:224
iterator end() noexcept
Get an iterator beyond the last item in the vector.
Definition lean_vector.hpp:475
const_iterator cend() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:493
iterator begin() noexcept
Get an iterator to the first item in the vector.
Definition lean_vector.hpp:448
iterator insert(const_iterator pos, std::initializer_list< value_type > list)
Insert new items.
Definition lean_vector.hpp:692
iterator erase(const_iterator pos)
Erase an item at position.
Definition lean_vector.hpp:709
void resize(size_type new_size, value_type const &value)
Resize a vector.
Definition lean_vector.hpp:842
friend size_type erase(lean_vector &c, value_type const &value)
Erase items of a value from a vector.
Definition lean_vector.hpp:887
reference emplace_back(Args &&...args)
In-place construct an item at the end of the vector.
Definition lean_vector.hpp:752
const_pointer data() const noexcept
Get a const-pointer to the first item.
Definition lean_vector.hpp:286
void resize(size_type new_size)
Resize a vector.
Definition lean_vector.hpp:814
pointer data() noexcept
Get a pointer to the first item.
Definition lean_vector.hpp:265
lean_vector(lean_vector &&other) noexcept(std::is_nothrow_move_constructible_v< value_type >)
Move-construct a vector.
Definition lean_vector.hpp:89
constexpr bool empty() const noexcept
Check if the vector is empty.
Definition lean_vector.hpp:296
friend bool operator==(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors.
Definition lean_vector.hpp:865
iterator insert(const_iterator pos, value_type &&value)
Insert a new item.
Definition lean_vector.hpp:612
friend auto operator<=>(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors lexicographically.
Definition lean_vector.hpp:876
void assign(std::initializer_list< value_type > list)
Replace the data in the vector.
Definition lean_vector.hpp:255
const_iterator begin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:457
friend size_type erase(lean_vector &c, Pred pred)
Erase items of a value from a vector.
Definition lean_vector.hpp:902
const_iterator cbegin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:466
void assign(std::input_iterator auto first, std::input_iterator auto last)
Replace the data in the vector.
Definition lean_vector.hpp:245
iterator insert(const_iterator pos, size_type count, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:636
const_reference operator[](size_type index) const noexcept
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:397
constexpr lean_vector() noexcept=default
Construct an empty vector.
reference at(size_type index)
Get a reference to an item in the vector.
Definition lean_vector.hpp:357
constexpr size_type size() const noexcept
Get the number of items in the vector.
Definition lean_vector.hpp:309
void shrink_to_fit()
Shrink the allocation to fit the current number of items.
Definition lean_vector.hpp:531
void pop_back()
Remove the last item from the vector.
Definition lean_vector.hpp:795
lean_vector & operator=(lean_vector const &other) noexcept
Copy-assign a vector.
Definition lean_vector.hpp:111
const_reference at(size_type index) const
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:374
reference front() noexcept
Get a reference to the first item in the vector.
Definition lean_vector.hpp:407
iterator emplace(const_iterator pos, Args &&...args)
Construct in-place a new item.
Definition lean_vector.hpp:566
const_reference back() const noexcept
Get a const-reference to the last item in the vector.
Definition lean_vector.hpp:439
constexpr allocator_type get_allocator() const noexcept
The allocator_type used to allocate items.
Definition lean_vector.hpp:49
lean_vector(std::input_iterator auto first, std::input_iterator auto last)
Construct a vector with the data pointed by iterators.
Definition lean_vector.hpp:215
void assign(size_type count, value_type const &value)
Replace the data in the vector.
Definition lean_vector.hpp:234
reference operator[](size_type index) noexcept
Get a reference to an item in the vector.
Definition lean_vector.hpp:385
iterator erase(const_iterator first, const_iterator last)
Erase an items.
Definition lean_vector.hpp:733
void reserve(size_type new_capacity)
Reserve capacity for items.
Definition lean_vector.hpp:517
iterator insert(const_iterator pos, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:589
T addressof(T... args)
T allocate(T... args)
T ceil(T... args)
T deallocate(T... args)
T distance(T... args)
T equal(T... args)
T max_size(T... args)
T move(T... args)
T remove(T... args)
T rotate(T... args)
T swap(T... args)
T uninitialized_copy_n(T... args)
T uninitialized_fill_n(T... args)