49 !std::is_const_v<T> && !std::is_volatile_v<T> && !std::is_reference_v<T>,
50 "Type of a managing container can not be const, volatile nor a reference");
52 using allocator_type = Allocator;
53 using size_type = size_t;
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 _ptr(nullptr), _size(0), _gap_offset(0), _gap_size(0), _allocator(allocator)
72 _ptr(_allocator.allocate(init.size() + _grow_size)),
73 _size(init.size() + _grow_size),
74 _gap_offset(init.size()),
75 _gap_size(_grow_size),
87 _gap_offset(other._gap_offset),
88 _gap_size(other._gap_size),
89 _allocator(other._allocator)
91 tt_axiom(&other !=
this);
93 if (other._ptr !=
nullptr) {
94 _ptr = _allocator.allocate(_size);
95 placement_copy(other.left_begin(), other.left_end(), left_begin());
96 placement_copy(other.right_begin(), other.right_end(), right_begin());
108 tt_axiom(&other !=
this);
111 if (_size >= other.size()) {
113 _gap_offset = other._gap_offset;
114 _gap_size = other._size - other.right_size();
116 placement_copy(other.left_begin(), other.left_end(), left_begin());
117 placement_copy(other.right_begin(), other.right_end(), right_begin());
121 if (_ptr !=
nullptr) {
122 _allocator.deallocate(_ptr, _size);
130 if (other._ptr !=
nullptr) {
131 _size = other.size() + _grow_size;
132 _ptr = _allocator.allocate(_size);
133 _gap_offset = other._gap_offset;
134 _gap_size = other._gap_size + _grow_size;
136 placement_copy(other.left_begin(), other.left_end(), left_begin());
137 placement_copy(other.right_begin(), other.right_end(), right_begin());
148 _gap_offset(other._gap_offset),
149 _gap_size(other._gap_size),
150 _allocator(other._allocator)
152 other._ptr =
nullptr;
154 other._gap_offset = 0;
163 tt_axiom(&other !=
this);
168 if (_allocator == other._allocator) {
172 std::swap(_gap_offset, other._gap_pffset);
177 if (_size >= other.size()) {
179 _gap_offset = other._gap_offset;
180 _gap_size = other._size - other.right_size();
182 placement_move(other.left_begin(), other.left_end(), left_begin());
183 placement_move(other.right_begin(), other.right_end(), right_begin());
187 if (_ptr !=
nullptr) {
188 _allocator.deallocate(_ptr, _size);
196 if (other._ptr !=
nullptr) {
197 _size = other.size() + _grow_size;
198 _ptr = _allocator.allocate(_size);
199 _gap_offset = other._gap_offset;
200 _gap_size = other._gap_size + _grow_size;
202 placement_move(other.left_begin(), other.left_end(), left_begin());
203 placement_move(other.right_begin(), other.right_end(), right_begin());
208 other._gap_offset = 0;
209 other._gap_size = other._size;
218 if (_ptr !=
nullptr) {
219 _allocator.deallocate(_ptr, _size);
231 tt_axiom(index < size());
232 return *get_pointer(index);
241 [[nodiscard]] const_reference
operator[](size_type index)
const noexcept
243 tt_axiom(index < size());
244 return *get_pointer(index);
255 if (index < size()) {
258 return (*
this)[index];
267 [[nodiscard]] const_reference
at(size_type index)
const
269 if (index < size()) {
272 return (*
this)[index];
277 tt_axiom(size() != 0);
281 [[nodiscard]] const_reference front() const noexcept
283 tt_axiom(size() != 0);
287 [[nodiscard]] reference back() noexcept
289 tt_axiom(size() != 0);
290 return *(
this)[size() - 1];
293 [[nodiscard]] const_reference back() const noexcept
295 tt_axiom(size() != 0);
296 return *(
this)[size() - 1];
299 void pop_back() noexcept
301 tt_axiom(size() != 0);
305 void pop_front() noexcept
307 tt_axiom(size() != 0);
321 std::destroy(left_begin(), left_end());
322 std::destroy(right_begin(), right_end());
328 [[nodiscard]]
size_t size() const noexcept
330 return _size - _gap_size;
333 [[nodiscard]]
bool empty() const noexcept
338 [[nodiscard]]
size_t capacity() const noexcept
343 void reserve(
size_t new_capacity)
noexcept
345 ttlet extra_capacity =
static_cast<ssize_t
>(new_capacity) - capacity();
346 if (extra_capacity <= 0) {
353 ttlet new_ptr = _allocator.allocate(new_capacity);
354 ttlet new_size = _size + extra_capacity;
355 ttlet new_gap_offset = _gap_offset;
356 ttlet new_gap_size = _gap_size + extra_capacity;
358 if (_ptr !=
nullptr) {
359 ttlet new_left_begin = new_ptr;
360 ttlet new_right_begin = new_ptr + new_gap_offset + new_gap_size;
361 placement_move(left_begin(), left_end(), new_left_begin);
362 placement_move(right_begin(), right_end(), new_right_begin);
363 _allocator.deallocate(_ptr, _size);
367 _gap_offset = new_gap_offset;
368 _gap_size = new_gap_size;
372 [[nodiscard]] iterator begin() noexcept
374 return make_gap_buffer_iterator(
this, 0);
377 [[nodiscard]] const_iterator begin() const noexcept
379 return make_gap_buffer_iterator(
this, 0);
382 [[nodiscard]] iterator cbegin() const noexcept
384 return make_gap_buffer_iterator(
this, 0);
387 [[nodiscard]] iterator end() noexcept
389 return make_gap_buffer_iterator(
this, narrow_cast<difference_type>(size()));
392 [[nodiscard]] const_iterator end() const noexcept
394 return make_gap_buffer_iterator(
this, narrow_cast<difference_type>(size()));
397 [[nodiscard]] iterator cend() const noexcept
399 return make_gap_buffer_iterator(
this, narrow_cast<difference_type>(size()));
402 template<
typename... Args>
403 void emplace_back(Args &&...args)
noexcept
405 set_gap_offset(size());
408 auto p = _ptr + _gap_offset;
409 new (p) value_type(std::forward<Args>(args)...);
414 void push_back(value_type
const &value)
noexcept
416 return emplace_back(value);
419 void push_back(value_type &&value)
noexcept
424 template<
typename... Args>
425 void emplace_front(Args &&...args)
noexcept
430 auto p = _ptr + _gap_offset + _gap_size - 1;
431 new (p) value_type(std::forward<Args>(args)...);
435 void push_front(value_type
const &value)
noexcept
437 return emplace_front(value);
440 void push_front(value_type &&value)
noexcept
447 template<
typename... Args>
450 tt_axiom(position.buffer() ==
this);
451 set_gap_offset(position.index());
454 auto p = _ptr + _gap_offset + _gap_size - 1;
455 new (p) value_type(std::forward<Args>(args)...);
460 iterator insert_before(iterator position, value_type
const &value)
noexcept
465 iterator insert_before(iterator position, value_type &&value)
noexcept
477 template<
typename It>
481 while (it != first) {
482 position = insert_before(position, *(--it));
489 template<
typename... Args>
492 tt_axiom(position.buffer() ==
this);
493 set_gap_offset(position.index() + 1);
496 auto p = _ptr + _gap_offset;
497 new (p) value_type(std::forward<Args>(args)...);
503 iterator insert_after(iterator position, value_type
const &value)
noexcept
508 iterator insert_after(iterator position, value_type &&value)
noexcept
520 template<
typename It>
523 for (
auto it = first; it != last; ++it) {
524 position = insert_after(position, *it);
537 tt_axiom(first.buffer() ==
this);
538 tt_axiom(last.buffer() ==
this);
540 set_gap_offset(first.index());
541 ttlet first_p = get_pointer(first.index());
542 ttlet last_p = get_pointer(last.index());
543 std::destroy(first_p, last_p);
544 _gap_size += last_p - first_p;
545 return make_gap_buffer_iterator(
this, _gap_offset);
554 return erase(position, position + 1);
559 if (lhs.size() != rhs.size()) {
566 template<
typename Container>
567 [[nodiscard]]
friend bool operator==(
gap_buffer const &lhs, Container
const &rhs)
noexcept
569 if (lhs.size() != rhs.size()) {
576 template<
typename Container>
577 [[nodiscard]]
friend bool operator==(Container
const &lhs,
gap_buffer const &rhs)
noexcept
579 if (lhs.size() != rhs.size()) {
588 static constexpr difference_type _grow_size = 256;
591 difference_type _size;
592 difference_type _gap_offset;
593 difference_type _gap_size;
594 [[no_unique_address]] allocator_type _allocator;
596 [[nodiscard]]
bool is_valid() const noexcept
598 return _size >= 0 && _gap_offset >= 0 && _gap_size >= 0 && _gap_offset + _gap_size <= _size &&
599 (_ptr !=
nullptr || (_size == 0 && _gap_offset == 0 && _gap_size == 0));
604 void grow_to_insert(size_type n)
noexcept
606 tt_axiom(is_valid());
608 if (n > narrow_cast<size_type>(_gap_size)) [[unlikely]] {
609 auto new_capacity = size() + n + narrow_cast<size_type>(_grow_size);
610 reserve(
ceil(new_capacity, hardware_constructive_interference_size));
619 [[nodiscard]] difference_type get_offset(difference_type index)
const noexcept
621 tt_axiom(is_valid());
622 tt_axiom(index >= 0 && index <= std::ssize(*
this));
623 if (index >= _gap_offset) {
634 pointer get_pointer(difference_type index)
noexcept
636 tt_axiom(is_valid());
637 tt_axiom(index >= 0);
638 return std::launder(_ptr + get_offset(index));
646 const_pointer get_pointer(difference_type index)
const noexcept
648 tt_axiom(is_valid());
649 tt_axiom(index >= 0);
650 return std::launder(_ptr + get_offset(index));
653 [[nodiscard]] value_type
const *left_begin() const noexcept
658 [[nodiscard]] value_type *left_begin() noexcept
663 [[nodiscard]] value_type
const *left_end() const noexcept
665 tt_axiom(is_valid());
666 return _ptr + _gap_offset;
669 [[nodiscard]] value_type *left_end() noexcept
671 tt_axiom(is_valid());
672 return _ptr + _gap_offset;
675 [[nodiscard]] value_type
const *right_begin() const noexcept
677 tt_axiom(is_valid());
678 return _ptr + _gap_offset + _gap_size;
681 [[nodiscard]] value_type *right_begin() noexcept
683 tt_axiom(is_valid());
684 return _ptr + _gap_offset + _gap_size;
687 [[nodiscard]] value_type
const *right_end() const noexcept
689 tt_axiom(is_valid());
693 [[nodiscard]] value_type *right_end() noexcept
695 tt_axiom(is_valid());
699 [[nodiscard]] value_type
const *gap_begin() const noexcept
701 tt_axiom(is_valid());
702 return _ptr + _gap_offset;
705 [[nodiscard]] value_type *gap_begin() noexcept
707 tt_axiom(is_valid());
708 return _ptr + _gap_offset;
711 [[nodiscard]] value_type
const *gap_end() const noexcept
713 tt_axiom(is_valid());
714 return _ptr + _gap_offset + _gap_size;
717 [[nodiscard]] value_type *gap_end() noexcept
719 tt_axiom(is_valid());
720 return _ptr + _gap_offset + _gap_size;
725 void set_gap_offset(difference_type new_gap_offset)
noexcept
727 ttlet new_gap_begin = _ptr + new_gap_offset;
728 ttlet new_gap_end = new_gap_begin + _gap_size;
730 if (new_gap_offset < _gap_offset) {
734 placement_move_within_array(new_gap_begin, gap_begin(), new_gap_end);
736 }
else if (new_gap_offset > _gap_offset) {
740 placement_move_within_array(gap_end(), new_gap_end, gap_begin());
743 _gap_offset = new_gap_offset;
746 friend gap_buffer_iterator<T>;
755 !std::is_volatile_v<T> && !std::is_reference_v<T>,
756 "Type of a managing container iterator can not be volatile nor a reference");
758 using value_type = std::remove_cv_t<T>;
759 using size_type = size_t;
760 using difference_type = ptrdiff_t;
762 using const_pointer = T
const *;
764 using const_reference = T
const &;
775 gap_buffer_iterator(gap_buffer_type *buffer, difference_type index) noexcept : _buffer(buffer), _index(index) {}
777 gap_buffer_type *buffer()
const noexcept
782 difference_type index()
const noexcept
789 return (*_buffer)[narrow_cast<size_type>(_index)];
792 const_reference operator*()
const noexcept
794 tt_axiom(is_valid());
795 return (*_buffer)[narrow_cast<size_type>(_index)];
798 reference operator[](std::integral
auto index)
noexcept
800 return (*_buffer)[narrow_cast<size_type>(_index + narrow_cast<difference_type>(index))];
803 const_reference operator[](std::integral
auto index)
const noexcept
805 return (*_buffer)[narrow_cast<size_type>(_index + narrow_cast<difference_type>(index))];
811 tt_axiom(is_valid());
819 tt_axiom(is_valid());
826 tt_axiom(is_valid());
834 tt_axiom(is_valid());
840 _index += narrow_cast<difference_type>(n);
841 tt_axiom(is_valid());
847 _index -= narrow_cast<difference_type>(n);
848 tt_axiom(is_valid());
869 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend difference_type
872 tt_axiom(lhs.is_valid(rhs));
873 return lhs._index - rhs._index;
877 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
880 tt_axiom(lhs.is_valid(rhs));
881 return lhs._index == rhs._index;
885 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
888 tt_axiom(lhs.is_valid(rhs));
889 return lhs._index != rhs._index;
893 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
896 tt_axiom(lhs.is_valid(rhs));
897 return lhs._index < rhs._index;
901 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
904 tt_axiom(lhs.is_valid(rhs));
905 return lhs._index < rhs._index;
909 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
912 tt_axiom(lhs.is_valid(rhs));
913 return lhs._index <= rhs._index;
917 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
920 tt_axiom(lhs.is_valid(rhs));
921 return lhs._index >= rhs._index;
925 gap_buffer_type *_buffer;
926 difference_type _index;
928 [[nodiscard]]
bool is_valid()
const noexcept
930 return _buffer !=
nullptr && _index >= 0 && _index <= std::ssize(*_buffer);
934 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<O>>)
937 return is_valid() && other.is_valid() && _buffer == other._buffer;