24#include <seastar/core/transfer.hh>
25#include <seastar/core/bitops.hh>
26#include <seastar/util/modules.hh>
62template <
typename T,
typename Alloc = std::allocator<T>>
71 impl(Alloc a) noexcept : Alloc(std::move(a)) { }
79 static_assert(!std::is_default_constructible_v<Alloc>
80 || std::is_nothrow_default_constructible_v<Alloc>);
81 static_assert(std::is_nothrow_move_constructible_v<Alloc>);
85 using size_type = size_t;
88 using const_reference =
const T&;
89 using const_pointer =
const T*;
98 void push_front(
const T& data);
99 void push_front(T&& data);
100 template <
typename... A>
101 void emplace_front(A&&... args);
102 void push_back(
const T& data);
103 void push_back(T&& data);
104 template <
typename... A>
105 void emplace_back(A&&... args);
107 const T& front()
const noexcept;
109 const T& back()
const noexcept;
110 void pop_front()
noexcept;
111 void pop_back()
noexcept;
112 bool empty()
const noexcept;
113 size_t size()
const noexcept;
114 size_t capacity()
const noexcept;
115 void reserve(
size_t);
116 void clear()
noexcept;
117 T& operator[](
size_t idx)
noexcept;
118 const T& operator[](
size_t idx)
const noexcept;
119 template <
typename Func>
120 void for_each(Func func);
123 T& access_element_unsafe(
size_t idx)
noexcept;
127 void maybe_expand(
size_t nr = 1);
128 size_t mask(
size_t idx)
const;
130 template<
typename CB,
typename ValueType>
132 using iterator_category = std::random_access_iterator_tag;
133 using value_type = ValueType;
134 using difference_type = std::ptrdiff_t;
135 using pointer = ValueType*;
136 using reference = ValueType&;
138 ValueType& operator*()
const noexcept {
return cb->_impl.storage[cb->mask(idx)]; }
139 ValueType* operator->()
const noexcept {
return &cb->_impl.storage[cb->mask(idx)]; }
141 cbiterator<CB, ValueType>& operator++()
noexcept {
146 cbiterator<CB, ValueType> operator++(
int)
noexcept {
152 cbiterator<CB, ValueType>& operator--()
noexcept {
157 cbiterator<CB, ValueType> operator--(
int)
noexcept {
162 cbiterator<CB, ValueType> operator+(difference_type n)
const noexcept {
163 return cbiterator<CB, ValueType>(cb, idx + n);
165 cbiterator<CB, ValueType> operator-(difference_type n)
const noexcept {
166 return cbiterator<CB, ValueType>(cb, idx - n);
168 cbiterator<CB, ValueType>& operator+=(difference_type n)
noexcept {
172 cbiterator<CB, ValueType>& operator-=(difference_type n)
noexcept {
176 bool operator==(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
177 return idx == rhs.idx;
179 bool operator!=(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
180 return idx != rhs.idx;
182 bool operator<(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
183 return *
this - rhs < 0;
185 bool operator>(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
186 return *
this - rhs > 0;
188 bool operator>=(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
189 return *
this - rhs >= 0;
191 bool operator<=(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
192 return *
this - rhs <= 0;
194 difference_type operator-(
const cbiterator<CB, ValueType>& rhs)
const noexcept {
195 return idx - rhs.idx;
197 cbiterator() =
default;
201 cbiterator(CB* b,
size_t i) noexcept : cb(b), idx(i) {}
204 friend class iterator;
207 typedef cbiterator<circular_buffer, T> iterator;
208 typedef cbiterator<const circular_buffer, const T> const_iterator;
210 iterator begin()
noexcept {
211 return iterator(
this, _impl.begin);
213 const_iterator begin()
const noexcept {
214 return const_iterator(
this, _impl.begin);
216 iterator end()
noexcept {
217 return iterator(
this, _impl.end);
219 const_iterator end()
const noexcept {
220 return const_iterator(
this, _impl.end);
222 const_iterator cbegin()
const noexcept {
223 return const_iterator(
this, _impl.begin);
225 const_iterator cend()
const noexcept {
226 return const_iterator(
this, _impl.end);
228 iterator erase(iterator first, iterator last)
noexcept;
231template <
typename T,
typename Alloc>
235 return idx & (_impl.capacity - 1);
238template <
typename T,
typename Alloc>
241circular_buffer<T, Alloc>::empty() const noexcept {
242 return _impl.begin == _impl.end;
245template <
typename T,
typename Alloc>
248circular_buffer<T, Alloc>::size() const noexcept {
249 return _impl.end - _impl.begin;
252template <
typename T,
typename Alloc>
255circular_buffer<T, Alloc>::capacity() const noexcept {
256 return _impl.capacity;
259template <
typename T,
typename Alloc>
262circular_buffer<T, Alloc>::reserve(
size_t size) {
263 if (capacity() < size) {
265 expand(
size_t(1) << log2ceil(size));
269template <
typename T,
typename Alloc>
272circular_buffer<T, Alloc>::clear() noexcept {
273 erase(begin(), end());
276template <
typename T,
typename Alloc>
278circular_buffer<T, Alloc>::circular_buffer(Alloc alloc) noexcept
279 : _impl(std::move(alloc)) {
282template <
typename T,
typename Alloc>
284circular_buffer<T, Alloc>::circular_buffer(circular_buffer&& x) noexcept
285 : _impl(std::move(x._impl)) {
289template <
typename T,
typename Alloc>
291circular_buffer<T, Alloc>& circular_buffer<T, Alloc>::operator=(circular_buffer&& x)
noexcept {
293 this->~circular_buffer();
294 new (
this) circular_buffer(std::move(x));
299template <
typename T,
typename Alloc>
300template <
typename Func>
303circular_buffer<T, Alloc>::for_each(Func func) {
304 auto s = _impl.storage;
305 auto m = _impl.capacity - 1;
306 for (
auto i = _impl.begin; i != _impl.end; ++i) {
311template <
typename T,
typename Alloc>
313circular_buffer<T, Alloc>::~circular_buffer() {
314 for_each([
this] (T& obj) {
315 std::allocator_traits<Alloc>::destroy(_impl, &obj);
317 _impl.deallocate(_impl.storage, _impl.capacity);
320template <
typename T,
typename Alloc>
322circular_buffer<T, Alloc>::expand() {
323 expand(std::max<size_t>(_impl.capacity * 2, 1));
326template <
typename T,
typename Alloc>
328circular_buffer<T, Alloc>::expand(
size_t new_cap) {
329 auto new_storage = _impl.allocate(new_cap);
330 auto p = new_storage;
332 for_each([
this, &p] (T& obj) {
333 transfer_pass1(_impl, &obj, p);
337 while (p != new_storage) {
338 std::allocator_traits<Alloc>::destroy(_impl, --p);
340 _impl.deallocate(new_storage, new_cap);
344 for_each([
this, &p] (T& obj) {
345 transfer_pass2(_impl, &obj, p++);
347 std::swap(_impl.storage, new_storage);
348 std::swap(_impl.capacity, new_cap);
350 _impl.end = p - _impl.storage;
351 _impl.deallocate(new_storage, new_cap);
354template <
typename T,
typename Alloc>
357circular_buffer<T, Alloc>::maybe_expand(
size_t nr) {
358 if (_impl.end - _impl.begin + nr > _impl.capacity) {
363template <
typename T,
typename Alloc>
366circular_buffer<T, Alloc>::push_front(
const T& data) {
368 auto p = &_impl.storage[mask(_impl.begin - 1)];
369 std::allocator_traits<Alloc>::construct(_impl, p, data);
373template <
typename T,
typename Alloc>
376circular_buffer<T, Alloc>::push_front(T&& data) {
378 auto p = &_impl.storage[mask(_impl.begin - 1)];
379 std::allocator_traits<Alloc>::construct(_impl, p, std::move(data));
383template <
typename T,
typename Alloc>
384template <
typename... Args>
387circular_buffer<T, Alloc>::emplace_front(Args&&... args) {
389 auto p = &_impl.storage[mask(_impl.begin - 1)];
390 std::allocator_traits<Alloc>::construct(_impl, p, std::forward<Args>(args)...);
394template <
typename T,
typename Alloc>
397circular_buffer<T, Alloc>::push_back(
const T& data) {
399 auto p = &_impl.storage[mask(_impl.end)];
400 std::allocator_traits<Alloc>::construct(_impl, p, data);
404template <
typename T,
typename Alloc>
407circular_buffer<T, Alloc>::push_back(T&& data) {
409 auto p = &_impl.storage[mask(_impl.end)];
410 std::allocator_traits<Alloc>::construct(_impl, p, std::move(data));
414template <
typename T,
typename Alloc>
415template <
typename... Args>
418circular_buffer<T, Alloc>::emplace_back(Args&&... args) {
420 auto p = &_impl.storage[mask(_impl.end)];
421 std::allocator_traits<Alloc>::construct(_impl, p, std::forward<Args>(args)...);
425template <
typename T,
typename Alloc>
428circular_buffer<T, Alloc>::front() noexcept {
429 return _impl.storage[mask(_impl.begin)];
432template <
typename T,
typename Alloc>
435circular_buffer<T, Alloc>::front() const noexcept {
436 return _impl.storage[mask(_impl.begin)];
439template <
typename T,
typename Alloc>
442circular_buffer<T, Alloc>::back() noexcept {
443 return _impl.storage[mask(_impl.end - 1)];
446template <
typename T,
typename Alloc>
449circular_buffer<T, Alloc>::back() const noexcept {
450 return _impl.storage[mask(_impl.end - 1)];
453template <
typename T,
typename Alloc>
456circular_buffer<T, Alloc>::pop_front() noexcept {
457 std::allocator_traits<Alloc>::destroy(_impl, &front());
461template <
typename T,
typename Alloc>
464circular_buffer<T, Alloc>::pop_back() noexcept {
465 std::allocator_traits<Alloc>::destroy(_impl, &back());
469template <
typename T,
typename Alloc>
472circular_buffer<T, Alloc>::operator[](
size_t idx)
noexcept {
473 return _impl.storage[mask(_impl.begin + idx)];
476template <
typename T,
typename Alloc>
479circular_buffer<T, Alloc>::operator[](
size_t idx)
const noexcept {
480 return _impl.storage[mask(_impl.begin + idx)];
483template <
typename T,
typename Alloc>
486circular_buffer<T, Alloc>::access_element_unsafe(
size_t idx)
noexcept {
487 return _impl.storage[mask(_impl.begin + idx)];
490template <
typename T,
typename Alloc>
492typename circular_buffer<T, Alloc>::iterator
493circular_buffer<T, Alloc>::erase(iterator first, iterator last)
noexcept {
494 static_assert(std::is_nothrow_move_assignable_v<T>,
"erase() assumes move assignment does not throw");
500 if (std::distance(begin(), first) < std::distance(last, end())) {
501 auto new_start = std::move_backward(begin(), first, last);
502 for (
auto i = begin(); i < new_start; ++i) {
503 std::allocator_traits<Alloc>::destroy(_impl, &*i);
505 _impl.begin = new_start.idx;
508 auto new_end = std::move(last, end(), first);
509 for (
auto i = new_end, e = end(); i < e; ++i) {
510 std::allocator_traits<Alloc>::destroy(_impl, &*i);
512 _impl.end = new_end.idx;
Definition: circular_buffer.hh:63
holds the implementation parts of the metrics layer, do not use directly.
Seastar API namespace.
Definition: abort_on_ebadf.hh:26