30#include <seastar/util/assert.hh>
31#include <seastar/util/modules.hh>
93template <
typename T,
size_t items_per_chunk = 128>
95 static_assert((items_per_chunk & (items_per_chunk - 1)) == 0,
96 "chunked_fifo chunk size must be power of two");
98 maybe_item()
noexcept {}
103 maybe_item items[items_per_chunk];
110 size_t size()
const {
117 chunk* _front_chunk =
nullptr;
118 chunk* _back_chunk =
nullptr;
131 chunk* _free_chunks =
nullptr;
132 size_t _nfree_chunks = 0;
134 using value_type = T;
135 using size_type = size_t;
136 using reference = T&;
138 using const_reference =
const T&;
139 using const_pointer =
const T*;
142 template <
bool IsConst>
143 class basic_iterator {
147 using iterator_category = std::forward_iterator_tag;
148 using difference_type = std::ptrdiff_t;
149 using value_type = std::conditional_t<IsConst, const T, T>;
150 using pointer = value_type*;
151 using reference = value_type&;
154 using chunk_t = std::conditional_t<IsConst, const chunk, chunk>;
155 chunk_t* _chunk =
nullptr;
156 size_t _item_index = 0;
159 inline explicit basic_iterator(chunk_t* c)
noexcept;
160 inline basic_iterator(chunk_t* c,
size_t item_index)
noexcept;
163 basic_iterator()
noexcept =
default;
164 template<
bool OtherIsConst>
165 requires (IsConst && !OtherIsConst)
166 inline basic_iterator(
const basic_iterator<OtherIsConst>& o) noexcept
167 : basic_iterator{o._chunk, o._item_index} {}
168 inline bool operator==(
const basic_iterator& o)
const noexcept;
169 inline bool operator!=(
const basic_iterator& o)
const noexcept;
170 inline pointer operator->()
const noexcept;
171 inline reference operator*()
const noexcept;
172 inline basic_iterator operator++(
int)
noexcept;
173 basic_iterator& operator++()
noexcept;
177 using iterator = basic_iterator<false>;
178 using const_iterator = basic_iterator<true>;
188 inline void push_back(
const T& data);
189 inline void push_back(T&& data);
191 const T& back()
const noexcept;
192 template <
typename... A>
193 inline void emplace_back(A&&... args);
194 inline T& front()
const noexcept;
195 inline void pop_front()
noexcept;
196 inline bool empty()
const noexcept;
197 inline size_t size()
const noexcept;
201 void pop_front_n(
size_t n)
noexcept;
202 void clear()
noexcept;
209 void reserve(
size_t n);
212 void shrink_to_fit()
noexcept;
213 inline iterator begin()
noexcept;
214 inline iterator end()
noexcept;
215 inline const_iterator begin()
const noexcept;
216 inline const_iterator end()
const noexcept;
217 inline const_iterator cbegin()
const noexcept;
218 inline const_iterator cend()
const noexcept;
220 void back_chunk_new();
221 void front_chunk_delete()
noexcept;
222 inline void ensure_room_back();
223 void undo_room_back()
noexcept;
224 static inline size_t mask(
size_t idx)
noexcept;
228template <
typename T,
size_t items_per_chunk>
229template <
bool IsConst>
234template <
typename T,
size_t items_per_chunk>
235template <
bool IsConst>
237chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::basic_iterator(chunk_t* c,
size_t item_index) noexcept : _chunk(c), _item_index(item_index) {
240template <
typename T,
size_t items_per_chunk>
241template <
bool IsConst>
243chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator==(
const basic_iterator& o)
const noexcept {
244 return _chunk == o._chunk && _item_index == o._item_index;
247template <
typename T,
size_t items_per_chunk>
248template <
bool IsConst>
250chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator!=(
const basic_iterator& o)
const noexcept {
251 return !(*
this == o);
254template <
typename T,
size_t items_per_chunk>
255template <
bool IsConst>
256inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::pointer
257chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator->() const noexcept {
258 return &_chunk->items[chunked_fifo::mask(_item_index)].data;
261template <
typename T,
size_t items_per_chunk>
262template <
bool IsConst>
263inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::reference
264chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator*() const noexcept {
265 return _chunk->items[chunked_fifo::mask(_item_index)].data;
268template <
typename T,
size_t items_per_chunk>
269template <
bool IsConst>
270inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>
271chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++(
int)
noexcept {
277template <
typename T,
size_t items_per_chunk>
278template <
bool IsConst>
279typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>&
280chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++() noexcept {
282 if (_item_index == _chunk->end) {
283 _chunk = _chunk->next;
284 _item_index = _chunk ? _chunk->begin : 0;
289template <
typename T,
size_t items_per_chunk>
291chunked_fifo<T, items_per_chunk>::chunked_fifo(chunked_fifo&& x) noexcept
292 : _front_chunk(x._front_chunk)
293 , _back_chunk(x._back_chunk)
294 , _nchunks(x._nchunks)
295 , _free_chunks(x._free_chunks)
296 , _nfree_chunks(x._nfree_chunks) {
297 x._front_chunk =
nullptr;
298 x._back_chunk =
nullptr;
300 x._free_chunks =
nullptr;
304template <
typename T,
size_t items_per_chunk>
306chunked_fifo<T, items_per_chunk>::chunked_fifo(
const chunked_fifo& rhs)
308 std::copy_n(rhs.begin(), rhs.size(), std::back_inserter(*
this));
311template <
typename T,
size_t items_per_chunk>
313chunked_fifo<T, items_per_chunk>&
314chunked_fifo<T, items_per_chunk>::operator=(
const chunked_fifo& rhs) {
317 std::copy_n(rhs.begin(), rhs.size(), std::back_inserter(*
this));
323template <
typename T,
size_t items_per_chunk>
325chunked_fifo<T, items_per_chunk>&
326chunked_fifo<T, items_per_chunk>::operator=(chunked_fifo&& x)
noexcept {
328 this->~chunked_fifo();
329 new (
this) chunked_fifo(std::move(x));
334template <
typename T,
size_t items_per_chunk>
336chunked_fifo<T, items_per_chunk>::mask(
size_t idx)
noexcept {
337 return idx & (items_per_chunk - 1);
340template <
typename T,
size_t items_per_chunk>
342chunked_fifo<T, items_per_chunk>::empty() const noexcept {
343 return _front_chunk ==
nullptr;
346template <
typename T,
size_t items_per_chunk>
348chunked_fifo<T, items_per_chunk>::size() const noexcept{
349 if (_front_chunk ==
nullptr) {
351 }
else if (_back_chunk == _front_chunk) {
353 return _front_chunk->end - _front_chunk->begin;
355 return _front_chunk->end - _front_chunk->begin
356 +_back_chunk->end - _back_chunk->begin
357 + (_nchunks - 2) * items_per_chunk;
361template <
typename T,
size_t items_per_chunk>
362void chunked_fifo<T, items_per_chunk>::clear() noexcept {
366template <
typename T,
size_t items_per_chunk>
367void chunked_fifo<T, items_per_chunk>::pop_front_n(
size_t n)
noexcept {
369 SEASTAR_ASSERT(_front_chunk &&
"pop_front_n n too large");
371 auto target = _front_chunk;
372 unsigned delete_count = std::min(target->size(), n);
374 for (
auto i = target->begin, e = i + delete_count; i != e; i++) {
375 target->items[mask(i)].data.~T();
378 target->begin += delete_count;
381 if (target->size() == 0) {
382 front_chunk_delete();
389template <
typename T,
size_t items_per_chunk>
void
390chunked_fifo<T, items_per_chunk>::shrink_to_fit() noexcept {
391 while (_free_chunks) {
392 auto next = _free_chunks->next;
399template <
typename T,
size_t items_per_chunk>
400chunked_fifo<T, items_per_chunk>::~chunked_fifo() {
405template <
typename T,
size_t items_per_chunk>
407chunked_fifo<T, items_per_chunk>::back_chunk_new() {
408 chunk *old = _back_chunk;
410 _back_chunk = _free_chunks;
411 _free_chunks = _free_chunks->next;
414 _back_chunk =
new chunk;
416 _back_chunk->next =
nullptr;
417 _back_chunk->begin = 0;
418 _back_chunk->end = 0;
420 old->next = _back_chunk;
422 if (_front_chunk ==
nullptr) {
423 _front_chunk = _back_chunk;
429template <
typename T,
size_t items_per_chunk>
431chunked_fifo<T, items_per_chunk>::ensure_room_back() {
433 if (_back_chunk ==
nullptr ||
434 (_back_chunk->end - _back_chunk->begin) == items_per_chunk) {
439template <
typename T,
size_t items_per_chunk>
441chunked_fifo<T, items_per_chunk>::undo_room_back() noexcept {
446 if (_back_chunk->begin == _back_chunk->end) {
450 _back_chunk =
nullptr;
451 _front_chunk =
nullptr;
456 chunk *old = _back_chunk;
457 _back_chunk = _front_chunk;
458 while (_back_chunk->next != old) {
459 _back_chunk = _back_chunk->next;
461 _back_chunk->next =
nullptr;
467template <
typename T,
size_t items_per_chunk>
468template <
typename... Args>
470chunked_fifo<T, items_per_chunk>::emplace_back(Args&&... args) {
472 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
474 new(p) T(std::forward<Args>(args)...);
482template <
typename T,
size_t items_per_chunk>
483inline bool chunked_fifo<T, items_per_chunk>::operator==(
const chunked_fifo& rhs)
const {
484 return size() == rhs.size() && std::equal(begin(), end(), rhs.begin());
487template <
typename T,
size_t items_per_chunk>
489chunked_fifo<T, items_per_chunk>::push_back(
const T& data) {
491 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
501template <
typename T,
size_t items_per_chunk>
503chunked_fifo<T, items_per_chunk>::push_back(T&& data) {
505 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
507 new(p) T(std::move(data));
515template <
typename T,
size_t items_per_chunk>
518chunked_fifo<T, items_per_chunk>::back() noexcept {
519 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
522template <
typename T,
size_t items_per_chunk>
525chunked_fifo<T, items_per_chunk>::back() const noexcept {
526 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
529template <
typename T,
size_t items_per_chunk>
531chunked_fifo<T, items_per_chunk>::front() const noexcept {
532 return _front_chunk->items[mask(_front_chunk->begin)].data;
535template <
typename T,
size_t items_per_chunk>
537chunked_fifo<T, items_per_chunk>::front_chunk_delete() noexcept {
538 chunk *next = _front_chunk->next;
550 static constexpr int save_free_chunks = 1;
551 if (_nfree_chunks < save_free_chunks) {
552 _front_chunk->next = _free_chunks;
553 _free_chunks = _front_chunk;
559 if (_back_chunk == _front_chunk) {
560 _back_chunk =
nullptr;
566template <
typename T,
size_t items_per_chunk>
568chunked_fifo<T, items_per_chunk>::pop_front() noexcept {
572 if (++_front_chunk->begin == _front_chunk->end) {
573 front_chunk_delete();
577template <
typename T,
size_t items_per_chunk>
578void chunked_fifo<T, items_per_chunk>::reserve(
size_t n) {
584 size_t need = n - size();
588 size_t back_chunk_n = items_per_chunk - (_back_chunk->end - _back_chunk->begin);
589 need -= std::min(back_chunk_n, need);
591 size_t needed_chunks = (need + items_per_chunk - 1) / items_per_chunk;
594 if (needed_chunks <= _nfree_chunks) {
597 needed_chunks -= _nfree_chunks;
598 while (needed_chunks--) {
599 chunk *c =
new chunk;
600 c->next = _free_chunks;
606template <
typename T,
size_t items_per_chunk>
607inline typename chunked_fifo<T, items_per_chunk>::iterator
608chunked_fifo<T, items_per_chunk>::begin() noexcept {
609 return iterator(_front_chunk);
612template <
typename T,
size_t items_per_chunk>
613inline typename chunked_fifo<T, items_per_chunk>::iterator
614chunked_fifo<T, items_per_chunk>::end() noexcept {
615 return iterator(
nullptr);
618template <
typename T,
size_t items_per_chunk>
619inline typename chunked_fifo<T, items_per_chunk>::const_iterator
620chunked_fifo<T, items_per_chunk>::begin() const noexcept {
621 return const_iterator(_front_chunk);
624template <
typename T,
size_t items_per_chunk>
625inline typename chunked_fifo<T, items_per_chunk>::const_iterator
626chunked_fifo<T, items_per_chunk>::end() const noexcept {
627 return const_iterator(
nullptr);
630template <
typename T,
size_t items_per_chunk>
631inline typename chunked_fifo<T, items_per_chunk>::const_iterator
632chunked_fifo<T, items_per_chunk>::cbegin() const noexcept {
633 return const_iterator(_front_chunk);
636template <
typename T,
size_t items_per_chunk>
637inline typename chunked_fifo<T, items_per_chunk>::const_iterator
638chunked_fifo<T, items_per_chunk>::cend() const noexcept {
639 return const_iterator(
nullptr);
Definition: chunked_fifo.hh:94
Seastar API namespace.
Definition: abort_on_ebadf.hh:26