27#include <seastar/util/modules.hh>
89template <
typename T,
size_t items_per_chunk = 128>
91 static_assert((items_per_chunk & (items_per_chunk - 1)) == 0,
92 "chunked_fifo chunk size must be power of two");
94 maybe_item()
noexcept {}
99 maybe_item items[items_per_chunk];
106 size_t size()
const {
113 chunk* _front_chunk =
nullptr;
114 chunk* _back_chunk =
nullptr;
127 chunk* _free_chunks =
nullptr;
128 size_t _nfree_chunks = 0;
130 using value_type = T;
131 using size_type = size_t;
132 using reference = T&;
134 using const_reference =
const T&;
135 using const_pointer =
const T*;
138 template <
bool IsConst>
139 class basic_iterator {
143 using iterator_category = std::forward_iterator_tag;
144 using difference_type = std::ptrdiff_t;
145 using value_type = std::conditional_t<IsConst, const T, T>;
146 using pointer = value_type*;
147 using reference = value_type&;
150 using chunk_t = std::conditional_t<IsConst, const chunk, chunk>;
151 chunk_t* _chunk =
nullptr;
152 size_t _item_index = 0;
155 inline explicit basic_iterator(chunk_t* c)
noexcept;
156 inline basic_iterator(chunk_t* c,
size_t item_index)
noexcept;
159 basic_iterator()
noexcept =
default;
160 template<
bool OtherIsConst, std::enable_if_t<IsConst && !OtherIsConst,
int> = 0>
161 inline basic_iterator(
const basic_iterator<OtherIsConst>& o) noexcept
162 : basic_iterator{o._chunk, o._item_index} {}
163 inline bool operator==(
const basic_iterator& o)
const noexcept;
164 inline bool operator!=(
const basic_iterator& o)
const noexcept;
165 inline pointer operator->()
const noexcept;
166 inline reference operator*()
const noexcept;
167 inline basic_iterator operator++(
int)
noexcept;
168 basic_iterator& operator++()
noexcept;
172 using iterator = basic_iterator<false>;
173 using const_iterator = basic_iterator<true>;
182 inline void push_back(
const T& data);
183 inline void push_back(T&& data);
185 const T& back()
const noexcept;
186 template <
typename... A>
187 inline void emplace_back(A&&... args);
188 inline T& front()
const noexcept;
189 inline void pop_front()
noexcept;
190 inline bool empty()
const noexcept;
191 inline size_t size()
const noexcept;
195 void pop_front_n(
size_t n)
noexcept;
196 void clear()
noexcept;
203 void reserve(
size_t n);
206 void shrink_to_fit()
noexcept;
207 inline iterator begin()
noexcept;
208 inline iterator end()
noexcept;
209 inline const_iterator begin()
const noexcept;
210 inline const_iterator end()
const noexcept;
211 inline const_iterator cbegin()
const noexcept;
212 inline const_iterator cend()
const noexcept;
214 void back_chunk_new();
215 void front_chunk_delete()
noexcept;
216 inline void ensure_room_back();
217 void undo_room_back()
noexcept;
218 static inline size_t mask(
size_t idx)
noexcept;
222template <
typename T,
size_t items_per_chunk>
223template <
bool IsConst>
228template <
typename T,
size_t items_per_chunk>
229template <
bool IsConst>
231chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::basic_iterator(chunk_t* c,
size_t item_index) noexcept : _chunk(c), _item_index(item_index) {
234template <
typename T,
size_t items_per_chunk>
235template <
bool IsConst>
237chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator==(
const basic_iterator& o)
const noexcept {
238 return _chunk == o._chunk && _item_index == o._item_index;
241template <
typename T,
size_t items_per_chunk>
242template <
bool IsConst>
244chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator!=(
const basic_iterator& o)
const noexcept {
245 return !(*
this == o);
248template <
typename T,
size_t items_per_chunk>
249template <
bool IsConst>
250inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::pointer
251chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator->() const noexcept {
252 return &_chunk->items[chunked_fifo::mask(_item_index)].data;
255template <
typename T,
size_t items_per_chunk>
256template <
bool IsConst>
257inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>::reference
258chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator*() const noexcept {
259 return _chunk->items[chunked_fifo::mask(_item_index)].data;
262template <
typename T,
size_t items_per_chunk>
263template <
bool IsConst>
264inline typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>
265chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++(
int)
noexcept {
271template <
typename T,
size_t items_per_chunk>
272template <
bool IsConst>
273typename chunked_fifo<T, items_per_chunk>::template basic_iterator<IsConst>&
274chunked_fifo<T, items_per_chunk>::basic_iterator<IsConst>::operator++() noexcept {
276 if (_item_index == _chunk->end) {
277 _chunk = _chunk->next;
278 _item_index = _chunk ? _chunk->begin : 0;
283template <
typename T,
size_t items_per_chunk>
285chunked_fifo<T, items_per_chunk>::chunked_fifo(chunked_fifo&& x) noexcept
286 : _front_chunk(x._front_chunk)
287 , _back_chunk(x._back_chunk)
288 , _nchunks(x._nchunks)
289 , _free_chunks(x._free_chunks)
290 , _nfree_chunks(x._nfree_chunks) {
291 x._front_chunk =
nullptr;
292 x._back_chunk =
nullptr;
294 x._free_chunks =
nullptr;
298template <
typename T,
size_t items_per_chunk>
300chunked_fifo<T, items_per_chunk>&
301chunked_fifo<T, items_per_chunk>::operator=(chunked_fifo&& x)
noexcept {
303 this->~chunked_fifo();
304 new (
this) chunked_fifo(std::move(x));
309template <
typename T,
size_t items_per_chunk>
311chunked_fifo<T, items_per_chunk>::mask(
size_t idx)
noexcept {
312 return idx & (items_per_chunk - 1);
315template <
typename T,
size_t items_per_chunk>
317chunked_fifo<T, items_per_chunk>::empty() const noexcept {
318 return _front_chunk ==
nullptr;
321template <
typename T,
size_t items_per_chunk>
323chunked_fifo<T, items_per_chunk>::size() const noexcept{
324 if (_front_chunk ==
nullptr) {
326 }
else if (_back_chunk == _front_chunk) {
328 return _front_chunk->end - _front_chunk->begin;
330 return _front_chunk->end - _front_chunk->begin
331 +_back_chunk->end - _back_chunk->begin
332 + (_nchunks - 2) * items_per_chunk;
336template <
typename T,
size_t items_per_chunk>
337void chunked_fifo<T, items_per_chunk>::clear() noexcept {
341template <
typename T,
size_t items_per_chunk>
342void chunked_fifo<T, items_per_chunk>::pop_front_n(
size_t n)
noexcept {
344 assert(_front_chunk &&
"pop_front_n n too large");
346 auto target = _front_chunk;
347 unsigned delete_count = std::min(target->size(), n);
349 for (
auto i = target->begin, e = i + delete_count; i != e; i++) {
350 target->items[mask(i)].data.~T();
353 target->begin += delete_count;
356 if (target->size() == 0) {
357 front_chunk_delete();
364template <
typename T,
size_t items_per_chunk>
void
365chunked_fifo<T, items_per_chunk>::shrink_to_fit() noexcept {
366 while (_free_chunks) {
367 auto next = _free_chunks->next;
374template <
typename T,
size_t items_per_chunk>
375chunked_fifo<T, items_per_chunk>::~chunked_fifo() {
380template <
typename T,
size_t items_per_chunk>
382chunked_fifo<T, items_per_chunk>::back_chunk_new() {
383 chunk *old = _back_chunk;
385 _back_chunk = _free_chunks;
386 _free_chunks = _free_chunks->next;
389 _back_chunk =
new chunk;
391 _back_chunk->next =
nullptr;
392 _back_chunk->begin = 0;
393 _back_chunk->end = 0;
395 old->next = _back_chunk;
397 if (_front_chunk ==
nullptr) {
398 _front_chunk = _back_chunk;
404template <
typename T,
size_t items_per_chunk>
406chunked_fifo<T, items_per_chunk>::ensure_room_back() {
408 if (_back_chunk ==
nullptr ||
409 (_back_chunk->end - _back_chunk->begin) == items_per_chunk) {
414template <
typename T,
size_t items_per_chunk>
416chunked_fifo<T, items_per_chunk>::undo_room_back() noexcept {
421 if (_back_chunk->begin == _back_chunk->end) {
425 _back_chunk =
nullptr;
426 _front_chunk =
nullptr;
431 chunk *old = _back_chunk;
432 _back_chunk = _front_chunk;
433 while (_back_chunk->next != old) {
434 _back_chunk = _back_chunk->next;
436 _back_chunk->next =
nullptr;
442template <
typename T,
size_t items_per_chunk>
443template <
typename... Args>
445chunked_fifo<T, items_per_chunk>::emplace_back(Args&&... args) {
447 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
449 new(p) T(std::forward<Args>(args)...);
457template <
typename T,
size_t items_per_chunk>
459chunked_fifo<T, items_per_chunk>::push_back(
const T& data) {
461 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
471template <
typename T,
size_t items_per_chunk>
473chunked_fifo<T, items_per_chunk>::push_back(T&& data) {
475 auto p = &_back_chunk->items[mask(_back_chunk->end)].data;
477 new(p) T(std::move(data));
485template <
typename T,
size_t items_per_chunk>
488chunked_fifo<T, items_per_chunk>::back() noexcept {
489 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
492template <
typename T,
size_t items_per_chunk>
495chunked_fifo<T, items_per_chunk>::back() const noexcept {
496 return _back_chunk->items[mask(_back_chunk->end - 1)].data;
499template <
typename T,
size_t items_per_chunk>
501chunked_fifo<T, items_per_chunk>::front() const noexcept {
502 return _front_chunk->items[mask(_front_chunk->begin)].data;
505template <
typename T,
size_t items_per_chunk>
507chunked_fifo<T, items_per_chunk>::front_chunk_delete() noexcept {
508 chunk *next = _front_chunk->next;
520 static constexpr int save_free_chunks = 1;
521 if (_nfree_chunks < save_free_chunks) {
522 _front_chunk->next = _free_chunks;
523 _free_chunks = _front_chunk;
529 if (_back_chunk == _front_chunk) {
530 _back_chunk =
nullptr;
536template <
typename T,
size_t items_per_chunk>
538chunked_fifo<T, items_per_chunk>::pop_front() noexcept {
542 if (++_front_chunk->begin == _front_chunk->end) {
543 front_chunk_delete();
547template <
typename T,
size_t items_per_chunk>
548void chunked_fifo<T, items_per_chunk>::reserve(
size_t n) {
554 size_t need = n - size();
558 size_t back_chunk_n = items_per_chunk - (_back_chunk->end - _back_chunk->begin);
559 need -= std::min(back_chunk_n, need);
561 size_t needed_chunks = (need + items_per_chunk - 1) / items_per_chunk;
564 if (needed_chunks <= _nfree_chunks) {
567 needed_chunks -= _nfree_chunks;
568 while (needed_chunks--) {
569 chunk *c =
new chunk;
570 c->next = _free_chunks;
576template <
typename T,
size_t items_per_chunk>
577inline typename chunked_fifo<T, items_per_chunk>::iterator
578chunked_fifo<T, items_per_chunk>::begin() noexcept {
579 return iterator(_front_chunk);
582template <
typename T,
size_t items_per_chunk>
583inline typename chunked_fifo<T, items_per_chunk>::iterator
584chunked_fifo<T, items_per_chunk>::end() noexcept {
585 return iterator(
nullptr);
588template <
typename T,
size_t items_per_chunk>
589inline typename chunked_fifo<T, items_per_chunk>::const_iterator
590chunked_fifo<T, items_per_chunk>::begin() const noexcept {
591 return const_iterator(_front_chunk);
594template <
typename T,
size_t items_per_chunk>
595inline typename chunked_fifo<T, items_per_chunk>::const_iterator
596chunked_fifo<T, items_per_chunk>::end() const noexcept {
597 return const_iterator(
nullptr);
600template <
typename T,
size_t items_per_chunk>
601inline typename chunked_fifo<T, items_per_chunk>::const_iterator
602chunked_fifo<T, items_per_chunk>::cbegin() const noexcept {
603 return const_iterator(_front_chunk);
606template <
typename T,
size_t items_per_chunk>
607inline typename chunked_fifo<T, items_per_chunk>::const_iterator
608chunked_fifo<T, items_per_chunk>::cend() const noexcept {
609 return const_iterator(
nullptr);
Definition: chunked_fifo.hh:90
Seastar API namespace.
Definition: abort_on_ebadf.hh:26