24 #include <seastar/core/transfer.hh>
25 #include <seastar/core/bitops.hh>
26 #include <seastar/util/concepts.hh>
27 #include <seastar/util/modules.hh>
28 #ifndef SEASTAR_MODULE
62 template <
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;
200 cbiterator(CB* b,
size_t i) noexcept : cb(b), idx(i) {}
203 friend class iterator;
206 typedef cbiterator<circular_buffer, T> iterator;
207 typedef cbiterator<const circular_buffer, const T> const_iterator;
209 iterator begin() noexcept {
210 return iterator(
this, _impl.begin);
212 const_iterator begin()
const noexcept {
213 return const_iterator(
this, _impl.begin);
215 iterator end() noexcept {
216 return iterator(
this, _impl.end);
218 const_iterator end()
const noexcept {
219 return const_iterator(
this, _impl.end);
221 const_iterator cbegin()
const noexcept {
222 return const_iterator(
this, _impl.begin);
224 const_iterator cend()
const noexcept {
225 return const_iterator(
this, _impl.end);
227 iterator erase(iterator first, iterator last) noexcept;
230 template <
typename T,
typename Alloc>
234 return idx & (_impl.capacity - 1);
237 template <
typename T,
typename Alloc>
240 circular_buffer<T, Alloc>::empty() const noexcept {
241 return _impl.begin == _impl.end;
244 template <
typename T,
typename Alloc>
247 circular_buffer<T, Alloc>::size() const noexcept {
248 return _impl.end - _impl.begin;
251 template <
typename T,
typename Alloc>
254 circular_buffer<T, Alloc>::capacity() const noexcept {
255 return _impl.capacity;
258 template <
typename T,
typename Alloc>
261 circular_buffer<T, Alloc>::reserve(
size_t size) {
262 if (capacity() < size) {
264 expand(
size_t(1) << log2ceil(size));
268 template <
typename T,
typename Alloc>
271 circular_buffer<T, Alloc>::clear() noexcept {
272 erase(begin(), end());
275 template <
typename T,
typename Alloc>
277 circular_buffer<T, Alloc>::circular_buffer(Alloc alloc) noexcept
278 : _impl(std::move(alloc)) {
281 template <
typename T,
typename Alloc>
283 circular_buffer<T, Alloc>::circular_buffer(circular_buffer&& x) noexcept
284 : _impl(std::move(x._impl)) {
288 template <
typename T,
typename Alloc>
290 circular_buffer<T, Alloc>& circular_buffer<T, Alloc>::operator=(circular_buffer&& x) noexcept {
292 this->~circular_buffer();
293 new (
this) circular_buffer(std::move(x));
298 template <
typename T,
typename Alloc>
299 template <
typename Func>
302 circular_buffer<T, Alloc>::for_each(Func func) {
303 auto s = _impl.storage;
304 auto m = _impl.capacity - 1;
305 for (
auto i = _impl.begin; i != _impl.end; ++i) {
310 template <
typename T,
typename Alloc>
312 circular_buffer<T, Alloc>::~circular_buffer() {
313 for_each([
this] (T& obj) {
314 std::allocator_traits<Alloc>::destroy(_impl, &obj);
316 _impl.deallocate(_impl.storage, _impl.capacity);
319 template <
typename T,
typename Alloc>
321 circular_buffer<T, Alloc>::expand() {
322 expand(std::max<size_t>(_impl.capacity * 2, 1));
325 template <
typename T,
typename Alloc>
327 circular_buffer<T, Alloc>::expand(
size_t new_cap) {
328 auto new_storage = _impl.allocate(new_cap);
329 auto p = new_storage;
331 for_each([
this, &p] (T& obj) {
332 transfer_pass1(_impl, &obj, p);
336 while (p != new_storage) {
337 std::allocator_traits<Alloc>::destroy(_impl, --p);
339 _impl.deallocate(new_storage, new_cap);
343 for_each([
this, &p] (T& obj) {
344 transfer_pass2(_impl, &obj, p++);
346 std::swap(_impl.storage, new_storage);
347 std::swap(_impl.capacity, new_cap);
349 _impl.end = p - _impl.storage;
350 _impl.deallocate(new_storage, new_cap);
353 template <
typename T,
typename Alloc>
356 circular_buffer<T, Alloc>::maybe_expand(
size_t nr) {
357 if (_impl.end - _impl.begin + nr > _impl.capacity) {
362 template <
typename T,
typename Alloc>
365 circular_buffer<T, Alloc>::push_front(
const T& data) {
367 auto p = &_impl.storage[mask(_impl.begin - 1)];
368 std::allocator_traits<Alloc>::construct(_impl, p, data);
372 template <
typename T,
typename Alloc>
375 circular_buffer<T, Alloc>::push_front(T&& data) {
377 auto p = &_impl.storage[mask(_impl.begin - 1)];
378 std::allocator_traits<Alloc>::construct(_impl, p, std::move(data));
382 template <
typename T,
typename Alloc>
383 template <
typename... Args>
386 circular_buffer<T, Alloc>::emplace_front(Args&&... args) {
388 auto p = &_impl.storage[mask(_impl.begin - 1)];
389 std::allocator_traits<Alloc>::construct(_impl, p, std::forward<Args>(args)...);
393 template <
typename T,
typename Alloc>
396 circular_buffer<T, Alloc>::push_back(
const T& data) {
398 auto p = &_impl.storage[mask(_impl.end)];
399 std::allocator_traits<Alloc>::construct(_impl, p, data);
403 template <
typename T,
typename Alloc>
406 circular_buffer<T, Alloc>::push_back(T&& data) {
408 auto p = &_impl.storage[mask(_impl.end)];
409 std::allocator_traits<Alloc>::construct(_impl, p, std::move(data));
413 template <
typename T,
typename Alloc>
414 template <
typename... Args>
417 circular_buffer<T, Alloc>::emplace_back(Args&&... args) {
419 auto p = &_impl.storage[mask(_impl.end)];
420 std::allocator_traits<Alloc>::construct(_impl, p, std::forward<Args>(args)...);
424 template <
typename T,
typename Alloc>
427 circular_buffer<T, Alloc>::front() noexcept {
428 return _impl.storage[mask(_impl.begin)];
431 template <
typename T,
typename Alloc>
434 circular_buffer<T, Alloc>::front() const noexcept {
435 return _impl.storage[mask(_impl.begin)];
438 template <
typename T,
typename Alloc>
441 circular_buffer<T, Alloc>::back() noexcept {
442 return _impl.storage[mask(_impl.end - 1)];
445 template <
typename T,
typename Alloc>
448 circular_buffer<T, Alloc>::back() const noexcept {
449 return _impl.storage[mask(_impl.end - 1)];
452 template <
typename T,
typename Alloc>
455 circular_buffer<T, Alloc>::pop_front() noexcept {
456 std::allocator_traits<Alloc>::destroy(_impl, &front());
460 template <
typename T,
typename Alloc>
463 circular_buffer<T, Alloc>::pop_back() noexcept {
464 std::allocator_traits<Alloc>::destroy(_impl, &back());
468 template <
typename T,
typename Alloc>
471 circular_buffer<T, Alloc>::operator[](
size_t idx) noexcept {
472 return _impl.storage[mask(_impl.begin + idx)];
475 template <
typename T,
typename Alloc>
478 circular_buffer<T, Alloc>::operator[](
size_t idx)
const noexcept {
479 return _impl.storage[mask(_impl.begin + idx)];
482 template <
typename T,
typename Alloc>
485 circular_buffer<T, Alloc>::access_element_unsafe(
size_t idx) noexcept {
486 return _impl.storage[mask(_impl.begin + idx)];
489 template <
typename T,
typename Alloc>
491 typename circular_buffer<T, Alloc>::iterator
492 circular_buffer<T, Alloc>::erase(iterator first, iterator last) noexcept {
493 static_assert(std::is_nothrow_move_assignable_v<T>,
"erase() assumes move assignment does not throw");
499 if (std::distance(begin(), first) < std::distance(last, end())) {
500 auto new_start = std::move_backward(begin(), first, last);
501 for (
auto i = begin(); i < new_start; ++i) {
502 std::allocator_traits<Alloc>::destroy(_impl, &*i);
504 _impl.begin = new_start.idx;
507 auto new_end = std::move(last, end(), first);
508 for (
auto i = new_end, e = end(); i < e; ++i) {
509 std::allocator_traits<Alloc>::destroy(_impl, &*i);
511 _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