37 !std::is_const_v<T> and !std::is_volatile_v<T> and !std::is_reference_v<T>,
38 "Type of a managing container can not be const, volatile nor a reference");
40 using allocator_type = Allocator;
42 using difference_type = ptrdiff_t;
44 using const_reference = T
const&;
46 using const_pointer = T
const *;
51 !std::is_volatile_v<T> && !std::is_reference_v<T>,
52 "Type of a managing container iterator can not be volatile nor a reference");
54 using value_type = gap_buffer::value_type;
56 using difference_type = ptrdiff_t;
57 using pointer = value_type *;
58 using const_pointer = value_type
const *;
59 using reference = value_type&;
60 using const_reference = value_type
const&;
69 constexpr iterator(
gap_buffer *buffer, T *it_ptr) noexcept : _buffer(buffer), _it_ptr(it_ptr)
72 _version = buffer->_version;
74 hi_axiom(holds_invariant());
77 [[nodiscard]]
constexpr reference operator*()
noexcept
79 return *(_buffer->get_pointer_from_it(_it_ptr));
82 [[nodiscard]]
constexpr const_reference operator*()
const noexcept
84 return *(_buffer->get_const_pointer_from_it(_it_ptr));
87 [[nodiscard]]
constexpr pointer operator->()
noexcept
89 return _buffer->get_pointer_from_it(_it_ptr);
92 [[nodiscard]]
constexpr const_pointer operator->()
const noexcept
94 return _buffer->get_const_pointer_from_it(_it_ptr);
97 [[nodiscard]]
constexpr reference operator[](std::integral
auto index)
noexcept
99 return *(_buffer->get_pointer_from_it(_it_ptr + index));
102 [[nodiscard]]
constexpr const_reference operator[](std::integral
auto index)
const noexcept
104 return *(_buffer->get_const_pointer_from_it(_it_ptr + index));
107 constexpr iterator& operator++()
noexcept
110 hi_axiom(holds_invariant());
114 constexpr iterator operator++(
int)
noexcept
118 hi_axiom(holds_invariant());
122 constexpr iterator& operator--()
noexcept
125 hi_axiom(holds_invariant());
129 constexpr iterator& operator--(
int)
noexcept
133 hi_axiom(holds_invariant());
137 constexpr iterator& operator+=(difference_type n)
noexcept
140 hi_axiom(holds_invariant());
144 constexpr iterator& operator-=(difference_type n)
noexcept
147 hi_axiom(holds_invariant());
151 [[nodiscard]]
constexpr friend iterator operator+(
iterator lhs, difference_type rhs)
noexcept
156 [[nodiscard]]
constexpr friend iterator operator-(
iterator lhs, difference_type rhs)
noexcept
161 [[nodiscard]]
constexpr friend difference_type operator-(
iterator const& lhs,
iterator const& rhs)
noexcept
163 return lhs._it_ptr - rhs._it_ptr;
166 [[nodiscard]]
constexpr friend bool operator==(
iterator const& lhs,
iterator const& rhs)
noexcept
168 return lhs._it_ptr == rhs._it_ptr;
171 [[nodiscard]]
constexpr friend auto operator<=>(
iterator const& lhs,
iterator const& rhs)
noexcept
173 return lhs._it_ptr <=> rhs._it_ptr;
183 [[nodiscard]]
constexpr bool holds_invariant()
const noexcept
185 return _buffer and _it_ptr >= _buffer->_begin and _it_ptr <= _buffer->_it_end
187 and _version == _buffer->_version
192 [[nodiscard]]
constexpr bool holds_invariant(
iterator const& other)
const noexcept
194 return holds_invariant() and other.holds_invariant() and _buffer == other._buffer;
204 !std::is_volatile_v<T> && !std::is_reference_v<T>,
205 "Type of a managing container iterator can not be volatile nor a reference");
207 using value_type = gap_buffer::value_type;
209 using difference_type = ptrdiff_t;
210 using pointer = value_type *;
211 using const_pointer = value_type
const *;
212 using reference = value_type&;
213 using const_reference = value_type
const&;
225 _version = other._version;
227 hi_axiom(holds_invariant());
232 _buffer = other._buffer;
233 _it_ptr = other._it_ptr;
235 _version = other._version;
237 hi_axiom(holds_invariant());
241 constexpr const_iterator(
gap_buffer const *buffer, value_type
const *it_ptr) noexcept : _buffer(buffer), _it_ptr(it_ptr)
244 _version = buffer->_version;
246 hi_axiom(holds_invariant());
249 [[nodiscard]]
constexpr const_reference operator*()
const noexcept
251 return *(_buffer->get_const_pointer_from_it(_it_ptr));
254 [[nodiscard]]
constexpr const_pointer operator->()
const noexcept
256 return _buffer->get_const_pointer_from_it(_it_ptr);
259 [[nodiscard]]
constexpr const_reference operator[](std::integral
auto index)
const noexcept
261 return *(_buffer->get_const_pointer_from_it(_it_ptr + index));
267 hi_axiom(holds_invariant());
275 hi_axiom(holds_invariant());
282 hi_axiom(holds_invariant());
290 hi_axiom(holds_invariant());
297 hi_axiom(holds_invariant());
304 hi_axiom(holds_invariant());
320 return lhs._it_ptr - rhs._it_ptr;
325 return lhs._it_ptr == rhs._it_ptr;
330 return lhs._it_ptr <=> rhs._it_ptr;
340 [[nodiscard]]
constexpr bool holds_invariant()
const noexcept
342 return _buffer and _it_ptr >= _buffer->_begin and _it_ptr <= _buffer->_it_end
344 and _version == _buffer->_version
349 [[nodiscard]]
constexpr bool holds_invariant(
const_iterator const& other)
const noexcept
351 return holds_invariant() and other.holds_invariant() and _buffer == other._buffer;
359 constexpr gap_buffer(allocator_type
const& allocator = allocator_type{})
noexcept :
360 _begin(nullptr), _it_end(nullptr), _gap_begin(nullptr), _gap_size(0), _allocator(allocator)
362 hi_axiom(holds_invariant());
368 _begin(_allocator.allocate(init.size() + _grow_size)),
369 _it_end(_begin + init.size()),
370 _gap_begin(_begin + init.size()),
371 _gap_size(_grow_size),
372 _allocator(allocator)
375 hi_axiom(holds_invariant());
382 _begin(
nullptr), _it_end(
nullptr), _gap_begin(
nullptr), _gap_size(0), _allocator(other._allocator)
384 hi_assert(&other !=
this);
386 if (other._ptr !=
nullptr) {
387 _begin = _allocator.allocate(other.capacity());
388 _it_end = _begin + other.size();
389 _gap_begin = _begin + other.left_size();
390 _gap_size = other._gap_size;
392 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
393 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
395 hi_axiom(holds_invariant());
406 hi_return_on_self_assignment(other);
409 if (_gap_size >= other.size()) {
411 _gap_begin = _begin + other.left_size();
412 _gap_size = capacity() - other.size();
414 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
415 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
419 if (_begin !=
nullptr) {
420 _allocator.deallocate(_begin, capacity());
423 _gap_begin =
nullptr;
428 if (other._begin !=
nullptr) {
429 hilet new_capacity = other.size() + _grow_size;
431 _begin = _allocator.allocate(new_capacity);
432 _it_end = _begin + other.size();
433 _gap_begin = _begin + other.left_begin_ptr();
434 _gap_size = new_capacity - other.size();
436 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
437 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
440 hi_axiom(holds_invariant());
447 _begin(other._begin),
448 _it_end(other._it_end),
449 _gap_begin(other._gap_begin),
450 _gap_size(other._gap_size),
451 _allocator(other._allocator)
453 hi_assert(&other !=
this);
455 other._begin =
nullptr;
456 other._it_end =
nullptr;
457 other._gap_begin =
nullptr;
459 hi_axiom(holds_invariant());
467 hi_return_on_self_assignment(other);
472 if (_allocator == other._allocator) {
478 hi_axiom(holds_invariant());
481 }
else if (capacity() >= other.size()) {
483 _it_end = _begin + other.size();
484 _gap_begin = _begin + other.left_size();
485 _gap_size = capacity() - other.size();
487 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
488 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
491 hilet other_capacity = other.capacity();
492 other._it_end = other._begin;
493 other._gap_begin = other._begin;
494 other._gap_size = other_capacity;
495 hi_axiom(holds_invariant());
500 if (_begin !=
nullptr) {
501 _allocator.deallocate(_begin, capacity());
504 _gap_begin =
nullptr;
509 if (other._begin !=
nullptr) {
510 hilet new_capacity = other.size() + _grow_size;
512 _begin = _allocator.allocate(new_capacity);
513 _it_end = _begin + other.size();
514 _gap_begin = _begin + other.left_size();
515 _gap_size = new_capacity - other.size();
517 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
518 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
522 hilet other_capacity = other.capacity();
523 other._it_end = other._begin;
524 other._gap_begin = other._begin;
525 other._gap_size = other_capacity;
526 hi_axiom(holds_invariant());
537 if (_begin !=
nullptr) {
538 _allocator.deallocate(_begin, capacity());
550 hi_assert_bounds(index, *
this);
551 return *get_pointer_from_index(index);
562 hi_assert_bounds(index, *
this);
563 return *get_pointer_from_index(index);
574 if (index < size()) {
577 return *get_pointer_from_index(index);
588 if (index < size()) {
591 return *get_pointer_from_index(index);
594 [[nodiscard]]
constexpr reference front() noexcept
596 hi_axiom(size() != 0);
597 return *get_pointer_from_it_ptr(_begin);
600 [[nodiscard]]
constexpr const_reference front() const noexcept
602 hi_axiom(size() != 0);
603 return *get_pointer_from_it_ptr(_begin);
606 [[nodiscard]]
constexpr reference back() noexcept
608 hi_axiom(size() != 0);
609 return *get_pointer_from_it_ptr(_it_end - 1);
612 [[nodiscard]]
constexpr const_reference back() const noexcept
614 hi_axiom(size() != 0);
615 return *get_pointer_from_it_ptr(_it_end - 1);
618 constexpr void pop_back() noexcept
620 hi_axiom(size() != 0);
624 constexpr void pop_front() noexcept
626 hi_axiom(size() != 0);
640 std::destroy(left_begin_ptr(), left_end_ptr());
641 std::destroy(right_begin_ptr(), right_end_ptr());
642 hilet this_capacity = capacity();
645 _gap_size = this_capacity;
647 hi_axiom(holds_invariant());
650 [[nodiscard]]
constexpr std::size_t size() const noexcept
652 return narrow_cast<std::size_t>(_it_end - _begin);
655 [[nodiscard]]
constexpr bool empty() const noexcept
660 [[nodiscard]]
constexpr std::size_t capacity() const noexcept
662 return size() + _gap_size;
665 constexpr void reserve(
std::size_t new_capacity)
noexcept
667 hilet extra_capacity = narrow_cast<ptrdiff_t>(new_capacity) - capacity();
668 if (extra_capacity <= 0) {
675 hilet new_begin = _allocator.allocate(new_capacity);
676 hilet new_it_end = new_begin + size();
677 hilet new_gap_begin = new_begin + left_size();
678 hilet new_gap_size = new_capacity - size();
680 if (_begin !=
nullptr) {
682 placement_move(right_begin_ptr(), right_end_ptr(), new_gap_begin + new_gap_size);
683 _allocator.deallocate(_begin, capacity());
687 _it_end = new_it_end;
688 _gap_begin = new_gap_begin;
689 _gap_size = new_gap_size;
690 hi_axiom(holds_invariant());
693 [[nodiscard]]
constexpr iterator
begin() noexcept
695 return iterator{
this, _begin};
698 [[nodiscard]]
constexpr const_iterator
begin() const noexcept
700 return const_iterator{
this, _begin};
703 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
705 return const_iterator{
this, _begin};
708 [[nodiscard]]
constexpr iterator
end() noexcept
710 return iterator{
this, _it_end};
713 [[nodiscard]]
constexpr const_iterator
end() const noexcept
715 return const_iterator{
this, _it_end};
718 [[nodiscard]]
constexpr const_iterator cend() const noexcept
720 return const_iterator{
this, _it_end};
723 [[nodiscard]]
constexpr friend iterator
begin(gap_buffer& rhs)
noexcept
728 [[nodiscard]]
constexpr friend const_iterator
begin(gap_buffer
const& rhs)
noexcept
733 [[nodiscard]]
constexpr friend const_iterator cbegin(gap_buffer
const& rhs)
noexcept
738 [[nodiscard]]
constexpr friend iterator
end(gap_buffer& rhs)
noexcept
743 [[nodiscard]]
constexpr friend const_iterator
end(gap_buffer
const& rhs)
noexcept
748 [[nodiscard]]
constexpr friend const_iterator cend(gap_buffer
const& rhs)
noexcept
753 template<
typename... Args>
754 constexpr reference emplace_back(Args&&...args)
noexcept
756 return emplace_after(
end(), std::forward<Args>(args)...);
759 constexpr void push_back(value_type
const& value)
noexcept
764 constexpr void push_back(value_type&& value)
noexcept
769 template<
typename... Args>
770 constexpr reference emplace_front(Args&&...args)
noexcept
772 set_gap_offset(_begin);
775 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
781 hi_axiom(holds_invariant());
785 constexpr void push_front(value_type
const& value)
noexcept
787 emplace_front(value);
790 constexpr void push_front(value_type&& value)
noexcept
799 template<
typename... Args>
802 hi_axiom(position._buffer ==
this);
803 set_gap_offset(
const_cast<value_type *
>(position._it_ptr));
806 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
812 hi_axiom(holds_invariant());
822 auto ptr = &emplace_before(position, value_type(value));
823 return iterator{
this, get_it_from_pointer(ptr)};
832 auto ptr = &emplace_before(position,
std::move(value));
833 return iterator{
this, get_it_from_pointer(ptr)};
845 template<
typename It>
851 while (it != first) {
852 position = insert_before(position, *(--it));
854 hi_axiom(holds_invariant());
862 template<
typename... Args>
865 hi_axiom(position._buffer ==
this);
866 set_gap_offset(
const_cast<value_type *
>(position._it_ptr));
869 auto ptr =
new (left_end_ptr()) value_type(std::forward<Args>(args)...);
876 hi_axiom(holds_invariant());
886 auto ptr = &emplace_after(position, value_type(value));
887 return iterator{
this, get_it_from_pointer(ptr)};
896 auto ptr = &emplace_after(position,
std::move(value));
897 return iterator{
this, get_it_from_pointer(ptr)};
907 template<
typename It>
910 auto position_ =
iterator{
this,
const_cast<value_type *
>(position._it_ptr)};
911 for (
auto it = first; it != last; ++it) {
912 position_ = insert_after(position_, *it) + 1;
914 hi_axiom(holds_invariant());
927 hi_axiom(first._buffer ==
this);
928 hi_axiom(last._buffer ==
this);
930 set_gap_offset(
const_cast<value_type *
>(last._it_ptr));
931 auto first_p =
const_cast<value_type *
>(first._it_ptr);
932 auto last_p =
const_cast<value_type *
>(last._it_ptr);
933 hilet erase_size = last_p - first_p;
935 std::destroy(first_p, last_p);
936 _gap_begin = first_p;
937 _gap_size += erase_size;
938 _it_end -= erase_size;
939 hi_axiom(holds_invariant());
949 return erase(position, position + 1);
952 [[nodiscard]]
constexpr friend bool operator==(
gap_buffer const& lhs,
gap_buffer const& rhs)
noexcept
954 if (lhs.size() != rhs.size()) {
957 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
961 template<
typename Container>
962 [[nodiscard]]
constexpr friend bool operator==(gap_buffer
const& lhs, Container
const& rhs)
noexcept
967 if (lhs.size() != size(rhs)) {
974 template<
typename Container>
975 [[nodiscard]]
constexpr friend bool operator==(Container
const& lhs, gap_buffer
const& rhs)
noexcept
982 constexpr static difference_type _grow_size = 256;
995 value_type *_gap_begin;
1005 [[no_unique_address]] allocator_type _allocator;
1007 [[nodiscard]]
constexpr bool holds_invariant() const noexcept
1009 return (_begin ==
nullptr and _it_end ==
nullptr and _gap_begin ==
nullptr and _gap_size == 0) or
1010 (_begin <= _gap_begin and _gap_begin <= _it_end);
1015 constexpr void grow_to_insert(size_type n)
noexcept
1017 if (n > _gap_size) [[unlikely]] {
1018 auto new_capacity = size() + n + narrow_cast<size_type>(_grow_size);
1019 reserve(
ceil(new_capacity, hardware_constructive_interference_size));
1021 hi_axiom(holds_invariant());
1026 [[nodiscard]]
constexpr const_pointer get_it_from_pointer(const_pointer ptr)
const noexcept
1028 if (ptr < _gap_begin) {
1031 return ptr - _gap_size;
1037 [[nodiscard]]
constexpr pointer get_it_from_pointer(pointer ptr)
noexcept
1039 if (ptr < _gap_begin) {
1042 return ptr - _gap_size;
1051 [[nodiscard]]
constexpr const_pointer get_const_pointer_from_it(const_pointer it_ptr)
const noexcept
1053 hi_axiom(it_ptr >= _begin && it_ptr <= _it_end);
1055 if (it_ptr < _gap_begin) {
1058 return it_ptr + _gap_size;
1062 [[nodiscard]]
constexpr const_pointer get_pointer_from_it(pointer it_ptr)
const noexcept
1064 return get_const_pointer_from_it(it_ptr);
1067 [[nodiscard]]
constexpr pointer get_pointer_from_it(pointer it_ptr)
noexcept
1069 return const_cast<pointer
>(get_const_pointer_from_it(it_ptr));
1077 [[nodiscard]]
constexpr const_pointer get_const_pointer_from_index(size_type index)
const noexcept
1079 return get_const_pointer_from_it(_begin + index);
1082 [[nodiscard]]
constexpr const_pointer get_pointer_from_index(size_type index)
const noexcept
1084 return get_const_pointer_from_it(_begin + index);
1087 [[nodiscard]]
constexpr pointer get_pointer_from_index(size_type index)
noexcept
1089 return get_pointer_from_it(_begin + index);
1092 [[nodiscard]]
constexpr value_type
const *left_begin_ptr() const noexcept
1097 [[nodiscard]]
constexpr value_type *left_begin_ptr() noexcept
1102 [[nodiscard]]
constexpr value_type
const *left_end_ptr() const noexcept
1107 [[nodiscard]]
constexpr value_type *left_end_ptr() noexcept
1112 [[nodiscard]]
constexpr size_type left_size() const noexcept
1114 return narrow_cast<size_type>(_gap_begin - _begin);
1117 [[nodiscard]]
constexpr value_type
const *right_begin_ptr() const noexcept
1119 return _gap_begin + _gap_size;
1122 [[nodiscard]]
constexpr value_type *right_begin_ptr() noexcept
1124 return _gap_begin + _gap_size;
1127 [[nodiscard]]
constexpr value_type
const *right_end_ptr() const noexcept
1129 return _it_end + _gap_size;
1132 [[nodiscard]]
constexpr value_type *right_end_ptr() noexcept
1134 return _it_end + _gap_size;
1137 [[nodiscard]]
constexpr size_type right_size() const noexcept
1139 return _it_end - _gap_begin;
1144 constexpr void set_gap_offset(value_type *new_gap_begin)
noexcept
1146 if (new_gap_begin < _gap_begin) {
1152 }
else if (new_gap_begin > _gap_begin) {
1159 _gap_begin = new_gap_begin;
1160 hi_axiom(holds_invariant());