10#include "../utility/utility.hpp"
11#include "../macros.hpp"
21hi_export_module(hikogui.container.lean_vector);
27hi_warning_ignore_msvc(26459);
29hi_export
namespace hi {
inline namespace v1 {
39 using pointer = value_type *;
40 using const_pointer = value_type
const *;
41 using reference = value_type&;
42 using const_reference = value_type
const&;
43 using iterator = value_type *;
44 using const_iterator = value_type
const *;
51 constexpr static size_t value_alignment =
alignof(value_type);
82 auto const other_size =
other.size();
83 auto const update = _reserve<false>(other_size);
85 _reserve_update(update, other_size);
97 if (
other._is_short()) {
98 auto const other_size =
other._short_size();
99 std::uninitialized_move_n(
other.begin(), other_size,
begin());
100 other._set_short_size(0);
101 _set_short_size(other_size);
104 _ptr = std::exchange(
other._ptr,
nullptr);
105 _end = std::exchange(
other._end,
nullptr);
106 _cap = std::exchange(
other._cap,
nullptr);
119 hi_return_on_self_assignment(
other);
121 auto const other_size =
other.size();
124 auto const update = _reserve<false>(other_size);
126 _reserve_update(update, other_size);
141 hi_return_on_self_assignment(
other);
143 if (not _is_short() and not
other._is_short()) {
152 if (
other._is_short()) {
153 auto const other_size =
other._short_size();
154 std::uninitialized_move_n(
other.begin(), other_size, _short_data());
155 _set_short_size(other_size);
158 _ptr = std::exchange(
other._ptr,
nullptr);
159 _end = std::exchange(
other._end,
nullptr);
160 _cap = std::exchange(
other._cap,
nullptr);
169 auto const this_is_short = this->_is_short();
170 auto const other_is_short =
other._is_short();
177 }
else if (other_is_short) {
193 std::uninitialized_value_construct_n(_short_data(), count);
194 _set_short_size(count);
197 auto const update = _reserve<false>(count);
198 std::uninitialized_value_construct_n(update.ptr, count);
199 _reserve_update(update, count);
203 lean_vector(size_type count, value_type
const& value)
207 _set_short_size(count);
210 auto const update = _reserve<false>(count);
212 _reserve_update(update, count);
221 lean_vector(std::input_iterator
auto first, std::input_iterator
auto last)
223 insert(_short_data(), first, last);
251 void assign(std::input_iterator
auto first, std::input_iterator
auto last)
271 [[nodiscard]] pointer
data() noexcept
274 if (_short_size() == 0) {
277 return _short_data();
292 [[nodiscard]] const_pointer
data() const noexcept
302 [[nodiscard]]
constexpr bool empty() const noexcept
305 return _short_size() == 0;
318 return _short_size();
320 hi_axiom(_ptr <= _end);
321 return truncate<size_type>(_long_size());
325 [[nodiscard]]
constexpr size_type max_size() const noexcept
335 if constexpr (std::endian::native == std::endian::little) {
337 return (
sizeof(pointer) * 3 -
alignof(value_type)) /
sizeof(value_type);
340 return (
sizeof(pointer) * 3 - 1) /
sizeof(value_type);
353 return _long_capacity();
365 auto const is_short = _is_short();
366 auto const size_ = is_short ? _short_size() : _long_size();
368 return _begin_data(is_short)[index];
393 hi_axiom(index <
size());
394 return _begin_data(_is_short())[index];
405 return const_cast<lean_vector *
>(
this)->
operator[](index);
413 [[nodiscard]] reference
front() noexcept
415 hi_axiom(not
empty());
416 return *_begin_data(_is_short());
424 [[nodiscard]] const_reference
front() const noexcept
434 [[nodiscard]] reference
back() noexcept
436 hi_axiom(not
empty());
437 return *(_end_data(_is_short()) - 1);
445 [[nodiscard]] const_reference
back() const noexcept
454 [[nodiscard]] iterator
begin() noexcept
456 return _begin_data(_is_short());
463 [[nodiscard]] const_iterator
begin() const noexcept
465 return _begin_data(_is_short());
472 [[nodiscard]] const_iterator
cbegin() const noexcept
481 [[nodiscard]] iterator
end() noexcept
483 return _end_data(_is_short());
490 [[nodiscard]] const_iterator
end() const noexcept
499 [[nodiscard]] const_iterator
cend() const noexcept
510 auto const is_short = _is_short();
511 std::destroy(_begin_data(is_short), _end_data(is_short));
512 _set_size(0, is_short);
525 auto const update = _reserve<false>(new_capacity);
526 _reserve_update(update);
543 auto const old_ptr = _ptr;
544 auto const old_size =
size();
545 auto const old_capacity =
capacity();
548 _set_short_size(old_size);
552 _end = _ptr + old_size;
553 _cap = _ptr + old_size;
556 std::uninitialized_move_n(old_ptr, old_size,
begin());
557 std::destroy_n(old_ptr, old_size);
571 template<
typename... Args>
572 iterator
emplace(const_iterator pos, Args&&...args)
574 auto const index = pos -
begin();
575 auto const new_size =
size() + 1;
577 auto const update = _reserve<true>(new_size);
578 std::construct_at(update.end, std::forward<Args>(args)...);
579 _reserve_update(update, new_size);
581 auto const new_pos =
begin() + index;
595 iterator
insert(const_iterator pos, value_type
const& value)
597 auto const index = pos -
begin();
598 auto const new_size =
size() + 1;
600 auto const update = _reserve<true>(new_size);
602 _reserve_update(update, new_size);
604 auto const new_pos =
begin() + index;
618 iterator
insert(const_iterator pos, value_type&& value)
620 auto const index = pos -
begin();
621 auto const new_size =
size() + 1;
623 auto const update = _reserve<true>(new_size);
625 _reserve_update(update, new_size);
627 auto const new_pos =
begin() + index;
644 auto const index = pos -
begin();
645 auto const new_size =
size() + count;
647 auto const update = _reserve<true>(new_size);
649 _reserve_update(update, new_size);
651 auto const new_pos =
begin() + index;
666 template<std::input_iterator First, std::input_iterator Last>
667 iterator
insert(const_iterator pos, First first, Last last)
672 auto const index = pos -
begin();
673 auto const new_size =
size() + n;
675 auto const update = _reserve<true>(new_size);
676 std::uninitialized_move_n(first, n, update.end);
677 _reserve_update(update, new_size);
679 auto const new_pos =
begin() + index;
684 for (
auto it = first; it != last; ++it) {
685 pos =
insert(pos, *it) + 1;
718 hi_axiom(pos >=
begin() and pos <=
end());
722 auto const is_short = _is_short();
723 _set_size(
size() - 1, is_short);
724 std::destroy_at(_end_data(is_short));
740 iterator
erase(const_iterator first, const_iterator last)
746 std::destroy(
end() - n,
end());
747 _set_size(
size() - n, _is_short());
758 template<
typename... Args>
761 auto const new_size =
size() + 1;
763 auto const update = _reserve<true>(new_size);
764 auto const obj = std::construct_at(update.end, std::forward<Args>(args)...);
765 _reserve_update(update, new_size);
776 auto const new_size =
size() + 1;
778 auto const update = _reserve<true>(new_size);
780 _reserve_update(update, new_size);
789 auto const new_size =
size() + 1;
791 auto const update = _reserve<true>(new_size);
793 _reserve_update(update, new_size);
804 hi_axiom(not
empty());
806 auto const is_short = _is_short();
807 _set_size(
size() - 1, is_short);
808 std::destroy_at(_end_data(is_short));
823 if (
auto const old_size =
size(); new_size > old_size) {
824 auto const n = new_size - old_size;
826 auto const update = _reserve<true>(new_size);
827 std::uninitialized_value_construct_n(update.end, n);
828 _reserve_update(update, new_size);
831 auto const is_short = _is_short();
832 auto const n = old_size - new_size;
833 std::destroy(_end_data(is_short) - n, _end_data(is_short));
834 _set_size(new_size, is_short);
851 if (
auto const old_size =
size(); new_size > old_size) {
852 auto const n = new_size - old_size;
854 auto const update = _reserve<true>(new_size);
856 _reserve_update(update, new_size);
859 auto const is_short = _is_short();
860 auto const n = old_size - new_size;
861 std::destroy(
end() - n,
end());
862 _set_size(new_size, is_short);
874 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
885 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
898 c.erase(it, c.end());
908 template<
typename Pred>
913 c.erase(it, c.end());
923 pointer _ptr =
nullptr;
924 pointer _end =
nullptr;
925 pointer _cap =
nullptr;
927 [[nodiscard]]
constexpr bool _is_short() const noexcept
929 if constexpr (std::endian::native == std::endian::little) {
930 if (_ptr ==
nullptr) {
933 return to_bool(to_int(_ptr) & 1);
936 if (_cap ==
nullptr) {
939 return to_bool(to_int(_cap) & 1);
944 [[nodiscard]] pointer _short_data() const noexcept
946 static_assert(
alignof(value_type) <=
alignof(pointer));
949 if constexpr (std::endian::native == std::endian::little) {
952 return std::launder(
static_cast<pointer
>(p));
955 [[nodiscard]] pointer _long_data() const noexcept
960 [[nodiscard]]
constexpr size_type _short_size() const noexcept
962 if constexpr (std::endian::native == std::endian::little) {
963 if (_ptr ==
nullptr) {
966 return (to_int(_ptr) >> 1) & 0x1f;
969 if (_cap ==
nullptr) {
972 return (to_int(_cap) >> 1) & 0x1f;
977 [[nodiscard]]
constexpr size_type _long_size() const noexcept
979 hi_axiom(_ptr <= _end);
983 [[nodiscard]]
constexpr size_type _long_capacity() const noexcept
985 hi_axiom(_ptr <= _cap);
989 void _set_short_size(
size_t new_size)
noexcept
991 constexpr auto mask = ~intptr_t{0xff};
995 if constexpr (std::endian::native == std::endian::little) {
996 _ptr = to_ptr<pointer>((to_int(_ptr) & mask) | new_size);
998 _cap = to_ptr<pointer>((to_int(_cap) & mask) | new_size);
1002 void _set_size(
size_t new_size,
bool is_short)
noexcept
1006 _set_short_size(new_size);
1008 _end = _ptr + new_size;
1012 [[nodiscard]] pointer _begin_data(
bool is_short)
const noexcept
1015 return _short_data();
1017 return _long_data();
1021 [[nodiscard]] pointer _end_data(
bool is_short)
const noexcept
1024 return _short_data() + _short_size();
1030 struct _reserve_type {
1042 template<
bool ForInsert>
1043 [[nodiscard]] _reserve_type _reserve(size_type new_capacity)
const
1045 auto const is_short = _is_short();
1048 [[likely]]
return {_begin_data(is_short), _end_data(is_short),
nullptr,
false, is_short};
1051 if constexpr (ForInsert) {
1053 if (new_capacity > next_capacity) {
1054 next_capacity = new_capacity + new_capacity / 2;
1056 new_capacity = next_capacity;
1062 auto const size_ = is_short ? _short_size() : _long_size();
1063 return {new_ptr, new_ptr + size_, new_ptr + new_capacity,
true,
false};
1066 void _reserve_update(_reserve_type update)
1068 if (not update.resized) {
1072 auto const is_short = _is_short();
1073 auto const old_size = is_short ? _short_size() : _long_size();
1074 auto const old_ptr = is_short ? _short_data() : _long_data();
1076 std::uninitialized_move_n(old_ptr, old_size, update.ptr);
1077 std::destroy_n(old_ptr, old_size);
1089 void _reserve_update(_reserve_type update, size_type new_size)
1091 _reserve_update(update);
1092 _set_size(new_size, update.is_short);
1096template<std::input_iterator It, std::input_iterator ItEnd>
1097lean_vector(It first, ItEnd last) -> lean_vector<typename std::iterator_traits<It>::value_type>;
1100template<
typename T, std::convertible_to<T>... Args>
1101lean_vector<T> make_lean_vector(Args &&...args)
noexcept
1103 return lean_vector<T>{std::forward<Args>(args)...};
1117struct std::formatter<
hi::lean_vector<T>, char> : std::formatter<std::string, char> {
1127 r += std::format(
"{}", x);
1131 return std::formatter<std::string, char>::format(r, fc);
@ other
The gui_event does not have associated data.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
void * advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
Advance a pointer by a number of bytes.
Definition memory.hpp:224
Lean-vector with (SVO) short-vector-optimization.
Definition lean_vector.hpp:36
lean_vector(lean_vector const &other)
Copy-construct a vector.
Definition lean_vector.hpp:80
const_reference front() const noexcept
Get a const-reference to the first item in the vector.
Definition lean_vector.hpp:424
size_t capacity() const noexcept
Get the current capacity of the vector.
Definition lean_vector.hpp:348
reference back() noexcept
Get a reference to the last item in the vector.
Definition lean_vector.hpp:434
void push_back(value_type &&value)
Move an item to the end of the vector.
Definition lean_vector.hpp:787
const_iterator end() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:490
lean_vector & operator=(lean_vector &&other) noexcept
Move-assign a vector.
Definition lean_vector.hpp:139
void clear() noexcept
Remove all items from the vector.
Definition lean_vector.hpp:508
void push_back(value_type const &value)
Copy an item to the end of the vector.
Definition lean_vector.hpp:774
constexpr size_t short_capacity() const noexcept
The maximum number of items that can fit without allocation.
Definition lean_vector.hpp:333
lean_vector(std::initializer_list< value_type > list)
Construct a vector with the given initializer list.
Definition lean_vector.hpp:230
iterator end() noexcept
Get an iterator beyond the last item in the vector.
Definition lean_vector.hpp:481
const_iterator cend() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:499
iterator begin() noexcept
Get an iterator to the first item in the vector.
Definition lean_vector.hpp:454
iterator insert(const_iterator pos, std::initializer_list< value_type > list)
Insert new items.
Definition lean_vector.hpp:699
iterator erase(const_iterator pos)
Erase an item at position.
Definition lean_vector.hpp:716
void resize(size_type new_size, value_type const &value)
Resize a vector.
Definition lean_vector.hpp:849
friend size_type erase(lean_vector &c, value_type const &value)
Erase items of a value from a vector.
Definition lean_vector.hpp:894
reference emplace_back(Args &&...args)
In-place construct an item at the end of the vector.
Definition lean_vector.hpp:759
const_pointer data() const noexcept
Get a const-pointer to the first item.
Definition lean_vector.hpp:292
void resize(size_type new_size)
Resize a vector.
Definition lean_vector.hpp:821
pointer data() noexcept
Get a pointer to the first item.
Definition lean_vector.hpp:271
lean_vector(lean_vector &&other) noexcept(std::is_nothrow_move_constructible_v< value_type >)
Move-construct a vector.
Definition lean_vector.hpp:95
constexpr bool empty() const noexcept
Check if the vector is empty.
Definition lean_vector.hpp:302
friend bool operator==(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors.
Definition lean_vector.hpp:872
iterator insert(const_iterator pos, value_type &&value)
Insert a new item.
Definition lean_vector.hpp:618
friend auto operator<=>(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors lexicographically.
Definition lean_vector.hpp:883
void assign(std::initializer_list< value_type > list)
Replace the data in the vector.
Definition lean_vector.hpp:261
const_iterator begin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:463
friend size_type erase(lean_vector &c, Pred pred)
Erase items of a value from a vector.
Definition lean_vector.hpp:909
const_iterator cbegin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:472
void assign(std::input_iterator auto first, std::input_iterator auto last)
Replace the data in the vector.
Definition lean_vector.hpp:251
iterator insert(const_iterator pos, size_type count, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:642
const_reference operator[](size_type index) const noexcept
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:403
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:363
constexpr size_type size() const noexcept
Get the number of items in the vector.
Definition lean_vector.hpp:315
void shrink_to_fit()
Shrink the allocation to fit the current number of items.
Definition lean_vector.hpp:537
void pop_back()
Remove the last item from the vector.
Definition lean_vector.hpp:802
lean_vector & operator=(lean_vector const &other) noexcept
Copy-assign a vector.
Definition lean_vector.hpp:117
const_reference at(size_type index) const
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:380
reference front() noexcept
Get a reference to the first item in the vector.
Definition lean_vector.hpp:413
iterator emplace(const_iterator pos, Args &&...args)
Construct in-place a new item.
Definition lean_vector.hpp:572
const_reference back() const noexcept
Get a const-reference to the last item in the vector.
Definition lean_vector.hpp:445
iterator insert(const_iterator pos, First first, Last last)
Insert new items.
Definition lean_vector.hpp:667
constexpr allocator_type get_allocator() const noexcept
The allocator_type used to allocate items.
Definition lean_vector.hpp:55
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:221
void assign(size_type count, value_type const &value)
Replace the data in the vector.
Definition lean_vector.hpp:240
reference operator[](size_type index) noexcept
Get a reference to an item in the vector.
Definition lean_vector.hpp:391
iterator erase(const_iterator first, const_iterator last)
Erase an items.
Definition lean_vector.hpp:740
void reserve(size_type new_capacity)
Reserve capacity for items.
Definition lean_vector.hpp:523
iterator insert(const_iterator pos, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:595
T uninitialized_copy_n(T... args)
T uninitialized_fill_n(T... args)