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;
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 _begin(nullptr), _it_end(nullptr), _gap_begin(nullptr), _gap_size(0), _allocator(allocator)
67 tt_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),
80 tt_axiom(holds_invariant());
91 _allocator(other._allocator)
93 tt_axiom(&other !=
this);
95 if (other._ptr !=
nullptr) {
96 _begin = _allocator.allocate(other.capacity());
97 _it_end = _begin + other.size();
98 _gap_begin = _begin + other.left_size();
99 _gap_size = other._gap_size;
101 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
102 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
104 tt_axiom(holds_invariant());
115 tt_return_on_self_assignment(other);
118 if (_gap_size >= other.size()) {
120 _gap_begin = _begin + other.left_size();
121 _gap_size = capacity() - other.size();
123 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
124 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
128 if (_begin !=
nullptr) {
129 _allocator.deallocate(_begin, capacity());
132 _gap_begin =
nullptr;
137 if (other._begin !=
nullptr) {
138 ttlet new_capacity = other.size() + _grow_size;
140 _begin = _allocator.allocate(new_capacity);
141 _it_end = _begin + other.size();
142 _gap_begin = _begin + other.left_begin_ptr();
143 _gap_size = new_capacity - other.size();
145 placement_copy(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
146 placement_copy(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
149 tt_axiom(holds_invariant());
156 _begin(other._begin),
157 _it_end(other._it_end),
158 _gap_begin(other._gap_begin),
159 _gap_size(other._gap_size),
160 _allocator(other._allocator)
162 tt_axiom(&other !=
this);
164 other._begin =
nullptr;
165 other._it_end =
nullptr;
166 other._gap_begin =
nullptr;
168 tt_axiom(holds_invariant());
176 tt_return_on_self_assignment(other);
181 if (_allocator == other._allocator) {
187 tt_axiom(holds_invariant());
190 }
else if (capacity() >= other.size()) {
192 _it_end = _begin + other.size();
193 _gap_begin = _begin + other.left_size();
194 _gap_size = capacity() - other.size();
196 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
197 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
200 ttlet other_capacity = other.capacity();
201 other._it_end = other._begin;
202 other._gap_begin = other._begin;
203 other._gap_size = other_capacity;
204 tt_axiom(holds_invariant());
209 if (_begin !=
nullptr) {
210 _allocator.deallocate(_begin, capacity());
213 _gap_begin =
nullptr;
218 if (other._begin !=
nullptr) {
219 ttlet new_capacity = other.size() + _grow_size;
221 _begin = _allocator.allocate(new_capacity);
222 _it_end = _begin + other.size();
223 _gap_begin = _begin + other.left_size();
224 _gap_size = new_capacity - other.size();
226 placement_move(other.left_begin_ptr(), other.left_end_ptr(), left_begin_ptr());
227 placement_move(other.right_begin_ptr(), other.right_end_ptr(), right_begin_ptr());
231 ttlet other_capacity = other.capacity();
232 other._it_end = other._begin;
233 other._gap_begin = other._begin;
234 other._gap_size = other_capacity;
235 tt_axiom(holds_invariant());
246 if (_begin !=
nullptr) {
247 _allocator.deallocate(_begin, capacity());
259 tt_axiom(index < size());
260 return *get_pointer_from_index(index);
269 [[nodiscard]] const_reference
operator[](size_type index)
const noexcept
271 tt_axiom(index < size());
272 return *get_pointer_from_index(index);
283 if (index < size()) {
286 return *get_pointer_from_index(index);
295 [[nodiscard]] const_reference
at(size_type index)
const
297 if (index < size()) {
300 return *get_pointer_from_index(index);
305 tt_axiom(size() != 0);
306 return *get_pointer_from_it_ptr(_begin);
309 [[nodiscard]] const_reference front() const noexcept
311 tt_axiom(size() != 0);
312 return *get_pointer_from_it_ptr(_begin);
315 [[nodiscard]] reference back() noexcept
317 tt_axiom(size() != 0);
318 return *get_pointer_from_it_ptr(_it_end - 1);
321 [[nodiscard]] const_reference back() const noexcept
323 tt_axiom(size() != 0);
324 return *get_pointer_from_it_ptr(_it_end - 1);
327 void pop_back() noexcept
329 tt_axiom(size() != 0);
333 void pop_front() noexcept
335 tt_axiom(size() != 0);
349 std::destroy(left_begin_ptr(), left_end_ptr());
350 std::destroy(right_begin_ptr(), right_end_ptr());
351 ttlet this_capacity = capacity();
354 _gap_size = this_capacity;
356 tt_axiom(holds_invariant());
359 [[nodiscard]]
size_t size() const noexcept
361 return static_cast<size_t>(_it_end - _begin);
364 [[nodiscard]]
bool empty() const noexcept
369 [[nodiscard]]
size_t capacity() const noexcept
371 return size() + _gap_size;
374 void reserve(
size_t new_capacity)
noexcept
376 ttlet extra_capacity =
static_cast<ssize_t
>(new_capacity) - capacity();
377 if (extra_capacity <= 0) {
384 ttlet new_begin = _allocator.allocate(new_capacity);
385 ttlet new_it_end = new_begin + size();
386 ttlet new_gap_begin = new_begin + left_size();
387 ttlet new_gap_size = new_capacity - size();
389 if (_begin !=
nullptr) {
390 placement_move(left_begin_ptr(), left_end_ptr(), new_begin);
391 placement_move(right_begin_ptr(), right_end_ptr(), new_gap_begin + new_gap_size);
392 _allocator.deallocate(_begin, capacity());
396 _it_end = new_it_end;
397 _gap_begin = new_gap_begin;
398 _gap_size = new_gap_size;
399 tt_axiom(holds_invariant());
402 [[nodiscard]] iterator begin() noexcept
404 return iterator{
this, _begin};
407 [[nodiscard]] const_iterator begin() const noexcept
409 return const_iterator{
this, _begin};
412 [[nodiscard]] const_iterator cbegin() const noexcept
414 return const_iterator{
this, _begin};
417 [[nodiscard]] iterator end() noexcept
419 return iterator{
this, _it_end};
422 [[nodiscard]] const_iterator end() const noexcept
424 return const_iterator{
this, _it_end};
427 [[nodiscard]] const_iterator cend() const noexcept
429 return const_iterator{
this, _it_end};
432 template<
typename... Args>
433 reference emplace_back(Args &&...args)
noexcept
438 void push_back(value_type
const &value)
noexcept
443 void push_back(value_type &&value)
noexcept
448 template<
typename... Args>
449 reference emplace_front(Args &&...args)
noexcept
451 set_gap_offset(_begin);
454 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
457#if TT_BUILT_TYPE == TT_BT_DEBUG
460 tt_axiom(holds_invariant());
464 void push_front(value_type
const &value)
noexcept
466 emplace_front(value);
469 void push_front(value_type &&value)
noexcept
478 template<
typename... Args>
481 tt_axiom(position._buffer ==
this);
482 set_gap_offset(position.it_rw_ptr());
485 auto ptr =
new (right_begin_ptr() - 1) value_type(std::forward<Args>(args)...);
488#if TT_BUILT_TYPE == TT_BT_DEBUG
491 tt_axiom(holds_invariant());
502 return iterator{
this, get_it_from_pointer(ptr)};
512 return iterator{
this, get_it_from_pointer(ptr)};
524 template<
typename It>
530 while (it != first) {
533 tt_axiom(holds_invariant());
541 template<
typename... Args>
544 tt_axiom(position._buffer ==
this);
545 set_gap_offset(position.it_rw_ptr());
548 auto ptr =
new (left_end_ptr()) value_type(std::forward<Args>(args)...);
552#if TT_BUILT_TYPE == TT_BT_DEBUG
555 tt_axiom(holds_invariant());
566 return iterator{
this, get_it_from_pointer(ptr)};
576 return iterator{
this, get_it_from_pointer(ptr)};
586 template<
typename It>
589 auto position_ =
iterator{position};
590 for (
auto it = first; it != last; ++it) {
593 tt_axiom(holds_invariant());
606 tt_axiom(first._buffer ==
this);
607 tt_axiom(last._buffer ==
this);
609 set_gap_offset(last.it_rw_ptr());
610 auto first_p = first.it_rw_ptr();
611 auto last_p = last.it_rw_ptr();
612 ttlet erase_size = last_p - first_p;
614 std::destroy(first_p, last_p);
615 _gap_begin = first_p;
616 _gap_size += erase_size;
617 _it_end -= erase_size;
618 tt_axiom(holds_invariant());
628 return erase(position, position + 1);
633 if (lhs.size() != rhs.size()) {
640 template<
typename Container>
641 [[nodiscard]]
friend bool operator==(
gap_buffer const &lhs, Container
const &rhs)
noexcept
643 if (lhs.size() != rhs.size()) {
650 template<
typename Container>
651 [[nodiscard]]
friend bool operator==(Container
const &lhs,
gap_buffer const &rhs)
noexcept
653 if (lhs.size() != rhs.size()) {
662 static constexpr difference_type _grow_size = 256;
675 value_type *_gap_begin;
681#if TT_BUILT_TYPE == TT_BT_DEBUG
685 [[no_unique_address]] allocator_type _allocator;
687 [[nodiscard]]
bool holds_invariant() const noexcept
689 return (_begin ==
nullptr and _it_end ==
nullptr and _gap_begin ==
nullptr and _gap_size == 0) or
690 (_begin <= _gap_begin and _gap_begin <= _it_end);
695 void grow_to_insert(size_type n)
noexcept
697 if (n > _gap_size) [[unlikely]] {
698 auto new_capacity = size() + n + narrow_cast<size_type>(_grow_size);
699 reserve(
ceil(new_capacity, hardware_constructive_interference_size));
701 tt_axiom(holds_invariant());
706 const_pointer get_it_from_pointer(const_pointer ptr)
const noexcept
708 if (ptr < _gap_begin) {
711 return ptr - _gap_size;
717 pointer get_it_from_pointer(pointer ptr)
noexcept
719 if (ptr < _gap_begin) {
722 return ptr - _gap_size;
731 const_pointer get_const_pointer_from_it(const_pointer it_ptr)
const noexcept
733 tt_axiom(it_ptr >= _begin && it_ptr <= _it_end);
735 if (it_ptr < _gap_begin) {
738 return it_ptr + _gap_size;
742 const_pointer get_pointer_from_it(pointer it_ptr)
const noexcept
744 return get_const_pointer_from_it(it_ptr);
747 pointer get_pointer_from_it(pointer it_ptr)
noexcept
749 return const_cast<pointer
>(get_const_pointer_from_it(it_ptr));
757 const_pointer get_const_pointer_from_index(size_type index)
const noexcept
759 return get_const_pointer_from_it(_begin + index);
762 const_pointer get_pointer_from_index(size_type index)
const noexcept
764 return get_const_pointer_from_it(_begin + index);
767 pointer get_pointer_from_index(size_type index)
noexcept
769 return get_pointer_from_it(_begin + index);
772 [[nodiscard]] value_type
const *left_begin_ptr() const noexcept
777 [[nodiscard]] value_type *left_begin_ptr() noexcept
782 [[nodiscard]] value_type
const *left_end_ptr() const noexcept
787 [[nodiscard]] value_type *left_end_ptr() noexcept
792 [[nodiscard]] size_type left_size() const noexcept
794 return static_cast<size_type
>(_gap_begin - _begin);
797 [[nodiscard]] value_type
const *right_begin_ptr() const noexcept
799 return _gap_begin + _gap_size;
802 [[nodiscard]] value_type *right_begin_ptr() noexcept
804 return _gap_begin + _gap_size;
807 [[nodiscard]] value_type
const *right_end_ptr() const noexcept
809 return _it_end + _gap_size;
812 [[nodiscard]] value_type *right_end_ptr() noexcept
814 return _it_end + _gap_size;
817 [[nodiscard]] size_type right_size() const noexcept
819 return _it_end - _gap_begin;
825 void set_gap_offset(value_type *new_gap_begin)
noexcept
827 if (new_gap_begin < _gap_begin) {
831 placement_move_within_array(new_gap_begin, _gap_begin, new_gap_begin + _gap_size);
833 }
else if (new_gap_begin > _gap_begin) {
837 placement_move_within_array(_gap_begin + _gap_size, new_gap_begin + _gap_size, _gap_begin);
840 _gap_begin = new_gap_begin;
841 tt_axiom(holds_invariant());
844 template<
typename IT>
845 friend class gap_buffer_iterator;
854 !std::is_volatile_v<T> && !std::is_reference_v<T>,
855 "Type of a managing container iterator can not be volatile nor a reference");
857 static constexpr bool is_const = std::is_const_v<T>;
859 using value_type = std::remove_cv_t<T>;
860 using size_type = size_t;
861 using difference_type = ptrdiff_t;
863 using const_pointer = value_type
const *;
865 using const_reference = value_type
const &;
868 using gap_buffer_type = std::conditional_t<is_const, gap_buffer<value_type>
const,
gap_buffer<value_type>>;
883#if TT_BUILT_TYPE == TT_BT_DEBUG
884 _version = other._version;
886 tt_axiom(holds_invariant());
890 gap_buffer_type *buffer,
892#
if TT_BUILT_TYPE == TT_BT_DEBUG
898#if TT_BUILT_TYPE == TT_BT_DEBUG
902 tt_axiom(holds_invariant());
905 reference operator*()
noexcept requires(!is_const)
907 return *(_buffer->get_pointer_from_it(_it_ptr));
910 const_reference operator*()
const noexcept
912 return *(_buffer->get_const_pointer_from_it(_it_ptr));
915 pointer operator->()
noexcept requires(!is_const)
917 return _buffer->get_pointer_from_it(_it_ptr);
920 const_pointer operator->()
const noexcept
922 return _buffer->get_const_pointer_from_it(_it_ptr);
925 reference operator[](std::integral
auto index)
noexcept requires(!is_const)
927 return *(_buffer->get_pointer_from_it(_it_ptr + index));
930 const_reference operator[](std::integral
auto index)
const noexcept
932 return *(_buffer->get_const_pointer_from_it(_it_ptr + index));
938 tt_axiom(holds_invariant());
946 tt_axiom(holds_invariant());
953 tt_axiom(holds_invariant());
961 tt_axiom(holds_invariant());
968 tt_axiom(holds_invariant());
975 tt_axiom(holds_invariant());
996 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend difference_type
999 return lhs._it_ptr - rhs._it_ptr;
1002 template<
typename R>
1003 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend bool
1006 return lhs._it_ptr == rhs.it_ptr();
1009 template<
typename R>
1010 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<R>>)
friend auto
1013 return lhs._it_ptr <=> rhs.it_ptr();
1017 gap_buffer_type *_buffer;
1019#if TT_BUILT_TYPE == TT_BT_DEBUG
1024 _buffer(
const_cast<gap_buffer_type *
>(other._buffer)), _it_ptr(
const_cast<T *
>(other._it_ptr))
1026#if TT_BUILT_TYPE == TT_BT_DEBUG
1027 _version = other._version;
1029 tt_axiom(holds_invariant());
1032 [[nodiscard]] T *it_ptr()
const noexcept
1037 [[nodiscard]] std::remove_cv_t<T> *it_rw_ptr()
const noexcept
1039 return const_cast<std::remove_cv_t<T> *
>(_it_ptr);
1042 [[nodiscard]]
bool holds_invariant()
const noexcept
1046 and _it_ptr >= _buffer->_begin
1047 and _it_ptr <= _buffer->_it_end
1048#if TT_BUILT_TYPE == TT_BT_DEBUG
1049 and _version == _buffer->_version
1054 template<
typename O>
1055 requires(std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<O>>)
1058 return holds_invariant() and other.holds_invariant() and _buffer == other._buffer;