49 !std::is_const_v<T> and !std::is_volatile_v<T> and !std::is_reference_v<T>,
50 "Type of a managing container can not be const, volatile nor a reference");
52 using allocator_type = Allocator;
54 using difference_type = ptrdiff_t;
56 using const_reference = T
const &;
58 using const_pointer = T
const *;
64 gap_buffer(allocator_type
const &allocator = allocator_type{})
noexcept :
65 _begin(nullptr), _it_end(nullptr), _gap_begin(nullptr), _gap_size(0), _allocator(allocator)
67 hi_axiom(holds_invariant());
73 _begin(_allocator.allocate(init.size() + _grow_size)),
74 _it_end(_begin + init.size()),
75 _gap_begin(_begin + init.size()),
76 _gap_size(_grow_size),
79 placement_copy(init.
begin(), init.
end(), _begin);
80 hi_axiom(holds_invariant());
87 _begin(
nullptr), _it_end(
nullptr), _gap_begin(
nullptr), _gap_size(0), _allocator(other._allocator)
89 hi_axiom(&other !=
this);
91 if (other._ptr !=
nullptr) {
92 _begin = _allocator.allocate(other.capacity());
93 _it_end = _begin + other.size();
94 _gap_begin = _begin + other.left_size();
95 _gap_size = other._gap_size;
97 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
98 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
100 hi_axiom(holds_invariant());
111 hi_return_on_self_assignment(other);
114 if (_gap_size >= other.size()) {
116 _gap_begin = _begin + other.left_size();
117 _gap_size = capacity() - other.size();
119 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
120 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
124 if (_begin !=
nullptr) {
125 _allocator.deallocate(_begin, capacity());
128 _gap_begin =
nullptr;
133 if (other._begin !=
nullptr) {
134 hilet new_capacity = other.size() + _grow_size;
136 _begin = _allocator.allocate(new_capacity);
137 _it_end = _begin + other.size();
138 _gap_begin = _begin + other.left_begin_ptr();
139 _gap_size = new_capacity - other.size();
141 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
142 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
145 hi_axiom(holds_invariant());
152 _begin(other._begin),
153 _it_end(other._it_end),
154 _gap_begin(other._gap_begin),
155 _gap_size(other._gap_size),
156 _allocator(other._allocator)
158 hi_axiom(&other !=
this);
160 other._begin =
nullptr;
161 other._it_end =
nullptr;
162 other._gap_begin =
nullptr;
164 hi_axiom(holds_invariant());
172 hi_return_on_self_assignment(other);
177 if (_allocator == other._allocator) {
183 hi_axiom(holds_invariant());
186 }
else if (capacity() >= other.size()) {
188 _it_end = _begin + other.size();
189 _gap_begin = _begin + other.left_size();
190 _gap_size = capacity() - other.size();
192 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
193 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
196 hilet other_capacity = other.capacity();
197 other._it_end = other._begin;
198 other._gap_begin = other._begin;
199 other._gap_size = other_capacity;
200 hi_axiom(holds_invariant());
205 if (_begin !=
nullptr) {
206 _allocator.deallocate(_begin, capacity());
209 _gap_begin =
nullptr;
214 if (other._begin !=
nullptr) {
215 hilet new_capacity = other.size() + _grow_size;
217 _begin = _allocator.allocate(new_capacity);
218 _it_end = _begin + other.size();
219 _gap_begin = _begin + other.left_size();
220 _gap_size = new_capacity - other.size();
222 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
223 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
227 hilet other_capacity = other.capacity();
228 other._it_end = other._begin;
229 other._gap_begin = other._begin;
230 other._gap_size = other_capacity;
231 hi_axiom(holds_invariant());
242 if (_begin !=
nullptr) {
243 _allocator.deallocate(_begin, capacity());
255 hi_axiom(index < size());
256 return *get_pointer_from_index(index);
267 hi_axiom(index < size());
268 return *get_pointer_from_index(index);
279 if (index < size()) {
282 return *get_pointer_from_index(index);
293 if (index < size()) {
296 return *get_pointer_from_index(index);
301 hi_axiom(size() != 0);
302 return *get_pointer_from_it_ptr(_begin);
305 [[nodiscard]] const_reference front() const noexcept
307 hi_axiom(size() != 0);
308 return *get_pointer_from_it_ptr(_begin);
311 [[nodiscard]] reference back() noexcept
313 hi_axiom(size() != 0);
314 return *get_pointer_from_it_ptr(_it_end - 1);
317 [[nodiscard]] const_reference back() const noexcept
319 hi_axiom(size() != 0);
320 return *get_pointer_from_it_ptr(_it_end - 1);
323 void pop_back() noexcept
325 hi_axiom(size() != 0);
329 void pop_front() noexcept
331 hi_axiom(size() != 0);
345 std::destroy(left_begin_ptr(), left_end_ptr());
346 std::destroy(right_begin_ptr(), right_end_ptr());
347 hilet this_capacity = capacity();
350 _gap_size = this_capacity;
352 hi_axiom(holds_invariant());
360 [[nodiscard]]
bool empty() const noexcept
365 [[nodiscard]]
std::size_t capacity() const noexcept
367 return size() + _gap_size;
372 hilet extra_capacity =
static_cast<ssize_t>(new_capacity) - capacity();
373 if (extra_capacity <= 0) {
380 hilet new_begin = _allocator.allocate(new_capacity);
381 hilet new_it_end = new_begin + size();
382 hilet new_gap_begin = new_begin + left_size();
383 hilet new_gap_size = new_capacity - size();
385 if (_begin !=
nullptr) {
386 placement_move(left_begin_ptr(), left_end_ptr(), new_begin);
387 placement_move(right_begin_ptr(), right_end_ptr(), new_gap_begin + new_gap_size);
388 _allocator.deallocate(_begin, capacity());
392 _it_end = new_it_end;
393 _gap_begin = new_gap_begin;
394 _gap_size = new_gap_size;
395 hi_axiom(holds_invariant());
398 [[nodiscard]] iterator
begin() noexcept
400 return iterator{
this, _begin};
403 [[nodiscard]] const_iterator
begin() const noexcept
405 return const_iterator{
this, _begin};
408 [[nodiscard]] const_iterator cbegin() const noexcept
410 return const_iterator{
this, _begin};
413 [[nodiscard]] iterator
end() noexcept
415 return iterator{
this, _it_end};
418 [[nodiscard]] const_iterator
end() const noexcept
420 return const_iterator{
this, _it_end};
423 [[nodiscard]] const_iterator cend() const noexcept
425 return const_iterator{
this, _it_end};
428 [[nodiscard]]
friend iterator
begin(gap_buffer &rhs)
noexcept
433 [[nodiscard]]
friend const_iterator
begin(gap_buffer
const &rhs)
noexcept
438 [[nodiscard]]
friend const_iterator cbegin(gap_buffer
const &rhs)
noexcept
443 [[nodiscard]]
friend iterator
end(gap_buffer &rhs)
noexcept
448 [[nodiscard]]
friend const_iterator
end(gap_buffer
const &rhs)
noexcept
453 [[nodiscard]]
friend const_iterator cend(gap_buffer
const &rhs)
noexcept
458 template<
typename... Args>
459 reference emplace_back(Args &&...args)
noexcept
461 return emplace_after(
end(), std::forward<Args>(args)...);
464 void push_back(value_type
const &value)
noexcept
469 void push_back(value_type &&value)
noexcept
474 template<
typename... Args>
475 reference emplace_front(Args &&...args)
noexcept
477 set_gap_offset(_begin);
480 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
483#if HI_BUILT_TYPE == HI_BT_DEBUG
486 hi_axiom(holds_invariant());
490 void push_front(value_type
const &value)
noexcept
492 emplace_front(value);
495 void push_front(value_type &&value)
noexcept
504 template<
typename... Args>
507 hi_axiom(position._buffer ==
this);
508 set_gap_offset(position.it_rw_ptr());
511 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
514#if HI_BUILT_TYPE == HI_BT_DEBUG
517 hi_axiom(holds_invariant());
527 auto ptr = &emplace_before(position, value_type(value));
528 return iterator{
this, get_it_from_pointer(ptr)};
537 auto ptr = &emplace_before(position,
std::move(value));
538 return iterator{
this, get_it_from_pointer(ptr)};
550 template<
typename It>
556 while (it != first) {
557 position = insert_before(position, *(--it));
559 hi_axiom(holds_invariant());
567 template<
typename... Args>
570 hi_axiom(position._buffer ==
this);
571 set_gap_offset(position.it_rw_ptr());
574 auto ptr =
new (left_end_ptr()) value_type(std::forward<Args>(args)...);
578#if HI_BUILT_TYPE == HI_BT_DEBUG
581 hi_axiom(holds_invariant());
591 auto ptr = &emplace_after(position, value_type(value));
592 return iterator{
this, get_it_from_pointer(ptr)};
601 auto ptr = &emplace_after(position,
std::move(value));
602 return iterator{
this, get_it_from_pointer(ptr)};
612 template<
typename It>
615 auto position_ =
iterator{position};
616 for (
auto it = first; it != last; ++it) {
617 position_ = insert_after(position_, *it) + 1;
619 hi_axiom(holds_invariant());
632 hi_axiom(first._buffer ==
this);
633 hi_axiom(last._buffer ==
this);
635 set_gap_offset(last.it_rw_ptr());
636 auto first_p = first.it_rw_ptr();
637 auto last_p = last.it_rw_ptr();
638 hilet erase_size = last_p - first_p;
640 std::destroy(first_p, last_p);
641 _gap_begin = first_p;
642 _gap_size += erase_size;
643 _it_end -= erase_size;
644 hi_axiom(holds_invariant());
654 return erase(position, position + 1);
659 if (lhs.size() != rhs.size()) {
662 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
666 template<
typename Container>
667 [[nodiscard]]
friend bool operator==(gap_buffer
const &lhs, Container
const &rhs)
noexcept
672 if (lhs.size() != size(rhs)) {
679 template<
typename Container>
680 [[nodiscard]]
friend bool operator==(Container
const &lhs, gap_buffer
const &rhs)
noexcept
687 static constexpr difference_type _grow_size = 256;
700 value_type *_gap_begin;
706#if HI_BUILT_TYPE == HI_BT_DEBUG
710 [[no_unique_address]] allocator_type _allocator;
712 [[nodiscard]]
bool holds_invariant() const noexcept
714 return (_begin ==
nullptr and _it_end ==
nullptr and _gap_begin ==
nullptr and _gap_size == 0) or
715 (_begin <= _gap_begin and _gap_begin <= _it_end);
720 void grow_to_insert(size_type n)
noexcept
722 if (n > _gap_size) [[unlikely]] {
723 auto new_capacity = size() + n + narrow_cast<size_type>(_grow_size);
724 reserve(
ceil(new_capacity, hardware_constructive_interference_size));
726 hi_axiom(holds_invariant());
731 const_pointer get_it_from_pointer(const_pointer ptr)
const noexcept
733 if (ptr < _gap_begin) {
736 return ptr - _gap_size;
742 pointer get_it_from_pointer(pointer ptr)
noexcept
744 if (ptr < _gap_begin) {
747 return ptr - _gap_size;
756 const_pointer get_const_pointer_from_it(const_pointer it_ptr)
const noexcept
758 hi_axiom(it_ptr >= _begin && it_ptr <= _it_end);
760 if (it_ptr < _gap_begin) {
763 return it_ptr + _gap_size;
767 const_pointer get_pointer_from_it(pointer it_ptr)
const noexcept
769 return get_const_pointer_from_it(it_ptr);
772 pointer get_pointer_from_it(pointer it_ptr)
noexcept
774 return const_cast<pointer
>(get_const_pointer_from_it(it_ptr));
782 const_pointer get_const_pointer_from_index(size_type index)
const noexcept
784 return get_const_pointer_from_it(_begin + index);
787 const_pointer get_pointer_from_index(size_type index)
const noexcept
789 return get_const_pointer_from_it(_begin + index);
792 pointer get_pointer_from_index(size_type index)
noexcept
794 return get_pointer_from_it(_begin + index);
797 [[nodiscard]] value_type
const *left_begin_ptr() const noexcept
802 [[nodiscard]] value_type *left_begin_ptr() noexcept
807 [[nodiscard]] value_type
const *left_end_ptr() const noexcept
812 [[nodiscard]] value_type *left_end_ptr() noexcept
817 [[nodiscard]] size_type left_size() const noexcept
819 return static_cast<size_type
>(_gap_begin - _begin);
822 [[nodiscard]] value_type
const *right_begin_ptr() const noexcept
824 return _gap_begin + _gap_size;
827 [[nodiscard]] value_type *right_begin_ptr() noexcept
829 return _gap_begin + _gap_size;
832 [[nodiscard]] value_type
const *right_end_ptr() const noexcept
834 return _it_end + _gap_size;
837 [[nodiscard]] value_type *right_end_ptr() noexcept
839 return _it_end + _gap_size;
842 [[nodiscard]] size_type right_size() const noexcept
844 return _it_end - _gap_begin;
849 void set_gap_offset(value_type *new_gap_begin)
noexcept
851 if (new_gap_begin < _gap_begin) {
855 placement_move_within_array(new_gap_begin, _gap_begin, new_gap_begin + _gap_size);
857 }
else if (new_gap_begin > _gap_begin) {
861 placement_move_within_array(_gap_begin + _gap_size, new_gap_begin + _gap_size, _gap_begin);
864 _gap_begin = new_gap_begin;
865 hi_axiom(holds_invariant());
868 template<
typename IT>
869 friend class gap_buffer_iterator;
878 !std::is_volatile_v<T> && !std::is_reference_v<T>,
879 "Type of a managing container iterator can not be volatile nor a reference");
881 static constexpr bool is_const = std::is_const_v<T>;
883 using value_type = std::remove_cv_t<T>;
885 using difference_type = ptrdiff_t;
887 using const_pointer = value_type
const *;
889 using const_reference = value_type
const &;
892 using gap_buffer_type = std::conditional_t<is_const, gap_buffer<value_type>
const,
gap_buffer<value_type>>;
906 _buffer(other._buffer), _it_ptr(other._it_ptr)
908#if HI_BUILT_TYPE == HI_BT_DEBUG
909 _version = other._version;
911 hi_axiom(holds_invariant());
915 gap_buffer_type *buffer,
917#
if HI_BUILT_TYPE == HI_BT_DEBUG
924#if HI_BUILT_TYPE == HI_BT_DEBUG
929 hi_axiom(holds_invariant());
932 reference operator*()
noexcept requires(!is_const)
934 return *(_buffer->get_pointer_from_it(_it_ptr));
937 const_reference operator*()
const noexcept
939 return *(_buffer->get_const_pointer_from_it(_it_ptr));
942 pointer operator->()
noexcept requires(!is_const)
944 return _buffer->get_pointer_from_it(_it_ptr);
947 const_pointer operator->()
const noexcept
949 return _buffer->get_const_pointer_from_it(_it_ptr);
952 reference operator[](std::integral
auto index)
noexcept requires(!is_const)
954 return *(_buffer->get_pointer_from_it(_it_ptr + index));
957 const_reference operator[](std::integral
auto index)
const noexcept
959 return *(_buffer->get_const_pointer_from_it(_it_ptr + index));
965 hi_axiom(holds_invariant());
973 hi_axiom(holds_invariant());
980 hi_axiom(holds_invariant());
988 hi_axiom(holds_invariant());
995 hi_axiom(holds_invariant());
1002 hi_axiom(holds_invariant());
1022 template<
typename R>
1023 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend difference_type
1026 return lhs._it_ptr - rhs._it_ptr;
1029 template<
typename R>
1030 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
1033 return lhs._it_ptr == rhs.it_ptr();
1036 template<
typename R>
1037 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend auto
1040 return lhs._it_ptr <=> rhs.it_ptr();
1044 gap_buffer_type *_buffer;
1046#if HI_BUILT_TYPE == HI_BT_DEBUG
1051 _buffer(
const_cast<gap_buffer_type *
>(other._buffer)), _it_ptr(
const_cast<T *
>(other._it_ptr))
1053#if HI_BUILT_TYPE == HI_BT_DEBUG
1054 _version = other._version;
1056 hi_axiom(holds_invariant());
1059 [[nodiscard]] T *it_ptr()
const noexcept
1064 [[nodiscard]] std::remove_cv_t<T> *it_rw_ptr()
const noexcept
1066 return const_cast<std::remove_cv_t<T> *
>(_it_ptr);
1069 [[nodiscard]]
bool holds_invariant()
const noexcept
1071 return _buffer and _it_ptr >= _buffer->_begin and _it_ptr <= _buffer->_it_end
1072#if HI_BUILT_TYPE == HI_BT_DEBUG
1073 and _version == _buffer->_version
1078 template<
typename O>
1079 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<O>>)
1082 return holds_invariant() and other.holds_invariant() and _buffer == other._buffer;