From 2055c9d5cbbd347dbe350a271a995a9c358c1a0e Mon Sep 17 00:00:00 2001 From: Slaven Falandys Date: Fri, 14 Jun 2024 23:20:11 +0200 Subject: [PATCH] Refactoring iterators for segmented vector and devector --- include/sfl/private.hpp | 261 +++++++++++++++ include/sfl/segmented_devector.hpp | 492 ++++------------------------- include/sfl/segmented_vector.hpp | 462 +++------------------------ 3 files changed, 366 insertions(+), 849 deletions(-) diff --git a/include/sfl/private.hpp b/include/sfl/private.hpp index 3c8b4d1..84bb51e 100644 --- a/include/sfl/private.hpp +++ b/include/sfl/private.hpp @@ -417,6 +417,267 @@ class normal_iterator } }; +template +class segmented_iterator +{ + template + friend class segmented_iterator; + + friend Container; + + template + friend struct sfl::dtl::segmented_iterator_traits; + +private: + + SegmentIterator segment_; + LocalIterator local_; + +public: + + using difference_type = typename std::iterator_traits::difference_type; + using value_type = typename std::iterator_traits::value_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + using iterator_category = typename std::iterator_traits::iterator_category; + +private: + + explicit segmented_iterator(const SegmentIterator& segment, const LocalIterator& local) noexcept + : segment_(segment) + , local_(local) + {} + +public: + + // Default constructor + segmented_iterator() noexcept + : segment_() + , local_() + {} + + // Copy constructor + segmented_iterator(const segmented_iterator& other) noexcept + : segment_(other.segment_) + , local_(other.local_) + {} + + // Converting constructor (from iterator to const_iterator) + template ::value && + std::is_convertible::value >* = nullptr > + segmented_iterator(const segmented_iterator& other) noexcept + : segment_(other.segment_) + , local_(other.local_) + {} + + // Copy assignment operator + segmented_iterator& operator=(const segmented_iterator& other) noexcept + { + segment_ = other.segment_; + local_ = other.local_; + return *this; + } + + SFL_NODISCARD + reference operator*() const noexcept + { + return *local_; + } + + SFL_NODISCARD + pointer operator->() const noexcept + { + return sfl::dtl::to_address(local_); + } + + segmented_iterator& operator++() noexcept + { + ++local_; + + if (local_ == *segment_ + SegmentSize) + { + ++segment_; + local_ = *segment_; + } + + return *this; + } + + segmented_iterator operator++(int) noexcept + { + auto temp = *this; + this->operator++(); + return temp; + } + + segmented_iterator& operator--() noexcept + { + if (local_ == *segment_) + { + --segment_; + local_ = *segment_ + SegmentSize; + } + + --local_; + + return *this; + } + + segmented_iterator operator--(int) noexcept + { + auto temp = *this; + this->operator--(); + return temp; + } + + segmented_iterator& operator+=(difference_type n) noexcept + { + const difference_type offset = std::distance(LocalIterator(*segment_), local_) + n; + + if (offset >= 0 && offset < difference_type(SegmentSize)) + { + local_ += n; + } + else + { + const difference_type segment_offset = + offset > 0 + ? offset / difference_type(SegmentSize) + : -difference_type((-offset - 1) / SegmentSize) - 1; + + segment_ += segment_offset; + + local_ = *segment_ + (offset - segment_offset * difference_type(SegmentSize)); + } + + return *this; + } + + segmented_iterator& operator-=(difference_type n) noexcept + { + return this->operator+=(-n); + } + + SFL_NODISCARD + segmented_iterator operator+(difference_type n) const noexcept + { + auto temp = *this; + temp += n; + return temp; + } + + SFL_NODISCARD + segmented_iterator operator-(difference_type n) const noexcept + { + auto temp = *this; + temp -= n; + return temp; + } + + SFL_NODISCARD + reference operator[](difference_type n) const noexcept + { + auto temp = *this; + temp += n; + return *temp; + } + + SFL_NODISCARD + friend segmented_iterator operator+(difference_type n, const segmented_iterator& it) noexcept + { + return it + n; + } + + SFL_NODISCARD + friend difference_type operator-(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return (x.segment_ - y.segment_) * difference_type(SegmentSize) + + (x.local_ - *x.segment_) - (y.local_ - *y.segment_); + } + + SFL_NODISCARD + friend bool operator==(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return x.local_ == y.local_; + } + + SFL_NODISCARD + friend bool operator!=(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return !(x == y); + } + + SFL_NODISCARD + friend bool operator<(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return (x.segment_ == y.segment_) ? (x.local_ < y.local_) : (x.segment_ < y.segment_); + } + + SFL_NODISCARD + friend bool operator>(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return y < x; + } + + SFL_NODISCARD + friend bool operator<=(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return !(y < x); + } + + SFL_NODISCARD + friend bool operator>=(const segmented_iterator& x, const segmented_iterator& y) noexcept + { + return !(x < y); + } +}; + +template +struct segmented_iterator_traits> +{ + using is_segmented_iterator = std::true_type; + + using iterator = sfl::dtl::segmented_iterator; + + using segment_iterator = SegmentIterator; + + using local_iterator = LocalIterator; + + static segment_iterator segment(iterator it) noexcept + { + return it.segment_; + } + + static local_iterator local(iterator it) noexcept + { + return it.local_; + } + + static local_iterator begin(segment_iterator it) noexcept + { + return *it; + } + + static local_iterator end(segment_iterator it) noexcept + { + return *it + SegmentSize; + } + + static iterator compose(segment_iterator segment, local_iterator local) noexcept + { + SFL_ASSERT(begin(segment) <= local && local <= end(segment)); + + if (local == end(segment)) + { + ++segment; + local = begin(segment); + } + + return iterator(segment, local); + } +}; + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // INITIALIZED MEMORY ALGORITHMS diff --git a/include/sfl/segmented_devector.hpp b/include/sfl/segmented_devector.hpp index 01859f7..91fd102 100644 --- a/include/sfl/segmented_devector.hpp +++ b/include/sfl/segmented_devector.hpp @@ -35,370 +35,36 @@ namespace sfl { -template < typename ValueType, // std::iterator_traits::value_type - typename Pointer, // std::iterator_traits::pointer - typename Reference, // std::iterator_traits::reference - typename DifferenceType, // std::iterator_traits::difference_type - typename SegmentPointer, // Non-const pointer to segment. - typename ElementPointer, // Non-const pointer to element. - std::size_t N > -class segmented_devector_iterator +template < typename T, + std::size_t N, + typename Allocator = std::allocator > +class segmented_devector { - template - friend class segmented_devector_iterator; - - template - friend class segmented_devector; - -public: - - using value_type = ValueType; - using pointer = Pointer; - using reference = Reference; - using difference_type = DifferenceType; - using iterator_category = std::random_access_iterator_tag; - -private: - - using segment_pointer = SegmentPointer; - using element_pointer = ElementPointer; - - segment_pointer seg_; - element_pointer elem_; + static_assert(N > 0, "N must be greater than zero."); public: - /// Default constructor. - segmented_devector_iterator() noexcept - {} - - /// Copy constructor. - segmented_devector_iterator(const segmented_devector_iterator& other) noexcept - : seg_(other.seg_) - , elem_(other.elem_) - {} - - /// Converting constructor (from iterator to const_iterator). - template ::value>* = nullptr> - segmented_devector_iterator - ( - const segmented_devector_iterator< - ValueType, - OtherPointer, - OtherReference, - DifferenceType, - SegmentPointer, - ElementPointer, - N - >& other - ) noexcept - : seg_(other.seg_) - , elem_(other.elem_) - {} - - /// Copy assignment operator. - segmented_devector_iterator& operator=(const segmented_devector_iterator& other) noexcept - { - seg_ = other.seg_; - elem_ = other.elem_; - return *this; - } - - SFL_NODISCARD - reference operator*() const noexcept - { - return *elem_; - } - - SFL_NODISCARD - pointer operator->() const noexcept - { - return elem_; - } - - segmented_devector_iterator& operator++() noexcept - { - increment_once(); - return *this; - } - - segmented_devector_iterator operator++(int) noexcept - { - auto temp = *this; - increment_once(); - return temp; - } - - segmented_devector_iterator& operator--() noexcept - { - decrement_once(); - return *this; - } - - segmented_devector_iterator operator--(int) noexcept - { - auto temp = *this; - decrement_once(); - return temp; - } - - segmented_devector_iterator& operator+=(difference_type n) noexcept - { - advance(n); - return *this; - } - - segmented_devector_iterator& operator-=(difference_type n) noexcept - { - advance(-n); - return *this; - } - - SFL_NODISCARD - segmented_devector_iterator operator+(difference_type n) const noexcept - { - auto temp = *this; - temp.advance(n); - return temp; - } - - SFL_NODISCARD - segmented_devector_iterator operator-(difference_type n) const noexcept - { - auto temp = *this; - temp.advance(-n); - return temp; - } - - SFL_NODISCARD - reference operator[](difference_type n) const noexcept - { - auto temp = *this; - temp.advance(n); - return *temp; - } - - SFL_NODISCARD - friend segmented_devector_iterator operator+ - ( - difference_type n, - const segmented_devector_iterator& it - ) noexcept - { - return it + n; - } - - SFL_NODISCARD - friend difference_type operator- - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return (x.seg_ - y.seg_) * difference_type(N) - + (x.elem_ - *x.seg_) - (y.elem_ - *y.seg_); - } - - SFL_NODISCARD - friend bool operator== - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return x.elem_ == y.elem_; - } - - SFL_NODISCARD - friend bool operator!= - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return !(x == y); - } - - SFL_NODISCARD - friend bool operator< - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return (x.seg_ == y.seg_) ? (x.elem_ < y.elem_) : (x.seg_ < y.seg_); - } - - SFL_NODISCARD - friend bool operator> - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return y < x; - } - - SFL_NODISCARD - friend bool operator<= - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return !(y < x); - } - - SFL_NODISCARD - friend bool operator>= - ( - const segmented_devector_iterator& x, - const segmented_devector_iterator& y - ) noexcept - { - return !(x < y); - } + using allocator_type = Allocator; + using allocator_traits = std::allocator_traits; + using value_type = T; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + using reference = T&; + using const_reference = const T&; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; private: - segmented_devector_iterator(segment_pointer seg, element_pointer elem) noexcept - : seg_(seg) - , elem_(elem) - {} - - void increment_once() noexcept - { - ++elem_; - - if (elem_ == *seg_ + N) - { - ++seg_; - elem_ = *seg_; - } - } - - void decrement_once() noexcept - { - if (elem_ == *seg_) - { - --seg_; - elem_ = *seg_ + N; - } - - --elem_; - } - - void advance(difference_type n) noexcept - { - const difference_type offset = n + (elem_ - *seg_); - - if (offset >= 0 && offset < difference_type(N)) - { - elem_ += n; - } - else - { - const difference_type seg_offset = - offset > 0 ? offset / difference_type(N) - : -difference_type((-offset - 1) / N) - 1; - - seg_ += seg_offset; - - elem_ = *seg_ + (offset - seg_offset * difference_type(N)); - } - } - - template - friend struct sfl::dtl::segmented_iterator_traits; -}; - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -namespace dtl -{ - -template < typename ValueType, - typename Pointer, - typename Reference, - typename DifferenceType, - typename SegmentPointer, - typename ElementPointer, - std::size_t N > -struct segmented_iterator_traits< segmented_devector_iterator< - ValueType, Pointer, Reference, DifferenceType, SegmentPointer, ElementPointer, N > > -{ - using is_segmented_iterator = std::true_type; - - using iterator = segmented_devector_iterator< ValueType, Pointer, - Reference, DifferenceType, SegmentPointer, ElementPointer, N >; - - using segment_iterator = SegmentPointer; - using local_iterator = ElementPointer; - - static segment_iterator segment(iterator it) noexcept - { - return it.seg_; - } - - static local_iterator local(iterator it) noexcept - { - return it.elem_; - } - - static local_iterator begin(segment_iterator it) noexcept - { - return *it; - } - - static local_iterator end(segment_iterator it) noexcept - { - return *it + N; - } - - static iterator compose(segment_iterator seg, local_iterator elem) noexcept - { - SFL_ASSERT(*seg <= elem && elem <= *seg + N); - - if (elem == *seg + N) - { - ++seg; - elem = *seg; - } - - return iterator(seg, elem); - } -}; - -} // namespace dtl - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -template < typename T, - std::size_t N, - typename Allocator = std::allocator > -class segmented_devector -{ - static_assert(N > 0, "N must be greater than zero."); + using segment_allocator = typename std::allocator_traits::template rebind_alloc; + using segment_pointer = typename std::allocator_traits::pointer; public: - using allocator_type = Allocator; - using allocator_traits = std::allocator_traits; - using value_type = T; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; - using reference = T&; - using const_reference = const T&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using iterator = sfl::dtl::segmented_iterator; + using const_iterator = sfl::dtl::segmented_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; static_assert ( @@ -410,44 +76,6 @@ class segmented_devector static constexpr size_type segment_capacity = N; -private: - - using segment_allocator = - typename std::allocator_traits::template rebind_alloc; - - using segment_pointer = - typename std::allocator_traits::pointer; - -public: - - using iterator = - sfl::segmented_devector_iterator< - value_type, - pointer, - reference, - difference_type, - segment_pointer, - pointer, - N - >; - - using const_iterator = - sfl::segmented_devector_iterator< - value_type, - const_pointer, - const_reference, - difference_type, - segment_pointer, - pointer, - N - >; - - using reverse_iterator = - std::reverse_iterator; - - using const_reverse_iterator = - std::reverse_iterator; - private: class data_base @@ -910,7 +538,7 @@ class segmented_devector { SFL_ASSERT(cbegin() <= pos && pos <= cend()); - iterator p1(pos.seg_, pos.elem_); + iterator p1 = begin() + std::distance(cbegin(), pos); const size_type dist_to_begin = std::distance(cbegin(), pos); const size_type dist_to_end = std::distance(pos, cend()); @@ -1147,7 +775,7 @@ class segmented_devector const size_type dist_to_begin = std::distance(cbegin(), pos); const size_type dist_to_end = std::distance(pos, cend()); - const iterator p1 = iterator(pos.seg_, pos.elem_); + const iterator p1 = begin() + std::distance(cbegin(), pos); const iterator p2 = ++iterator(p1); if (dist_to_begin < dist_to_end) @@ -1176,7 +804,7 @@ class segmented_devector if (first == last) { - return iterator(first.seg_, first.elem_); + return begin() + std::distance(cbegin(), first); } const size_type dist_to_begin = std::distance(cbegin(), first); @@ -1184,8 +812,8 @@ class segmented_devector if (dist_to_begin < dist_to_end) { - const iterator p1(first.seg_, first.elem_); - const iterator p2(last.seg_, last.elem_); + const iterator p1 = begin() + std::distance(cbegin(), first); + const iterator p2 = begin() + std::distance(cbegin(), last); const iterator new_first = sfl::dtl::move_backward(data_.first_, p1, p2); @@ -1197,8 +825,8 @@ class segmented_devector } else { - const iterator p1(first.seg_, first.elem_); - const iterator p2(last.seg_, last.elem_); + const iterator p1 = begin() + std::distance(cbegin(), first); + const iterator p2 = begin() + std::distance(cbegin(), last); const iterator new_last = sfl::dtl::move(p2, data_.last_, p1); @@ -1656,11 +1284,11 @@ class segmented_devector { allocate_segments(data_.table_first_, data_.table_last_); - data_.bos_.seg_ = data_.table_first_; - data_.bos_.elem_ = *data_.table_first_; + data_.bos_.segment_ = data_.table_first_; + data_.bos_.local_ = *data_.table_first_; - data_.eos_.seg_ = (data_.table_last_ - 1); - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = (data_.table_last_ - 1); + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); data_.first_ = data_.bos_; @@ -1725,11 +1353,11 @@ class segmented_devector // Distance (in segments) from BEGIN of storage to FIRST element. const size_type dist1 = - std::distance(data_.bos_.seg_, data_.first_.seg_); + std::distance(data_.bos_.segment_, data_.first_.segment_); // Distance (in segments) from BEGIN of storage to LAST element. const size_type dist2 = - std::distance(data_.bos_.seg_, data_.last_.seg_); + std::distance(data_.bos_.segment_, data_.last_.segment_); // Allocate new table. No effects if allocation fails. const segment_pointer new_table_bos = @@ -1760,10 +1388,10 @@ class segmented_devector data_.table_last_ = new_table_last; // Update iterators (noexcept). - data_.bos_.seg_ = data_.table_first_; - data_.eos_.seg_ = data_.table_last_ - 1; - data_.first_.seg_ = data_.table_first_ + dist1; - data_.last_.seg_ = data_.table_first_ + dist2; + data_.bos_.segment_ = data_.table_first_; + data_.eos_.segment_ = data_.table_last_ - 1; + data_.first_.segment_ = data_.table_first_ + dist1; + data_.last_.segment_ = data_.table_first_ + dist2; } const segment_pointer new_table_first = @@ -1776,8 +1404,8 @@ class segmented_devector data_.table_first_ = new_table_first; // Update iterators (noexcept). - data_.bos_.seg_ = data_.table_first_; - data_.bos_.elem_ = *data_.table_first_; + data_.bos_.segment_ = data_.table_first_; + data_.bos_.local_ = *data_.table_first_; } // Increases capacity at the back for given number of elements. @@ -1813,11 +1441,11 @@ class segmented_devector // Distance (in segments) from BEGIN of storage to FIRST element. const size_type dist1 = - std::distance(data_.bos_.seg_, data_.first_.seg_); + std::distance(data_.bos_.segment_, data_.first_.segment_); // Distance (in segments) from BEGIN of storage to LAST element. const size_type dist2 = - std::distance(data_.bos_.seg_, data_.last_.seg_); + std::distance(data_.bos_.segment_, data_.last_.segment_); // Allocate new table. No effects if allocation fails. const segment_pointer new_table_bos = @@ -1849,10 +1477,10 @@ class segmented_devector data_.table_last_ = new_table_last; // Update iterators (noexcept). - data_.bos_.seg_ = data_.table_first_; - data_.eos_.seg_ = data_.table_last_ - 1; - data_.first_.seg_ = data_.table_first_ + dist1; - data_.last_.seg_ = data_.table_first_ + dist2; + data_.bos_.segment_ = data_.table_first_; + data_.eos_.segment_ = data_.table_last_ - 1; + data_.first_.segment_ = data_.table_first_ + dist1; + data_.last_.segment_ = data_.table_first_ + dist2; } const segment_pointer new_table_last = @@ -1865,8 +1493,8 @@ class segmented_devector data_.table_last_ = new_table_last; // Update iterators (noexcept). - data_.eos_.seg_ = data_.table_last_ - 1; - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = data_.table_last_ - 1; + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); } // Removes unused capacity. @@ -1877,26 +1505,26 @@ class segmented_devector { // Destroy empty segments at front. { - const segment_pointer new_table_first = data_.first_.seg_; + const segment_pointer new_table_first = data_.first_.segment_; deallocate_segments(data_.table_first_, new_table_first); data_.table_first_ = new_table_first; - data_.bos_.seg_ = data_.table_first_; - data_.bos_.elem_ = *data_.table_first_; + data_.bos_.segment_ = data_.table_first_; + data_.bos_.local_ = *data_.table_first_; } // Destroy empty segments at back. { - const segment_pointer new_table_last = data_.last_.seg_ + 1; + const segment_pointer new_table_last = data_.last_.segment_ + 1; deallocate_segments(new_table_last, data_.table_last_); data_.table_last_ = new_table_last; - data_.eos_.seg_ = (data_.table_last_ - 1); - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = (data_.table_last_ - 1); + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); } // Shrink table. @@ -1912,7 +1540,7 @@ class segmented_devector // Distance (in segments) from FIRST element to LAST element. const size_type dist = - std::distance(data_.first_.seg_, data_.last_.seg_); + std::distance(data_.first_.segment_, data_.last_.segment_); // Allocate new table. No effects if allocation fails. const segment_pointer new_table_bos = @@ -1942,10 +1570,10 @@ class segmented_devector data_.table_last_ = new_table_last; // Update iterators (noexcept). - data_.bos_.seg_ = data_.table_first_; - data_.eos_.seg_ = data_.table_last_ - 1; - data_.first_.seg_ = data_.table_first_; - data_.last_.seg_ = data_.table_first_ + dist; + data_.bos_.segment_ = data_.table_first_; + data_.eos_.segment_ = data_.table_last_ - 1; + data_.first_.segment_ = data_.table_first_; + data_.last_.segment_ = data_.table_first_ + dist; } } @@ -2511,7 +2139,7 @@ class segmented_devector { if (n == 0) { - return iterator(pos.seg_, pos.elem_); + return begin() + std::distance(cbegin(), pos); } const value_type tmp(value); @@ -2694,7 +2322,7 @@ class segmented_devector { if (first == last) { - return iterator(pos.seg_, pos.elem_); + return begin() + std::distance(cbegin(), pos); } const size_type n = std::distance(first, last); diff --git a/include/sfl/segmented_vector.hpp b/include/sfl/segmented_vector.hpp index 54a88c4..1f5bf61 100644 --- a/include/sfl/segmented_vector.hpp +++ b/include/sfl/segmented_vector.hpp @@ -35,370 +35,36 @@ namespace sfl { -template < typename ValueType, // std::iterator_traits::value_type - typename Pointer, // std::iterator_traits::pointer - typename Reference, // std::iterator_traits::reference - typename DifferenceType, // std::iterator_traits::difference_type - typename SegmentPointer, // Non-const pointer to segment. - typename ElementPointer, // Non-const pointer to element. - std::size_t N > -class segmented_vector_iterator +template < typename T, + std::size_t N, + typename Allocator = std::allocator > +class segmented_vector { - template - friend class segmented_vector_iterator; - - template - friend class segmented_vector; + static_assert(N > 0, "N must be greater than zero."); public: - using value_type = ValueType; - using pointer = Pointer; - using reference = Reference; - using difference_type = DifferenceType; - using iterator_category = std::random_access_iterator_tag; + using allocator_type = Allocator; + using allocator_traits = std::allocator_traits; + using value_type = T; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + using reference = T&; + using const_reference = const T&; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; private: - using segment_pointer = SegmentPointer; - using element_pointer = ElementPointer; - - segment_pointer seg_; - element_pointer elem_; + using segment_allocator = typename std::allocator_traits::template rebind_alloc; + using segment_pointer = typename std::allocator_traits::pointer; public: - /// Default constructor. - segmented_vector_iterator() noexcept - {} - - /// Copy constructor. - segmented_vector_iterator(const segmented_vector_iterator& other) noexcept - : seg_(other.seg_) - , elem_(other.elem_) - {} - - /// Converting constructor (from iterator to const_iterator). - template ::value>* = nullptr> - segmented_vector_iterator - ( - const segmented_vector_iterator< - ValueType, - OtherPointer, - OtherReference, - DifferenceType, - SegmentPointer, - ElementPointer, - N - >& other - ) noexcept - : seg_(other.seg_) - , elem_(other.elem_) - {} - - /// Copy assignment operator. - segmented_vector_iterator& operator=(const segmented_vector_iterator& other) noexcept - { - seg_ = other.seg_; - elem_ = other.elem_; - return *this; - } - - SFL_NODISCARD - reference operator*() const noexcept - { - return *elem_; - } - - SFL_NODISCARD - pointer operator->() const noexcept - { - return elem_; - } - - segmented_vector_iterator& operator++() noexcept - { - increment_once(); - return *this; - } - - segmented_vector_iterator operator++(int) noexcept - { - auto temp = *this; - increment_once(); - return temp; - } - - segmented_vector_iterator& operator--() noexcept - { - decrement_once(); - return *this; - } - - segmented_vector_iterator operator--(int) noexcept - { - auto temp = *this; - decrement_once(); - return temp; - } - - segmented_vector_iterator& operator+=(difference_type n) noexcept - { - advance(n); - return *this; - } - - segmented_vector_iterator& operator-=(difference_type n) noexcept - { - advance(-n); - return *this; - } - - SFL_NODISCARD - segmented_vector_iterator operator+(difference_type n) const noexcept - { - auto temp = *this; - temp.advance(n); - return temp; - } - - SFL_NODISCARD - segmented_vector_iterator operator-(difference_type n) const noexcept - { - auto temp = *this; - temp.advance(-n); - return temp; - } - - SFL_NODISCARD - reference operator[](difference_type n) const noexcept - { - auto temp = *this; - temp.advance(n); - return *temp; - } - - SFL_NODISCARD - friend segmented_vector_iterator operator+ - ( - difference_type n, - const segmented_vector_iterator& it - ) noexcept - { - return it + n; - } - - SFL_NODISCARD - friend difference_type operator- - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return (x.seg_ - y.seg_) * difference_type(N) - + (x.elem_ - *x.seg_) - (y.elem_ - *y.seg_); - } - - SFL_NODISCARD - friend bool operator== - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return x.elem_ == y.elem_; - } - - SFL_NODISCARD - friend bool operator!= - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return !(x == y); - } - - SFL_NODISCARD - friend bool operator< - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return (x.seg_ == y.seg_) ? (x.elem_ < y.elem_) : (x.seg_ < y.seg_); - } - - SFL_NODISCARD - friend bool operator> - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return y < x; - } - - SFL_NODISCARD - friend bool operator<= - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return !(y < x); - } - - SFL_NODISCARD - friend bool operator>= - ( - const segmented_vector_iterator& x, - const segmented_vector_iterator& y - ) noexcept - { - return !(x < y); - } - -private: - - segmented_vector_iterator(segment_pointer seg, element_pointer elem) noexcept - : seg_(seg) - , elem_(elem) - {} - - void increment_once() noexcept - { - ++elem_; - - if (elem_ == *seg_ + N) - { - ++seg_; - elem_ = *seg_; - } - } - - void decrement_once() noexcept - { - if (elem_ == *seg_) - { - --seg_; - elem_ = *seg_ + N; - } - - --elem_; - } - - void advance(difference_type n) noexcept - { - const difference_type offset = n + (elem_ - *seg_); - - if (offset >= 0 && offset < difference_type(N)) - { - elem_ += n; - } - else - { - const difference_type seg_offset = - offset > 0 ? offset / difference_type(N) - : -difference_type((-offset - 1) / N) - 1; - - seg_ += seg_offset; - - elem_ = *seg_ + (offset - seg_offset * difference_type(N)); - } - } - - template - friend struct sfl::dtl::segmented_iterator_traits; -}; - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -namespace dtl -{ - -template < typename ValueType, - typename Pointer, - typename Reference, - typename DifferenceType, - typename SegmentPointer, - typename ElementPointer, - std::size_t N > -struct segmented_iterator_traits< segmented_vector_iterator< - ValueType, Pointer, Reference, DifferenceType, SegmentPointer, ElementPointer, N > > -{ - using is_segmented_iterator = std::true_type; - - using iterator = segmented_vector_iterator< ValueType, Pointer, - Reference, DifferenceType, SegmentPointer, ElementPointer, N >; - - using segment_iterator = SegmentPointer; - using local_iterator = ElementPointer; - - static segment_iterator segment(iterator it) noexcept - { - return it.seg_; - } - - static local_iterator local(iterator it) noexcept - { - return it.elem_; - } - - static local_iterator begin(segment_iterator it) noexcept - { - return *it; - } - - static local_iterator end(segment_iterator it) noexcept - { - return *it + N; - } - - static iterator compose(segment_iterator seg, local_iterator elem) noexcept - { - SFL_ASSERT(*seg <= elem && elem <= *seg + N); - - if (elem == *seg + N) - { - ++seg; - elem = *seg; - } - - return iterator(seg, elem); - } -}; - -} // namespace dtl - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -template < typename T, - std::size_t N, - typename Allocator = std::allocator > -class segmented_vector -{ - static_assert(N > 0, "N must be greater than zero."); - -public: - - using allocator_type = Allocator; - using allocator_traits = std::allocator_traits; - using value_type = T; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; - using reference = T&; - using const_reference = const T&; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using iterator = sfl::dtl::segmented_iterator; + using const_iterator = sfl::dtl::segmented_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; static_assert ( @@ -410,44 +76,6 @@ class segmented_vector static constexpr size_type segment_capacity = N; -private: - - using segment_allocator = - typename std::allocator_traits::template rebind_alloc; - - using segment_pointer = - typename std::allocator_traits::pointer; - -public: - - using iterator = - sfl::segmented_vector_iterator< - value_type, - pointer, - reference, - difference_type, - segment_pointer, - pointer, - N - >; - - using const_iterator = - sfl::segmented_vector_iterator< - value_type, - const_pointer, - const_reference, - difference_type, - segment_pointer, - pointer, - N - >; - - using reverse_iterator = - std::reverse_iterator; - - using const_reverse_iterator = - std::reverse_iterator; - private: class data_base @@ -920,7 +548,7 @@ class segmented_vector { SFL_ASSERT(cbegin() <= pos && pos <= cend()); - iterator p1(pos.seg_, pos.elem_); + iterator p1 = begin() + std::distance(cbegin(), pos); if (data_.last_ == data_.eos_) { @@ -1052,7 +680,7 @@ class segmented_vector { SFL_ASSERT(cbegin() <= pos && pos < cend()); - const iterator p(pos.seg_, pos.elem_); + const iterator p = begin() + std::distance(cbegin(), pos); data_.last_ = sfl::dtl::move(p + 1, data_.last_, p); @@ -1067,11 +695,11 @@ class segmented_vector if (first == last) { - return iterator(first.seg_, first.elem_); + return begin() + std::distance(cbegin(), first); } - const iterator p1(first.seg_, first.elem_); - const iterator p2(last.seg_, last.elem_); + const iterator p1 = begin() + std::distance(cbegin(), first); + const iterator p2 = begin() + std::distance(cbegin(), last); const iterator new_last = sfl::dtl::move(p2, data_.last_, p1); @@ -1287,13 +915,13 @@ class segmented_vector { allocate_segments(data_.table_first_, data_.table_last_); - data_.first_.seg_ = data_.table_first_; - data_.first_.elem_ = *data_.table_first_; + data_.first_.segment_ = data_.table_first_; + data_.first_.local_ = *data_.table_first_; data_.last_ = data_.first_; - data_.eos_.seg_ = (data_.table_last_ - 1); - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = (data_.table_last_ - 1); + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); } SFL_CATCH (...) { @@ -1354,11 +982,11 @@ class segmented_vector // Distance (in segments) from FIRST element to LAST element. const size_type dist1 = - std::distance(data_.first_.seg_, data_.last_.seg_); + std::distance(data_.first_.segment_, data_.last_.segment_); // Distance (in segments) from FIRST element to END OF STORAGE. const size_type dist2 = - std::distance(data_.first_.seg_, data_.eos_.seg_); + std::distance(data_.first_.segment_, data_.eos_.segment_); // Allocate new table. No effects if allocation fails. const segment_pointer new_table_first = @@ -1384,9 +1012,9 @@ class segmented_vector data_.table_eos_ = new_table_eos; // Update iterators (noexcept). - data_.first_.seg_ = new_table_first; - data_.last_.seg_ = new_table_first + dist1; - data_.eos_.seg_ = new_table_first + dist2; + data_.first_.segment_ = new_table_first; + data_.last_.segment_ = new_table_first + dist1; + data_.eos_.segment_ = new_table_first + dist2; } const segment_pointer new_table_last = @@ -1399,8 +1027,8 @@ class segmented_vector data_.table_last_ = new_table_last; // Update iterators (noexcept). - data_.eos_.seg_ = data_.table_last_ - 1; - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = data_.table_last_ - 1; + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); } // Removes unused capacity. @@ -1411,14 +1039,14 @@ class segmented_vector { // Destroy empty segments. { - const segment_pointer new_table_last = data_.last_.seg_ + 1; + const segment_pointer new_table_last = data_.last_.segment_ + 1; deallocate_segments(new_table_last, data_.table_last_); data_.table_last_ = new_table_last; - data_.eos_.seg_ = (data_.table_last_ - 1); - data_.eos_.elem_ = *(data_.table_last_ - 1) + (N - 1); + data_.eos_.segment_ = (data_.table_last_ - 1); + data_.eos_.local_ = *(data_.table_last_ - 1) + (N - 1); } // Shrink table. @@ -1434,7 +1062,7 @@ class segmented_vector // Distance (in segments) from FIRST element to LAST element. const size_type dist = - std::distance(data_.first_.seg_, data_.last_.seg_); + std::distance(data_.first_.segment_, data_.last_.segment_); // Allocate new table. No effects if allocation fails. const segment_pointer new_table_first = @@ -1460,9 +1088,9 @@ class segmented_vector data_.table_eos_ = new_table_eos; // Update iterators (noexcept). - data_.first_.seg_ = data_.table_first_; - data_.last_.seg_ = data_.table_first_ + dist; - data_.eos_.seg_ = data_.table_last_ - 1; + data_.first_.segment_ = data_.table_first_; + data_.last_.segment_ = data_.table_first_ + dist; + data_.eos_.segment_ = data_.table_last_ - 1; } } @@ -1895,7 +1523,7 @@ class segmented_vector { if (n == 0) { - return iterator(pos.seg_, pos.elem_); + return begin() + std::distance(cbegin(), pos); } const value_type tmp(value); @@ -1995,7 +1623,7 @@ class segmented_vector { if (first == last) { - return iterator(pos.seg_, pos.elem_); + return begin() + std::distance(cbegin(), pos); } const size_type n = std::distance(first, last);