10#include "utility/module.hpp"
21hi_warning_ignore_msvc(26459);
23namespace hi {
inline namespace v1 {
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 *;
45 constexpr static size_t value_alignment =
alignof(value_type);
77 hilet update = _reserve<false>(other_size);
79 _reserve_update(update, other_size);
91 if (
other._is_short()) {
93 std::uninitialized_move_n(
other.begin(), other_size,
begin());
94 other._set_short_size(0);
95 _set_short_size(other_size);
98 _ptr = std::exchange(
other._ptr,
nullptr);
99 _end = std::exchange(
other._end,
nullptr);
100 _cap = std::exchange(
other._cap,
nullptr);
113 hi_return_on_self_assignment(
other);
118 hilet update = _reserve<false>(other_size);
120 _reserve_update(update, other_size);
135 hi_return_on_self_assignment(
other);
137 if (not _is_short() and not
other._is_short()) {
146 if (
other._is_short()) {
148 std::uninitialized_move_n(
other.begin(), other_size, _short_data());
149 _set_short_size(other_size);
152 _ptr = std::exchange(
other._ptr,
nullptr);
153 _end = std::exchange(
other._end,
nullptr);
154 _cap = std::exchange(
other._cap,
nullptr);
163 hilet this_is_short = this->_is_short();
171 }
else if (other_is_short) {
187 std::uninitialized_value_construct_n(_short_data(), count);
188 _set_short_size(count);
191 hilet update = _reserve<false>(count);
192 std::uninitialized_value_construct_n(update.ptr, count);
193 _reserve_update(update, count);
197 lean_vector(size_type count, value_type
const& value)
201 _set_short_size(count);
204 hilet update = _reserve<false>(count);
206 _reserve_update(update, count);
215 lean_vector(std::input_iterator
auto first, std::input_iterator
auto last)
217 insert(_short_data(), first, last);
245 void assign(std::input_iterator
auto first, std::input_iterator
auto last)
265 [[nodiscard]] pointer
data() noexcept
268 if (_short_size() == 0) {
271 return _short_data();
286 [[nodiscard]] const_pointer
data() const noexcept
296 [[nodiscard]]
constexpr bool empty() const noexcept
299 return _short_size() == 0;
312 return _short_size();
315 return truncate<size_type>(_long_size());
319 [[nodiscard]]
constexpr size_type max_size() const noexcept
329 if constexpr (std::endian::native == std::endian::little) {
331 return (
sizeof(pointer) * 3 -
alignof(value_type)) /
sizeof(value_type);
334 return (
sizeof(pointer) * 3 - 1) /
sizeof(value_type);
347 return _long_capacity();
359 hilet is_short = _is_short();
360 hilet size_ = is_short ? _short_size() : _long_size();
362 return _begin_data(is_short)[index];
388 return _begin_data(_is_short())[index];
399 return const_cast<lean_vector *
>(
this)->
operator[](index);
407 [[nodiscard]] reference
front() noexcept
410 return *_begin_data(_is_short());
418 [[nodiscard]] const_reference
front() const noexcept
428 [[nodiscard]] reference
back() noexcept
431 return *(_end_data(_is_short()) - 1);
439 [[nodiscard]] const_reference
back() const noexcept
448 [[nodiscard]] iterator
begin() noexcept
450 return _begin_data(_is_short());
457 [[nodiscard]] const_iterator
begin() const noexcept
459 return _begin_data(_is_short());
466 [[nodiscard]] const_iterator
cbegin() const noexcept
475 [[nodiscard]] iterator
end() noexcept
477 return _end_data(_is_short());
484 [[nodiscard]] const_iterator
end() const noexcept
493 [[nodiscard]] const_iterator
cend() const noexcept
504 hilet is_short = _is_short();
505 std::destroy(_begin_data(is_short), _end_data(is_short));
506 _set_size(0, is_short);
519 hilet update = _reserve<false>(new_capacity);
520 _reserve_update(update);
537 hilet old_ptr = _ptr;
542 _set_short_size(old_size);
546 _end = _ptr + old_size;
547 _cap = _ptr + old_size;
550 std::uninitialized_move_n(old_ptr, old_size,
begin());
551 std::destroy_n(old_ptr, old_size);
565 template<
typename... Args>
566 iterator
emplace(const_iterator pos, Args&&...args)
571 hilet update = _reserve<true>(new_size);
572 std::construct_at(update.end, std::forward<Args>(args)...);
573 _reserve_update(update, new_size);
589 iterator
insert(const_iterator pos, value_type
const& value)
594 hilet update = _reserve<true>(new_size);
596 _reserve_update(update, new_size);
612 iterator
insert(const_iterator pos, value_type&& value)
617 hilet update = _reserve<true>(new_size);
619 _reserve_update(update, new_size);
641 hilet update = _reserve<true>(new_size);
643 _reserve_update(update, new_size);
660 iterator
insert(const_iterator pos, std::input_iterator
auto first, std::input_iterator
auto last)
668 hilet update = _reserve<true>(new_size);
669 std::uninitialized_move_n(first, n, update.end);
670 _reserve_update(update, new_size);
677 for (
auto it = first; it != last; ++it) {
678 pos =
insert(pos, *it) + 1;
715 hilet is_short = _is_short();
716 _set_size(
size() - 1, is_short);
717 std::destroy_at(_end_data(is_short));
733 iterator
erase(const_iterator first, const_iterator last)
739 std::destroy(
end() - n,
end());
740 _set_size(
size() - n, _is_short());
751 template<
typename... Args>
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);
771 hilet update = _reserve<true>(new_size);
773 _reserve_update(update, new_size);
784 hilet update = _reserve<true>(new_size);
786 _reserve_update(update, new_size);
799 hilet is_short = _is_short();
800 _set_size(
size() - 1, is_short);
801 std::destroy_at(_end_data(is_short));
816 if (
hilet old_size =
size(); new_size > old_size) {
817 hilet n = new_size - old_size;
819 hilet update = _reserve<true>(new_size);
820 std::uninitialized_value_construct_n(update.end, n);
821 _reserve_update(update, new_size);
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);
844 if (
hilet old_size =
size(); new_size > old_size) {
845 hilet n = new_size - old_size;
847 hilet update = _reserve<true>(new_size);
849 _reserve_update(update, new_size);
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);
867 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
878 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
891 c.erase(it, c.end());
901 template<
typename Pred>
906 c.erase(it, c.end());
916 pointer _ptr =
nullptr;
917 pointer _end =
nullptr;
918 pointer _cap =
nullptr;
920 [[nodiscard]]
constexpr bool _is_short() const noexcept
922 if constexpr (std::endian::native == std::endian::little) {
923 if (_ptr ==
nullptr) {
926 return to_bool(to_int(_ptr) & 1);
929 if (_cap ==
nullptr) {
932 return to_bool(to_int(_cap) & 1);
937 [[nodiscard]] pointer _short_data() const noexcept
939 static_assert(
alignof(value_type) <=
alignof(pointer));
942 if constexpr (std::endian::native == std::endian::little) {
945 return std::launder(
static_cast<pointer
>(p));
948 [[nodiscard]] pointer _long_data() const noexcept
953 [[nodiscard]]
constexpr size_type _short_size() const noexcept
955 if constexpr (std::endian::native == std::endian::little) {
956 if (_ptr ==
nullptr) {
959 return (to_int(_ptr) >> 1) & 0x1f;
962 if (_cap ==
nullptr) {
965 return (to_int(_cap) >> 1) & 0x1f;
970 [[nodiscard]]
constexpr size_type _long_size() const noexcept
976 [[nodiscard]]
constexpr size_type _long_capacity() const noexcept
982 void _set_short_size(
size_t new_size)
noexcept
984 constexpr auto mask = ~intptr_t{0xff};
988 if constexpr (std::endian::native == std::endian::little) {
989 _ptr = to_ptr<pointer>((to_int(_ptr) & mask) | new_size);
991 _cap = to_ptr<pointer>((to_int(_cap) & mask) | new_size);
995 void _set_size(
size_t new_size,
bool is_short)
noexcept
999 _set_short_size(new_size);
1001 _end = _ptr + new_size;
1005 [[nodiscard]] pointer _begin_data(
bool is_short)
const noexcept
1008 return _short_data();
1010 return _long_data();
1014 [[nodiscard]] pointer _end_data(
bool is_short)
const noexcept
1017 return _short_data() + _short_size();
1023 struct _reserve_type {
1035 template<
bool ForInsert>
1036 [[nodiscard]] _reserve_type _reserve(size_type new_capacity)
const
1038 hilet is_short = _is_short();
1041 [[likely]]
return {_begin_data(is_short), _end_data(is_short),
nullptr,
false, is_short};
1044 if constexpr (ForInsert) {
1046 if (new_capacity > next_capacity) {
1047 next_capacity = new_capacity + new_capacity / 2;
1049 new_capacity = next_capacity;
1055 hilet size_ = is_short ? _short_size() : _long_size();
1056 return {new_ptr, new_ptr + size_, new_ptr + new_capacity,
true,
false};
1059 void _reserve_update(_reserve_type update)
1061 if (not update.resized) {
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();
1069 std::uninitialized_move_n(old_ptr, old_size, update.ptr);
1070 std::destroy_n(old_ptr, old_size);
1082 void _reserve_update(_reserve_type update, size_type new_size)
1084 _reserve_update(update);
1085 _set_size(new_size, update.is_short);
1089template<std::input_iterator It, std::input_iterator ItEnd>
1090lean_vector(It first, ItEnd last) -> lean_vector<typename std::iterator_traits<It>::value_type>;
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#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 uninitialized_copy_n(T... args)
T uninitialized_fill_n(T... args)