29#include <seastar/util/assert.hh>
30#include <seastar/util/modules.hh>
92template <
typename T,
size_t items_per_chunk = 128>
94 static_assert((items_per_chunk & (items_per_chunk - 1)) == 0,
95 "chunked_fifo chunk size must be power of two");
97 maybe_item()
noexcept {}
102 maybe_item items[items_per_chunk];
109 size_t size()
const {
116 chunk* _front_chunk =
nullptr;
117 chunk* _back_chunk =
nullptr;
130 chunk* _free_chunks =
nullptr;
131 size_t _nfree_chunks = 0;
133 using value_type = T;
134 using size_type = size_t;
135 using reference = T&;
137 using const_reference =
const T&;
138 using const_pointer =
const T*;
141 template <
bool IsConst>
142 class basic_iterator {
146 using iterator_category = std::forward_iterator_tag;
147 using difference_type = std::ptrdiff_t;
148 using value_type = std::conditional_t<IsConst, const T, T>;
149 using pointer = value_type*;
150 using reference = value_type&;
153 using chunk_t = std::conditional_t<IsConst, const chunk, chunk>;
154 chunk_t* _chunk =
nullptr;
155 size_t _item_index = 0;
158 inline explicit basic_iterator(chunk_t* c)
noexcept;
159 inline basic_iterator(chunk_t* c,
size_t item_index)
noexcept;
162 basic_iterator()
noexcept =
default;
163 template<
bool OtherIsConst, std::enable_if_t<IsConst && !OtherIsConst,
int> = 0>
164 inline basic_iterator(
const basic_iterator<OtherIsConst>& o) noexcept
165 : basic_iterator{o._chunk, o._item_index} {}
166 inline bool operator==(
const basic_iterator& o)
const noexcept;
167 inline bool operator!=(
const basic_iterator& o)
const noexcept;
168 inline pointer operator->()
const noexcept;
169 inline reference operator*()
const noexcept;
170 inline basic_iterator operator++(
int)
noexcept;
171 basic_iterator& operator++()
noexcept;
175 using iterator = basic_iterator<false>;
176 using const_iterator = basic_iterator<true>;
186 inline void push_back(
const T& data);
187 inline void push_back(T&& data);
189 const T& back()
const noexcept;
190 template <
typename... A>
191 inline void emplace_back(A&&... args);
192 inline T& front()
const noexcept;
193 inline void pop_front()
noexcept;
194 inline bool empty()
const noexcept;
195 inline size_t size()
const noexcept;
199 void pop_front_n(
size_t n)
noexcept;
200 void clear()
noexcept;
207 void reserve(
size_t n);
210 void shrink_to_fit()
noexcept;
211 inline iterator begin()
noexcept;
212 inline iterator end()
noexcept;
213 inline const_iterator begin()
const noexcept;
214 inline const_iterator end()
const noexcept;
215 inline const_iterator cbegin()
const noexcept;
216 inline const_iterator cend()
const noexcept;
218 void back_chunk_new();
219 void front_chunk_delete()
noexcept;
220 inline void ensure_room_back();
221 void undo_room_back()
noexcept;
222 static inline size_t mask(
size_t idx)
noexcept;
226template <
typename T,
size_t items_per_chunk>
227template <
bool IsConst>
232template <
typename T,
size_t items_per_chunk>
233template <
bool IsConst>
235chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::basic_iterator(chunk_t* c,
size_t item_index) noexcept : _chunk(c), _item_index(item_index) {
238template <
typename T,
size_t items_per_chunk>
239template <
bool IsConst>
241chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator==(
const basic_iterator& o)
const noexcept {
242 return _chunk == o._chunk && _item_index == o._item_index;
245template <
typename T,
size_t items_per_chunk>
246template <
bool IsConst>
248chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator!=(
const basic_iterator& o)
const noexcept {
249 return !(*
this == o);
252template <
typename T,
size_t items_per_chunk>
253template <
bool IsConst>
254inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::pointer
255chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator->() const noexcept {
256 return &_chunk->items[chunked_fifo::mask(_item_index)].data;
259template <
typename T,
size_t items_per_chunk>
260template <
bool IsConst>
261inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::reference
262chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator*() const noexcept {
263 return _chunk->items[chunked_fifo::mask(_item_index)].data;
266template <
typename T,
size_t items_per_chunk>
267template <
bool IsConst>
268inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>
269chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++(
int)
noexcept {
275template <
typename T,
size_t items_per_chunk>
276template <
bool IsConst>
277typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>&
278chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++() noexcept {
280 if (_item_index == _chunk->end) {
281 _chunk = _chunk->next;
282 _item_index = _chunk ? _chunk->begin : 0;
287template <
typename T,
size_t items_per_chunk>
289chunked_fifo<T, items_per_chunk>::chunked_fifo(chunked_fifo&& x) noexcept
290 : _front_chunk(x._front_chunk)
291 , _back_chunk(x._back_chunk)
292 , _nchunks(x._nchunks)
293 , _free_chunks(x._free_chunks)
294 , _nfree_chunks(x._nfree_chunks) {
295 x._front_chunk =
nullptr;
296 x._back_chunk =
nullptr;
298 x._free_chunks =
nullptr;
302template <
typename T,
size_t items_per_chunk>
304chunked_fifo<T, items_per_chunk>::chunked_fifo(
const chunked_fifo& rhs)
306 std::copy_n(rhs.begin(), rhs.size(), std::back_inserter(*
this));
309template <
typename T,
size_t items_per_chunk>
311chunked_fifo<T, items_per_chunk>&
312chunked_fifo<T, items_per_chunk>::operator=(
const chunked_fifo& rhs) {
315 std::copy_n(rhs.begin(), rhs.size(), std::back_inserter(*
this));
321template <
typename T,
size_t items_per_chunk>
323chunked_fifo<T, items_per_chunk>&
324chunked_fifo<T, items_per_chunk>::operator=(chunked_fifo&& x)
noexcept {
326 this->~chunked_fifo();
327 new (
this) chunked_fifo(std::move(x));
332template <
typename T,
size_t items_per_chunk>
334chunked_fifo<T, items_per_chunk>::mask(
size_t idx)
noexcept {
335 return idx & (items_per_chunk - 1);
338template <
typename T,
size_t items_per_chunk>
340chunked_fifo<T, items_per_chunk>::empty() const noexcept {
341 return _front_chunk ==
nullptr;
344template <
typename T,
size_t items_per_chunk>
346chunked_fifo<T, items_per_chunk>::size() const noexcept{
347 if (_front_chunk ==
nullptr) {
349 }
else if (_back_chunk == _front_chunk) {
351 return _front_chunk->end - _front_chunk->begin;
353 return _front_chunk->end - _front_chunk->begin
354 +_back_chunk->end - _back_chunk->begin
355 + (_nchunks - 2) * items_per_chunk;
359template <
typename T,
size_t items_per_chunk>
360void chunked_fifo<T, items_per_chunk>::clear() noexcept {
364template <
typename T,
size_t items_per_chunk>
365void chunked_fifo<T, items_per_chunk>::pop_front_n(
size_t n)
noexcept {
367 SEASTAR_ASSERT(_front_chunk &&
"pop_front_n n too large");
369 auto target = _front_chunk;
370 unsigned delete_count = std::min(target->size(), n);
372 for (
auto i = target->begin, e = i + delete_count; i != e; i++) {
373 target->items[mask(i)].data.~T();
376 target->begin += delete_count;
379 if (target->size() == 0) {
380 front_chunk_delete();
387template <
typename T,
size_t items_per_chunk>
void
388chunked_fifo<T, items_per_chunk>::shrink_to_fit() noexcept {
389 while (_free_chunks) {
390 auto next = _free_chunks->next;
397template <
typename T,
size_t items_per_chunk>
398chunked_fifo<T, items_per_chunk>::~chunked_fifo() {
403template <
typename T,
size_t items_per_chunk>
405chunked_fifo<T, items_per_chunk>::back_chunk_new() {
406 chunk *old = _back_chunk;
408 _back_chunk = _free_chunks;
409 _free_chunks = _free_chunks->next;
412 _back_chunk =
new chunk;
414 _back_chunk->next =
nullptr;
415 _back_chunk->begin = 0;
416 _back_chunk->end = 0;
418 old->next = _back_chunk;
420 if (_front_chunk ==
nullptr) {
421 _front_chunk = _back_chunk;
427template <
typename T,
size_t items_per_chunk>
429chunked_fifo<T, items_per_chunk>::ensure_room_back() {
431 if (_back_chunk ==
nullptr ||
432 (_back_chunk->end - _back_chunk->begin) == items_per_chunk) {
437template <
typename T,
size_t items_per_chunk>
439chunked_fifo<T, items_per_chunk>::undo_room_back() noexcept {
444 if (_back_chunk->begin == _back_chunk->end) {
448 _back_chunk =
nullptr;
449 _front_chunk =
nullptr;
454 chunk *old = _back_chunk;
455 _back_chunk = _front_chunk;
456 while (_back_chunk->next != old) {
457 _back_chunk = _back_chunk->next;
459 _back_chunk->next =
nullptr;
465template <
typename T,
size_t items_per_chunk>
466template <
typename... Args>
468chunked_fifo<T, items_per_chunk>::emplace_back(Args&&... args) {
470 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
472 new(p) T(std::forward<Args>(args)...);
480template <
typename T,
size_t items_per_chunk>
481inline bool chunked_fifo<T, items_per_chunk>::operator==(
const chunked_fifo& rhs)
const {
482 return size() == rhs.size() && std::equal(begin(), end(), rhs.begin());
485template <
typename T,
size_t items_per_chunk>
487chunked_fifo<T, items_per_chunk>::push_back(
const T& data) {
489 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
499template <
typename T,
size_t items_per_chunk>
501chunked_fifo<T, items_per_chunk>::push_back(T&& data) {
503 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
505 new(p) T(std::move(data));
513template <
typename T,
size_t items_per_chunk>
516chunked_fifo<T, items_per_chunk>::back() noexcept {
517 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
520template <
typename T,
size_t items_per_chunk>
523chunked_fifo<T, items_per_chunk>::back() const noexcept {
524 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
527template <
typename T,
size_t items_per_chunk>
529chunked_fifo<T, items_per_chunk>::front() const noexcept {
530 return _front_chunk->items[mask(_front_chunk->begin)].data;
533template <
typename T,
size_t items_per_chunk>
535chunked_fifo<T, items_per_chunk>::front_chunk_delete() noexcept {
536 chunk *next = _front_chunk->next;
548 static constexpr int save_free_chunks = 1;
549 if (_nfree_chunks < save_free_chunks) {
550 _front_chunk->next = _free_chunks;
551 _free_chunks = _front_chunk;
557 if (_back_chunk == _front_chunk) {
558 _back_chunk =
nullptr;
564template <
typename T,
size_t items_per_chunk>
566chunked_fifo<T, items_per_chunk>::pop_front() noexcept {
570 if (++_front_chunk->begin == _front_chunk->end) {
571 front_chunk_delete();
575template <
typename T,
size_t items_per_chunk>
576void chunked_fifo<T, items_per_chunk>::reserve(
size_t n) {
582 size_t need = n - size();
586 size_t back_chunk_n = items_per_chunk - (_back_chunk->end - _back_chunk->begin);
587 need -= std::min(back_chunk_n, need);
589 size_t needed_chunks = (need + items_per_chunk - 1) / items_per_chunk;
592 if (needed_chunks <= _nfree_chunks) {
595 needed_chunks -= _nfree_chunks;
596 while (needed_chunks--) {
597 chunk *c =
new chunk;
598 c->next = _free_chunks;
604template <
typename T,
size_t items_per_chunk>
605inline typename chunked_fifo<T, items_per_chunk>::iterator
606chunked_fifo<T, items_per_chunk>::begin() noexcept {
607 return iterator(_front_chunk);
610template <
typename T,
size_t items_per_chunk>
611inline typename chunked_fifo<T, items_per_chunk>::iterator
612chunked_fifo<T, items_per_chunk>::end() noexcept {
613 return iterator(
nullptr);
616template <
typename T,
size_t items_per_chunk>
617inline typename chunked_fifo<T, items_per_chunk>::const_iterator
618chunked_fifo<T, items_per_chunk>::begin() const noexcept {
619 return const_iterator(_front_chunk);
622template <
typename T,
size_t items_per_chunk>
623inline typename chunked_fifo<T, items_per_chunk>::const_iterator
624chunked_fifo<T, items_per_chunk>::end() const noexcept {
625 return const_iterator(
nullptr);
628template <
typename T,
size_t items_per_chunk>
629inline typename chunked_fifo<T, items_per_chunk>::const_iterator
630chunked_fifo<T, items_per_chunk>::cbegin() const noexcept {
631 return const_iterator(_front_chunk);
634template <
typename T,
size_t items_per_chunk>
635inline typename chunked_fifo<T, items_per_chunk>::const_iterator
636chunked_fifo<T, items_per_chunk>::cend() const noexcept {
637 return const_iterator(
nullptr);
Definition: chunked_fifo.hh:93
Seastar API namespace.
Definition: abort_on_ebadf.hh:26