19#include <fmt/ostream.h>
27template<
class T,
size_t _Padding = 0>
38 : _infiniteBuffer(maxSize == 0), _maxSize(maxSize + _Padding), _dataStart(_Padding), _dataEnd(_infiniteBuffer ? 0 : _Padding)
40 _data.reserve(maxSize + _Padding);
41 _data.resize(_Padding);
47 : _infiniteBuffer(init.
size() == 0), _maxSize(init.
size())
49 _data.reserve(init.size());
51 for (
auto& val : init)
75 [[nodiscard]]
const T&
at(
size_t pos)
const
79 throw std::out_of_range(
"ScrollingBuffer::at: pos (which is "
80 + std::to_string(pos) +
") >= this->size() (which is " + std::to_string(
size()) +
")");
87 if (_dataStart + pos >= _maxSize)
89 return _data.at(_dataStart + pos - _maxSize);
92 return _data.at(_dataStart + pos);
107 [[nodiscard]]
const T&
front()
const
109 return _data.at(_dataStart);
123 [[nodiscard]]
const T&
back()
const
125 if (_data.size() < _maxSize || _dataEnd == 0)
130 return _data.at(_dataEnd - 1);
151 : buffer(buffer), index(index) {}
161 if (index == buffer.
size()) {
return *
this; }
212 : buffer(buffer), index(index) {}
222 if (index == buffer.
size()) {
return *
this; }
281 : buffer(buffer), index(index) {}
291 if (index < 0) {
return *
this; }
344 : buffer(buffer), index(index) {}
354 if (index < 0) {
return *
this; }
414 [[nodiscard]]
bool full()
const
416 return !_infiniteBuffer && _maxSize - _Padding ==
size();
420 [[nodiscard]]
size_t size()
const
422 if (_dataStart == _Padding && _dataEnd == _Padding)
424 return _data.size() - _Padding;
426 if (_dataStart < _dataEnd)
428 return _dataEnd - _dataStart;
432 return _maxSize - (_dataStart - _dataEnd);
439 _data.reserve(new_cap);
445 return _infiniteBuffer ? 0 : (_maxSize - _Padding);
456 _dataStart = _Padding;
457 _dataEnd = _infiniteBuffer ? 0 : _Padding;
459 for (
size_t i = 0; i < _Padding; i++)
471 _data.push_back(value);
472 _maxSize = _data.size();
474 else if (_data.size() < _maxSize)
476 _data.push_back(value);
477 _dataEnd = (_dataEnd + 1) % _maxSize;
481 _data.at(_dataEnd) = value;
486 _dataStart = (_dataStart + 1) % _maxSize;
488 _dataEnd = (_dataEnd + 1) % _maxSize;
507 _data.erase(_data.begin());
508 _maxSize = _data.size();
516 _dataStart = (_dataStart + 1) % _maxSize;
526 _infiniteBuffer =
true;
533 std::vector<T> to_vector;
535 if (_dataEnd > _dataStart)
537 std::copy(std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd)), _data.end(),
538 std::back_inserter(to_vector));
542 std::copy(std::next(_data.begin(), std::max(
static_cast<int>(_dataStart - _Padding), 0)),
543 std::next(_data.begin(),
static_cast<int64_t
>(std::max(_dataEnd, _maxSize))),
544 std::back_inserter(to_vector));
546 if (int64_t elementsFront = std::min(
static_cast<int64_t
>(_dataEnd),
static_cast<int64_t
>(_dataStart - _Padding));
549 std::copy(_data.begin(), std::next(_data.begin(), elementsFront),
550 std::back_inserter(to_vector));
552 _data.swap(to_vector);
554 _maxSize = _data.size();
556 _dataStart = _Padding;
562 _infiniteBuffer =
false;
564 if (_maxSize - _Padding > targetSize)
568 size_t elementsToDelete = _maxSize - _Padding - targetSize;
570 if (
size_t emptyAtTheBack = _maxSize - _dataEnd;
571 size_t emptyAtTheBackToDelete = std::min(emptyAtTheBack, elementsToDelete))
575 _maxSize -= emptyAtTheBackToDelete;
576 _dataEnd %= _maxSize;
577 elementsToDelete -= emptyAtTheBackToDelete;
583 if (elementsToDelete)
585 _data.erase(std::next(_data.begin(),
static_cast<int64_t
>(_dataStart)),
586 std::next(_data.begin(),
static_cast<int64_t
>(_dataStart + elementsToDelete)));
587 _maxSize -= elementsToDelete;
601 size_t elementsToDelete = _maxSize - _Padding - targetSize;
603 if (
size_t emptyInBetween =
static_cast<size_t>(std::max(
static_cast<int>(_dataStart - _Padding - _dataEnd), 0));
604 size_t emptyInBetweenToDelete = std::min(emptyInBetween, elementsToDelete))
607 _data.erase(std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd)),
608 std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd + emptyInBetweenToDelete)));
610 _dataStart -= emptyInBetweenToDelete;
611 _maxSize -= emptyInBetweenToDelete;
612 elementsToDelete -= emptyInBetweenToDelete;
618 if (
size_t paddingAtTheEnd =
static_cast<size_t>(std::max(
static_cast<int>(_Padding - _dataStart), 0));
619 size_t paddingAtTheEndToDelete = std::min(paddingAtTheEnd, elementsToDelete))
621 _data.erase(std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd)),
622 std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd + paddingAtTheEndToDelete)));
623 _maxSize -= paddingAtTheEndToDelete;
624 _dataStart += paddingAtTheEndToDelete;
625 _dataEnd %= _maxSize;
626 elementsToDelete -= paddingAtTheEndToDelete;
632 if (
size_t elementsAtTheBack = _maxSize - _dataStart - (_dataEnd > _dataStart ? _maxSize - _dataEnd : 0);
633 size_t elementsAtTheBackToDelete = std::min(elementsAtTheBack, elementsToDelete))
636 _data.erase(std::next(_data.begin(),
static_cast<int64_t
>(_dataStart - _Padding)),
637 std::next(_data.begin(),
static_cast<int64_t
>(_dataStart - _Padding + elementsAtTheBackToDelete)));
640 _maxSize -= elementsAtTheBackToDelete;
641 _dataStart %= _maxSize;
642 if (_dataEnd > _maxSize)
644 _dataEnd -= elementsToDelete;
646 _dataEnd %= _maxSize;
647 elementsToDelete -= elementsAtTheBackToDelete;
649 if (elementsToDelete)
652 _data.erase(std::next(_data.begin(),
static_cast<int64_t
>(_dataStart)),
653 std::next(_data.begin(),
static_cast<int64_t
>(std::min(_dataStart + elementsToDelete, _maxSize - _Padding))));
655 _maxSize -= elementsToDelete;
656 if (_dataEnd >= elementsToDelete)
658 _dataEnd -= elementsToDelete;
663 else if (_maxSize - _Padding < targetSize)
669 _maxSize = targetSize + _Padding;
670 _data.reserve(_maxSize);
677 _data.resize(targetSize + _Padding);
679 std::copy_backward(std::next(_data.begin(),
static_cast<int64_t
>(_dataEnd)),
680 std::next(_data.begin(),
static_cast<int64_t
>(_maxSize)),
681 std::next(_data.begin(),
static_cast<int64_t
>(targetSize + _Padding)));
683 auto diff = targetSize + _Padding - _maxSize;
684 if (_dataStart >= _dataEnd)
689 _maxSize = targetSize + _Padding;
700 [[nodiscard]] T
max()
const
702 T currentMax =
front();
703 for (
size_t i = 0; i < _data.size(); i++)
705 if (i >= _dataStart || i < _dataEnd)
707 currentMax = std::max(currentMax, _data.at(i));
714 [[nodiscard]] T
min()
const
716 T currentMin =
front();
717 for (
size_t i = 0; i < _data.size(); i++)
719 if (i >= _dataStart || i < _dataEnd)
721 currentMin = std::min(currentMin, _data.at(i));
730 return static_cast<int>(_dataStart);
734 [[nodiscard]]
const T*
data()
const
748 return _infiniteBuffer;
782 for (
int i = 0;
static_cast<size_t>(i) < _maxSize; i++)
784 if ((i >=
static_cast<int>(_dataStart - _Padding) &&
static_cast<size_t>(i) < _dataStart)
785 || (
static_cast<size_t>(i) >= _dataStart + _maxSize - _Padding))
789 else if (
bool scrolled = isScrolled();
790 (scrolled &&
static_cast<size_t>(i) >= _dataEnd && (
static_cast<int>(_dataStart - _Padding) < 0 || i < static_cast<int>(_dataStart - _Padding)))
791 || (scrolled && _dataStart < _dataEnd && (static_cast<size_t>(i) < _dataStart ||
static_cast<size_t>(i) >= _dataEnd))
792 || (!scrolled &&
static_cast<size_t>(i) >= _dataEnd))
798 out += std::to_string(_data.at(
static_cast<size_t>(i)));
800 if (
static_cast<size_t>(i) != _maxSize - 1)
814 os << fmt::format(
"{}", fmt::join(buffer,
", "));
820 bool _infiniteBuffer{
false };
825 size_t _dataStart{ 0 };
827 size_t _dataEnd{ 0 };
829 std::vector<T> _data;
832 [[nodiscard]]
bool isScrolled()
const
838 if (_dataEnd == 0 && !
empty())
843 return _dataEnd < _dataStart
844 || (_dataStart != _Padding);
858#ifndef DOXYGEN_IGNORE
860template<
class T,
size_t _Padding>
861struct fmt::formatter<NAV::ScrollingBuffer<T, _Padding>> : ostream_formatter