-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XMas-Day-1: HistoryBuffer: added push_front method, iterator constraints, and resize #490
base: main
Are you sure you want to change the base?
Conversation
- provide push_front(const T&) and push_front(Iter, Iter) for reversed usage - provide pop_front() and pop_back() to have a deque-like behaviour - provide resize(std::size_t) to adjust capacity - enforce std::input_iterator and std::ranges::range in push_back_bulk/push_[front, back] - added minimal unit tests for resize and front()/back() Signed-off-by: Ralph J. Steinhagen <[email protected]>
const auto nSamplesToCopy = std::distance(cbegin, cend); | ||
Iter optimizedBegin = static_cast<std::size_t>(nSamplesToCopy) > _capacity ? std::prev(cend, static_cast<std::ptrdiff_t>(_capacity)) : cbegin; | ||
for (auto it = optimizedBegin; it != cend; ++it) { | ||
push_back(*it); | ||
} | ||
} | ||
|
||
template<std::input_iterator Iter> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a separate name for the new push_back?
IMO, it should be named append_range
as in std::vector
, though that one takes a range and not a pair of iterators. We could have append_range(begin, end)
and append_range(range)
-- if the functions below also become append_range
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't want to break existing code, thus keeping the "old" push_back_bulk(...)
. From a templated API point of view there is no need to distinguish to distinguish between single sample or bulk operation. The implementation is different (for efficiency reasons) but the API should stay the same.
push_back
and `push_front' keep the symmetry between reverse (nominal) and forward (new optional) behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't want to break existing code, thus keeping the "old" push_back_bulk(...).
I was hoping we're still in the 'we can break API things' as we didn't have a release. (and we do break behaviour in other places from time to time)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally yes, but didn't want to change the whole code base and do the follow-up in gr-digitizer and OpenDigitizer ... yet.
constexpr void push_back_bulk(const Range& range) noexcept { | ||
push_back_bulk(range.cbegin(), range.cend()); | ||
} | ||
|
||
/** | ||
* @brief Adds an element to the front expiring the oldest element beyond the buffer's capacities. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what this means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still a circular/limited buffer size. If you add a sample (either front or back) the oldest is being dropped once the maximum size is reached. This is the difference to the std::deque
behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I get that, just wanted to say the comment itself is not that clear :)
* the "newest" in the ring, with operator[](0) always the oldest. | ||
*/ | ||
template<std::input_iterator Iter> | ||
constexpr void push_front(Iter first, Iter last) noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the previous comment, this would be prepend_range
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went for the std::deque API syntax with some sprinkles of std::vector<T>
. Hope this make sense. Didn't want to break too much of the existing API/use elsewhere.
:-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::deque
also has single-value push_back/push_front and append_range/prepend_range for multiple values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't know about 'append_range/prepend_range' yet (it's C++23 newish). Shall we add this? I like the overloaded push_back/push_front
alone because semantically there isn't much difference other than that the ..._range
also describe the type of function argument.
Signed-off-by: Ralph J. Steinhagen <[email protected]>
Quality Gate failedFailed conditions |
On the first day of Christmas 🎄 👼 1️⃣ 🎄 , my code base gave to me...
A ring buffer with push_front and pop—how jolly can that be?
This PR refines the
HistoryBuffer
by introducing or improving:Along the way, we trimmed some unneeded modulo operations for single-step increments, simplified loops with
std::copy
, and tidied up our tests.Feel free to test it out and give feedback.
Happy coding—and happy holidays!
Code Example: