49 #include <type_traits>
57 template <
typename Allocator>
58 void MoveAllocator(Allocator& lhs,
67 template <
typename Allocator>
68 void MoveAllocator(Allocator& ,
70 std::false_type ) noexcept {}
73 template <
typename Allocator>
74 void MoveAllocator(Allocator& lhs, Allocator& rhs) {
75 using AllocTraits = std::allocator_traits<Allocator>;
77 typename AllocTraits::propagate_on_container_move_assignment;
78 MoveAllocator(lhs, rhs, Propagate{});
82 template <
typename Allocator>
83 void SwapAllocator(Allocator& lhs,
90 template <
typename Allocator>
91 void SwapAllocator(Allocator& ,
96 template <
typename Allocator>
97 void SwapAllocator(Allocator& lhs, Allocator& rhs) {
98 using AllocTraits = std::allocator_traits<Allocator>;
99 using Propagate =
typename AllocTraits::propagate_on_container_swap;
100 SwapAllocator(lhs, rhs, Propagate{});
104 template <
typename Allocator>
105 void CopyAllocator(Allocator& lhs,
106 const Allocator& rhs,
112 template <
typename Allocator>
113 void CopyAllocator(Allocator& ,
118 template <
typename Allocator>
119 void CopyAllocator(Allocator& lhs,
const Allocator& rhs) {
120 using AllocTraits = std::allocator_traits<Allocator>;
122 typename AllocTraits::propagate_on_container_copy_assignment;
123 CopyAllocator(lhs, rhs, Propagate{});
136 template <std::
size_t Capacity>
137 constexpr std::size_t RingWrap(
const std::size_t ring_index) {
140 return (ring_index <= Capacity) ? ring_index : ring_index - Capacity - 1;
153 template <
typename Ptr,
typename AllocTraits, std::
size_t Capacity>
156 using difference_type =
typename AllocTraits::difference_type;
157 using size_type =
typename AllocTraits::difference_type;
158 using value_type =
typename AllocTraits::value_type;
160 using reference = decltype(*pointer{});
161 using iterator_category = std::random_access_iterator_tag;
163 constexpr
Iterator() noexcept =
default;
173 const size_type ring_offset,
174 const size_type ring_index)
175 : data_(data), ring_offset_(ring_offset), ring_index_(ring_index) {}
182 operator Iterator<
typename AllocTraits::const_pointer,
186 data_, ring_offset_, ring_index_);
189 reference operator*()
const {
190 return data_[RingWrap<Capacity>(ring_offset_ + ring_index_)];
193 pointer operator->() const noexcept {
return &**
this; }
195 Iterator operator++(
int) noexcept {
196 Iterator copy(*
this);
201 Iterator& operator++() noexcept {
206 Iterator operator--(
int) noexcept {
207 Iterator copy(*
this);
212 Iterator& operator--() noexcept {
217 Iterator& operator+=(difference_type n) noexcept {
222 Iterator operator+(difference_type n)
const noexcept {
223 return Iterator(data_, ring_offset_, ring_index_ + n);
226 Iterator& operator-=(difference_type n) noexcept {
231 Iterator operator-(difference_type n)
const noexcept {
232 return Iterator(data_, ring_offset_, ring_index_ - n);
235 reference operator[](difference_type n)
const {
return *(*
this + n); }
237 friend difference_type operator-(
const Iterator& lhs,
238 const Iterator& rhs) noexcept {
239 return lhs.ring_index_ > rhs.ring_index_
240 ? lhs.ring_index_ - rhs.ring_index_
241 : -(rhs.ring_index_ - lhs.ring_index_);
244 friend Iterator operator+(difference_type lhs,
const Iterator& rhs) noexcept {
248 friend bool operator<(
const Iterator& lhs,
const Iterator& rhs) noexcept {
251 return std::tie(lhs.data_, lhs.ring_offset_, lhs.ring_index_) <
252 std::tie(rhs.data_, rhs.ring_offset_, rhs.ring_index_);
255 friend bool operator>(
const Iterator& lhs,
const Iterator& rhs) noexcept {
259 friend bool operator<=(
const Iterator& lhs,
const Iterator& rhs) noexcept {
263 friend bool operator>=(
const Iterator& lhs,
const Iterator& rhs) noexcept {
267 friend bool operator==(
const Iterator& lhs,
const Iterator& rhs) noexcept {
268 return &*lhs == &*rhs;
271 friend bool operator!=(
const Iterator& lhs,
const Iterator& rhs) noexcept {
272 return !(lhs == rhs);
275 template <
typename P,
typename A, std::
size_t C,
typename OutputIt>
278 friend OutputIt copy(
const Iterator<P, A, C>& begin,
279 const Iterator<P, A, C>& end,
290 size_type ring_offset_{};
292 size_type ring_index_{};
299 template <
typename Ptr,
300 typename AllocTraits,
301 std::size_t Capacity,
303 OutputIt
copy(
const Iterator<Ptr, AllocTraits, Capacity>& begin,
304 const Iterator<Ptr, AllocTraits, Capacity>& end,
306 assert(begin <= end);
310 }
else if (&*end > &*begin) {
315 out =
std::copy(&*begin, &begin.data_[Capacity + 1], out);
334 template <
typename Elem,
335 std::size_t Capacity,
336 typename Allocator = std::allocator<Elem>>
339 using allocator_type = Allocator;
340 using alloc_traits = std::allocator_traits<allocator_type>;
341 using value_type = Elem;
342 using pointer =
typename alloc_traits::pointer;
343 using const_pointer =
typename alloc_traits::const_pointer;
344 using reference = decltype(*pointer{});
345 using const_reference = decltype(*const_pointer{});
349 using reverse_iterator = std::reverse_iterator<iterator>;
350 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
351 using difference_type =
typename alloc_traits::difference_type;
352 using size_type =
typename alloc_traits::size_type;
353 using unsigned_difference =
354 typename std::make_unsigned<difference_type>::type;
361 allocator_type alloc_{};
364 pointer data_{
nullptr};
369 size_type ring_offset_{0U};
374 constexpr
static size_type Decrement(
const size_type index) {
375 return index > 0 ? index - 1 : Capacity;
378 constexpr
static size_type Increment(
const size_type index) {
379 return index < (Capacity) ? index + 1 : 0;
384 void Swap(
RingBuf& other) noexcept {
385 std::swap(data_, other.data_);
386 std::swap(next_, other.next_);
387 std::swap(ring_offset_, other.ring_offset_);
388 std::swap(size_, other.size_);
392 void ShrinkFront() noexcept {
393 ring_offset_ = Increment(ring_offset_);
399 void ShrinkBack() noexcept {
400 next_ = Decrement(next_);
406 void GrowFront() noexcept {
408 ring_offset_ = Decrement(ring_offset_);
415 void GrowBack() noexcept {
416 next_ = Increment(next_);
426 reference UncheckedAt(size_type index) {
return (*
this)[index]; }
446 explicit RingBuf(
const allocator_type& allocator)
448 data_(alloc_traits::allocate(alloc_, Capacity + 1)) {}
457 alloc_traits::deallocate(alloc_, data_, Capacity + 1);
469 alloc_traits::select_on_container_copy_construction(other.alloc_)) {
483 for (
const auto& value : other) {
506 if (other.alloc_ == allocator) {
509 for (
auto& element : other) {
526 detail::ringbuf::CopyAllocator(alloc_, other.alloc_);
528 for (
const auto& value : other) {
543 alloc_traits::propagate_on_container_move_assignment::value ||
544 std::is_nothrow_move_constructible<value_type>::value) {
545 if (alloc_traits::propagate_on_container_move_assignment::value ||
546 alloc_ == other.alloc_) {
549 detail::ringbuf::MoveAllocator(alloc_, other.alloc_);
554 for (
auto& element : other) {
576 const_reference
front()
const {
return at(0); }
597 return data_[detail::ringbuf::RingWrap<Capacity>(ring_offset_ + index)];
608 return data_[detail::ringbuf::RingWrap<Capacity>(ring_offset_ + index)];
618 const_reference
at(
const size_type index)
const {
619 if (index >=
size()) {
620 throw std::out_of_range(
"RingBuf::at: index >= Size");
622 return (*
this)[index];
632 reference
at(
const size_type index) {
633 if (index >=
size()) {
634 throw std::out_of_range(
"RingBuf::at: index >= Size");
636 return (*
this)[index];
663 return const_cast<self const&
>(*this).
begin();
669 return const_cast<self const&
>(*this).
end();
674 reverse_iterator
rbegin() noexcept {
return reverse_iterator(
end()); }
678 reverse_iterator
rend() noexcept {
return reverse_iterator(
begin()); }
682 const_reverse_iterator
rbegin() const noexcept {
683 return const_reverse_iterator(
end());
688 const_reverse_iterator
rend() const noexcept {
689 return const_reverse_iterator(
begin());
694 const_reverse_iterator
crbegin() const noexcept {
695 return const_cast<self const&
>(*this).
rbegin();
700 const_reverse_iterator
crend() const noexcept {
701 return const_cast<self const&
>(*this).
rend();
711 size_type
size() const noexcept {
return size_; }
715 constexpr size_type
max_size() const noexcept {
return Capacity; }
738 template <
typename... Args>
742 return UncheckedAt(0);
745 alloc_traits::construct(alloc_, &data_[Decrement(ring_offset_)],
746 std::forward<Args>(args)...);
753 return UncheckedAt(0);
775 template <
typename... Args>
779 return UncheckedAt(0);
782 alloc_traits::construct(alloc_, &data_[next_], std::forward<Args>(args)...);
789 return UncheckedAt(
size() - 1);
801 alloc_traits::destroy(alloc_, &data_[ring_offset_]);
814 alloc_traits::destroy(alloc_, &data_[next_]);
837 noexcept(
pop_front()) && std::is_nothrow_move_assignable<Elem>::value) {
839 return UnConstIterator(to);
842 const iterator first = UnConstIterator(from);
843 const iterator last = UnConstIterator(to);
845 const auto leading = first -
begin();
846 const auto trailing =
end() - last;
847 if (leading > trailing) {
849 for (
auto i = 0; i < trailing; i++) {
850 first[i] = std::move(last[i]);
852 const auto to_pop = last - first;
853 for (
auto i = 0; i < to_pop; i++) {
858 for (
auto i = -1; i >= -leading; i--) {
859 last[i] = std::move(first[i]);
861 const auto to_pop = last - first;
862 for (
auto i = 0; i < to_pop; i++) {
867 return end() - trailing;
877 return erase(pos, pos + 1);
886 detail::ringbuf::SwapAllocator(alloc_, other.alloc_);
896 return std::lexicographical_compare(lhs.
begin(), lhs.
end(), rhs.
begin(),
941 return !(lhs == rhs);
963 template <
typename Ptr,
964 typename AllocTraits,
965 std::size_t Capacity,