10#include "../utility/utility.hpp"
11#include "../macros.hpp"
20hi_export_module(hikogui.container.lean_vector);
26hi_warning_ignore_msvc(26459);
28hi_export
namespace hi {
inline namespace v1 {
38 using pointer = value_type *;
39 using const_pointer = value_type
const *;
40 using reference = value_type&;
41 using const_reference = value_type
const&;
42 using iterator = value_type *;
43 using const_iterator = value_type
const *;
50 constexpr static size_t value_alignment =
alignof(value_type);
57 return allocator_type{};
81 auto const other_size =
other.size();
82 auto const update = _reserve<false>(other_size);
84 _reserve_update(update, other_size);
96 if (
other._is_short()) {
97 auto const other_size =
other._short_size();
98 std::uninitialized_move_n(
other.begin(), other_size,
begin());
99 other._set_short_size(0);
100 _set_short_size(other_size);
103 _ptr = std::exchange(
other._ptr,
nullptr);
104 _end = std::exchange(
other._end,
nullptr);
105 _cap = std::exchange(
other._cap,
nullptr);
118 hi_return_on_self_assignment(
other);
120 auto const other_size =
other.size();
123 auto const update = _reserve<false>(other_size);
125 _reserve_update(update, other_size);
140 hi_return_on_self_assignment(
other);
142 if (not _is_short() and not
other._is_short()) {
151 if (
other._is_short()) {
152 auto const other_size =
other._short_size();
153 std::uninitialized_move_n(
other.begin(), other_size, _short_data());
154 _set_short_size(other_size);
157 _ptr = std::exchange(
other._ptr,
nullptr);
158 _end = std::exchange(
other._end,
nullptr);
159 _cap = std::exchange(
other._cap,
nullptr);
168 auto const this_is_short = this->_is_short();
169 auto const other_is_short =
other._is_short();
176 }
else if (other_is_short) {
192 std::uninitialized_value_construct_n(_short_data(), count);
193 _set_short_size(count);
196 auto const update = _reserve<false>(count);
197 std::uninitialized_value_construct_n(update.ptr, count);
198 _reserve_update(update, count);
202 lean_vector(size_type count, value_type
const& value)
206 _set_short_size(count);
209 auto const update = _reserve<false>(count);
211 _reserve_update(update, count);
220 lean_vector(std::input_iterator
auto first, std::input_iterator
auto last)
222 insert(_short_data(), first, last);
239 void assign(size_type count, value_type
const& value)
250 void assign(std::input_iterator
auto first, std::input_iterator
auto last)
270 [[nodiscard]] pointer
data() noexcept
273 if (_short_size() == 0) {
276 return _short_data();
291 [[nodiscard]] const_pointer
data() const noexcept
301 [[nodiscard]]
constexpr bool empty() const noexcept
304 return _short_size() == 0;
314 [[nodiscard]]
constexpr size_type
size() const noexcept
317 return _short_size();
319 hi_axiom(_ptr <= _end);
324 [[nodiscard]]
constexpr size_type max_size() const noexcept
334 if constexpr (std::endian::native == std::endian::little) {
336 return (
sizeof(pointer) * 3 -
alignof(value_type)) /
sizeof(value_type);
339 return (
sizeof(pointer) * 3 - 1) /
sizeof(value_type);
352 return _long_capacity();
362 [[nodiscard]] reference
at(size_type index)
364 auto const is_short = _is_short();
365 auto const size_ = is_short ? _short_size() : _long_size();
367 return _begin_data(is_short)[index];
379 [[nodiscard]] const_reference
at(size_type index)
const
392 hi_axiom(index <
size());
393 return _begin_data(_is_short())[index];
402 [[nodiscard]] const_reference
operator[](size_type index)
const noexcept
404 return const_cast<lean_vector *
>(
this)->
operator[](index);
412 [[nodiscard]] reference
front() noexcept
414 hi_axiom(not
empty());
415 return *_begin_data(_is_short());
423 [[nodiscard]] const_reference
front() const noexcept
433 [[nodiscard]] reference
back() noexcept
435 hi_axiom(not
empty());
436 return *(_end_data(_is_short()) - 1);
444 [[nodiscard]] const_reference
back() const noexcept
453 [[nodiscard]] iterator
begin() noexcept
455 return _begin_data(_is_short());
462 [[nodiscard]] const_iterator
begin() const noexcept
464 return _begin_data(_is_short());
471 [[nodiscard]] const_iterator
cbegin() const noexcept
480 [[nodiscard]] iterator
end() noexcept
482 return _end_data(_is_short());
489 [[nodiscard]] const_iterator
end() const noexcept
498 [[nodiscard]] const_iterator
cend() const noexcept
509 auto const is_short = _is_short();
510 std::destroy(_begin_data(is_short), _end_data(is_short));
511 _set_size(0, is_short);
524 auto const update = _reserve<false>(new_capacity);
525 _reserve_update(update);
542 auto const old_ptr = _ptr;
543 auto const old_size =
size();
544 auto const old_capacity =
capacity();
547 _set_short_size(old_size);
551 _end = _ptr + old_size;
552 _cap = _ptr + old_size;
555 std::uninitialized_move_n(old_ptr, old_size,
begin());
556 std::destroy_n(old_ptr, old_size);
570 template<
typename... Args>
571 iterator
emplace(const_iterator pos, Args&&...args)
573 auto const index = pos -
begin();
574 auto const new_size =
size() + 1;
576 auto const update = _reserve<true>(new_size);
578 _reserve_update(update, new_size);
580 auto const new_pos =
begin() + index;
594 iterator
insert(const_iterator pos, value_type
const& value)
596 auto const index = pos -
begin();
597 auto const new_size =
size() + 1;
599 auto const update = _reserve<true>(new_size);
601 _reserve_update(update, new_size);
603 auto const new_pos =
begin() + index;
617 iterator
insert(const_iterator pos, value_type&& value)
619 auto const index = pos -
begin();
620 auto const new_size =
size() + 1;
622 auto const update = _reserve<true>(new_size);
624 _reserve_update(update, new_size);
626 auto const new_pos =
begin() + index;
641 iterator
insert(const_iterator pos, size_type count, value_type
const& value)
643 auto const index = pos -
begin();
644 auto const new_size =
size() + count;
646 auto const update = _reserve<true>(new_size);
648 _reserve_update(update, new_size);
650 auto const new_pos =
begin() + index;
665 template<std::input_iterator First, std::input_iterator Last>
666 iterator
insert(const_iterator pos, First first, Last last)
671 auto const index = pos -
begin();
672 auto const new_size =
size() + n;
674 auto const update = _reserve<true>(new_size);
675 std::uninitialized_move_n(first, n, update.end);
676 _reserve_update(update, new_size);
678 auto const new_pos =
begin() + index;
683 for (
auto it = first; it != last; ++it) {
684 pos =
insert(pos, *it) + 1;
717 hi_axiom(pos >=
begin() and pos <=
end());
721 auto const is_short = _is_short();
722 _set_size(
size() - 1, is_short);
723 std::destroy_at(_end_data(is_short));
739 iterator
erase(const_iterator first, const_iterator last)
745 std::destroy(
end() - n,
end());
746 _set_size(
size() - n, _is_short());
757 template<
typename... Args>
760 auto const new_size =
size() + 1;
762 auto const update = _reserve<true>(new_size);
764 _reserve_update(update, new_size);
775 auto const new_size =
size() + 1;
777 auto const update = _reserve<true>(new_size);
779 _reserve_update(update, new_size);
788 auto const new_size =
size() + 1;
790 auto const update = _reserve<true>(new_size);
792 _reserve_update(update, new_size);
803 hi_axiom(not
empty());
805 auto const is_short = _is_short();
806 _set_size(
size() - 1, is_short);
807 std::destroy_at(_end_data(is_short));
822 if (
auto const old_size =
size(); new_size > old_size) {
823 auto const n = new_size - old_size;
825 auto const update = _reserve<true>(new_size);
826 std::uninitialized_value_construct_n(update.end, n);
827 _reserve_update(update, new_size);
830 auto const is_short = _is_short();
831 auto const n = old_size - new_size;
832 std::destroy(_end_data(is_short) - n, _end_data(is_short));
833 _set_size(new_size, is_short);
848 void resize(size_type new_size, value_type
const& value)
850 if (
auto const old_size =
size(); new_size > old_size) {
851 auto const n = new_size - old_size;
853 auto const update = _reserve<true>(new_size);
855 _reserve_update(update, new_size);
858 auto const is_short = _is_short();
859 auto const n = old_size - new_size;
860 std::destroy(
end() - n,
end());
861 _set_size(new_size, is_short);
873 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
884 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
897 c.erase(it, c.end());
907 template<
typename Pred>
912 c.erase(it, c.end());
922 pointer _ptr =
nullptr;
923 pointer _end =
nullptr;
924 pointer _cap =
nullptr;
926 [[nodiscard]]
constexpr bool _is_short() const noexcept
928 if constexpr (std::endian::native == std::endian::little) {
929 if (_ptr ==
nullptr) {
932 return to_bool(to_int(_ptr) & 1);
935 if (_cap ==
nullptr) {
938 return to_bool(to_int(_cap) & 1);
943 [[nodiscard]] pointer _short_data() const noexcept
945 static_assert(
alignof(value_type) <=
alignof(pointer));
948 if constexpr (std::endian::native == std::endian::little) {
951 return std::launder(
static_cast<pointer
>(p));
954 [[nodiscard]] pointer _long_data() const noexcept
959 [[nodiscard]]
constexpr size_type _short_size() const noexcept
961 if constexpr (std::endian::native == std::endian::little) {
962 if (_ptr ==
nullptr) {
965 return (to_int(_ptr) >> 1) & 0x1f;
968 if (_cap ==
nullptr) {
971 return (to_int(_cap) >> 1) & 0x1f;
976 [[nodiscard]]
constexpr size_type _long_size() const noexcept
978 hi_axiom(_ptr <= _end);
982 [[nodiscard]]
constexpr size_type _long_capacity() const noexcept
984 hi_axiom(_ptr <= _cap);
988 void _set_short_size(
size_t new_size)
noexcept
990 constexpr auto mask = ~intptr_t{0xff};
994 if constexpr (std::endian::native == std::endian::little) {
995 _ptr = to_ptr<pointer>((to_int(_ptr) & mask) | new_size);
997 _cap = to_ptr<pointer>((to_int(_cap) & mask) | new_size);
1001 void _set_size(
size_t new_size,
bool is_short)
noexcept
1005 _set_short_size(new_size);
1007 _end = _ptr + new_size;
1011 [[nodiscard]] pointer _begin_data(
bool is_short)
const noexcept
1014 return _short_data();
1016 return _long_data();
1020 [[nodiscard]] pointer _end_data(
bool is_short)
const noexcept
1023 return _short_data() + _short_size();
1029 struct _reserve_type {
1041 template<
bool ForInsert>
1042 [[nodiscard]] _reserve_type _reserve(size_type new_capacity)
const
1044 auto const is_short = _is_short();
1047 [[likely]]
return {_begin_data(is_short), _end_data(is_short),
nullptr,
false, is_short};
1050 if constexpr (ForInsert) {
1052 if (new_capacity > next_capacity) {
1053 next_capacity = new_capacity + new_capacity / 2;
1055 new_capacity = next_capacity;
1061 auto const size_ = is_short ? _short_size() : _long_size();
1062 return {new_ptr, new_ptr + size_, new_ptr + new_capacity,
true,
false};
1065 void _reserve_update(_reserve_type update)
1067 if (not update.resized) {
1071 auto const is_short = _is_short();
1072 auto const old_size = is_short ? _short_size() : _long_size();
1073 auto const old_ptr = is_short ? _short_data() : _long_data();
1075 std::uninitialized_move_n(old_ptr, old_size, update.ptr);
1076 std::destroy_n(old_ptr, old_size);
1088 void _reserve_update(_reserve_type update, size_type new_size)
1090 _reserve_update(update);
1091 _set_size(new_size, update.is_short);
1095template<std::input_iterator It, std::input_iterator ItEnd>
1099template<
typename T, std::convertible_to<T>... Args>
@ other
The gui_event does not have associated data.
Definition gui_event_variant.hpp:24
hi_inline void * advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
Advance a pointer by a number of bytes.
Definition memory.hpp:253
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
The HikoGUI API version 1.
Definition recursive_iterator.hpp:16
constexpr Out truncate(In rhs) noexcept
Cast between integral types truncating or zero-extending the result.
Definition cast.hpp:544
Lean-vector with (SVO) short-vector-optimization.
Definition lean_vector.hpp:35
lean_vector(lean_vector const &other)
Copy-construct a vector.
Definition lean_vector.hpp:79
const_reference front() const noexcept
Get a const-reference to the first item in the vector.
Definition lean_vector.hpp:423
size_t capacity() const noexcept
Get the current capacity of the vector.
Definition lean_vector.hpp:347
reference back() noexcept
Get a reference to the last item in the vector.
Definition lean_vector.hpp:433
void push_back(value_type &&value)
Move an item to the end of the vector.
Definition lean_vector.hpp:786
const_iterator end() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:489
lean_vector & operator=(lean_vector &&other) noexcept
Move-assign a vector.
Definition lean_vector.hpp:138
void clear() noexcept
Remove all items from the vector.
Definition lean_vector.hpp:507
void push_back(value_type const &value)
Copy an item to the end of the vector.
Definition lean_vector.hpp:773
constexpr size_t short_capacity() const noexcept
The maximum number of items that can fit without allocation.
Definition lean_vector.hpp:332
lean_vector(std::initializer_list< value_type > list)
Construct a vector with the given initializer list.
Definition lean_vector.hpp:229
iterator end() noexcept
Get an iterator beyond the last item in the vector.
Definition lean_vector.hpp:480
const_iterator cend() const noexcept
Get an const-iterator beyond the last item in the vector.
Definition lean_vector.hpp:498
iterator begin() noexcept
Get an iterator to the first item in the vector.
Definition lean_vector.hpp:453
iterator insert(const_iterator pos, std::initializer_list< value_type > list)
Insert new items.
Definition lean_vector.hpp:698
iterator erase(const_iterator pos)
Erase an item at position.
Definition lean_vector.hpp:715
void resize(size_type new_size, value_type const &value)
Resize a vector.
Definition lean_vector.hpp:848
friend size_type erase(lean_vector &c, value_type const &value)
Erase items of a value from a vector.
Definition lean_vector.hpp:893
reference emplace_back(Args &&...args)
In-place construct an item at the end of the vector.
Definition lean_vector.hpp:758
const_pointer data() const noexcept
Get a const-pointer to the first item.
Definition lean_vector.hpp:291
void resize(size_type new_size)
Resize a vector.
Definition lean_vector.hpp:820
pointer data() noexcept
Get a pointer to the first item.
Definition lean_vector.hpp:270
lean_vector(lean_vector &&other) noexcept(std::is_nothrow_move_constructible_v< value_type >)
Move-construct a vector.
Definition lean_vector.hpp:94
constexpr bool empty() const noexcept
Check if the vector is empty.
Definition lean_vector.hpp:301
friend bool operator==(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors.
Definition lean_vector.hpp:871
iterator insert(const_iterator pos, value_type &&value)
Insert a new item.
Definition lean_vector.hpp:617
friend auto operator<=>(lean_vector const &lhs, lean_vector const &rhs) noexcept
Compare two vectors lexicographically.
Definition lean_vector.hpp:882
void assign(std::initializer_list< value_type > list)
Replace the data in the vector.
Definition lean_vector.hpp:260
const_iterator begin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:462
friend size_type erase(lean_vector &c, Pred pred)
Erase items of a value from a vector.
Definition lean_vector.hpp:908
const_iterator cbegin() const noexcept
Get an const-iterator to the first item in the vector.
Definition lean_vector.hpp:471
void assign(std::input_iterator auto first, std::input_iterator auto last)
Replace the data in the vector.
Definition lean_vector.hpp:250
iterator insert(const_iterator pos, size_type count, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:641
const_reference operator[](size_type index) const noexcept
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:402
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:362
constexpr size_type size() const noexcept
Get the number of items in the vector.
Definition lean_vector.hpp:314
void shrink_to_fit()
Shrink the allocation to fit the current number of items.
Definition lean_vector.hpp:536
void pop_back()
Remove the last item from the vector.
Definition lean_vector.hpp:801
lean_vector & operator=(lean_vector const &other) noexcept
Copy-assign a vector.
Definition lean_vector.hpp:116
const_reference at(size_type index) const
Get a const-reference to an item in the vector.
Definition lean_vector.hpp:379
reference front() noexcept
Get a reference to the first item in the vector.
Definition lean_vector.hpp:412
iterator emplace(const_iterator pos, Args &&...args)
Construct in-place a new item.
Definition lean_vector.hpp:571
const_reference back() const noexcept
Get a const-reference to the last item in the vector.
Definition lean_vector.hpp:444
iterator insert(const_iterator pos, First first, Last last)
Insert new items.
Definition lean_vector.hpp:666
constexpr allocator_type get_allocator() const noexcept
The allocator_type used to allocate items.
Definition lean_vector.hpp:54
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:220
void assign(size_type count, value_type const &value)
Replace the data in the vector.
Definition lean_vector.hpp:239
reference operator[](size_type index) noexcept
Get a reference to an item in the vector.
Definition lean_vector.hpp:390
iterator erase(const_iterator first, const_iterator last)
Erase an items.
Definition lean_vector.hpp:739
void reserve(size_type new_capacity)
Reserve capacity for items.
Definition lean_vector.hpp:522
iterator insert(const_iterator pos, value_type const &value)
Insert a new item.
Definition lean_vector.hpp:594
T uninitialized_copy_n(T... args)
T uninitialized_fill_n(T... args)