Skip to content
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

Beats: Remove legacy BeatIterator class in favor of std iterator #4411

Merged
merged 2 commits into from
Oct 29, 2021

Conversation

Holzhaus
Copy link
Member

@Holzhaus Holzhaus commented Oct 13, 2021

The custom, legacy iterator API was only used for rendering beats on the
waveform and for importing beats from Serato BeatGrids.

Since the new iterator API is way more powerful and can be used
with the iterator-based functions from <algorithm>, it makes sense to
replace the only occurrence and then remove the old API entirely.

Based on #4255.

The custom, legacy iterator API was only used for rendering beats on the
waveform and for importing beats from Serato BeatGrids.

Since the new iterator API is way more powerful and can be used
with the iterator-based functions from `<algorithm>`, it makes sense to
replace the only occurrence and then remove the old API entirely.
@Holzhaus Holzhaus marked this pull request as ready for review October 26, 2021 09:18
@Holzhaus
Copy link
Member Author

Ok, ready to review.

@@ -79,8 +81,8 @@ void WaveformRenderBeat::draw(QPainter* painter, QPaintEvent* /*event*/) {

int beatCount = 0;

while (it->hasNext()) {
double beatPosition = it->next().toEngineSamplePos();
for (; it != trackBeats->clatest() && *it <= endPosition; ++it) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for jumping in here, after merging #4255, but it I have discovered now that I have not fully understand the concept of clatest() and cend()

Unfortunately there are zero comments in beats.h explaining this. Can you catch up that in this PR?

I think I have read the original commit as if clatest()++ = cend() but It turns out that this is wrong.
Maybe we can improve the naming a bit.

Here, I have hard time to understand how the new code id equivalent to the old.

Copy link
Member Author

@Holzhaus Holzhaus Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments to beats.h in 9480561.

Copy link
Member Author

@Holzhaus Holzhaus Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically the it != clatest() check prevents an integer overflow here.

@daschuer
Copy link
Member

Ah Ok, thank you for the comments.

The confusing part was/is that this "violates" some regular laws around iterators.

Normally you should never access the end() iterator value and never continue to iterate it, because the result is undefined and is a risk for a segfault.

This is done here regularly, because clatest takes this role.

This was the source if my confusion. I also expect that various helper functions will follow the normal iterator rules, which leads to dificult understand call trees and side effects.

How about introducing two type of iterators?
One for editing purpose that only has the anotaded beats between begin() and end() and an "endless" iterator that allows to iterate over the entire int range. Depending on the use case we can take one or another,both with "normal" end() behavior.

Alternatively we may rename the clatest() to cend() and introduce a new one cAnotatonEnd() or something that expresses the implication that it is appropriate to fetch beats after the end of the anotaded beats.

@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 27, 2021

Ah Ok, thank you for the comments.

The confusing part was/is that this "violates" some regular laws around iterators.

Normally you should never access the end() iterator value and never continue to iterate it, because the result is undefined and is a risk for a segfault.

This is done here regularly, because clatest takes this role.

This was the source if my confusion. I also expect that various helper functions will follow the normal iterator rules, which leads to dificult understand call trees and side effects.

My reasoning was that cbegin returns an iterator that points at the first element of the container, and cend points at the element behind the last element of the container.

Hence, cbegin points at the first beat of the first beat marker(all earlier beats may be before the beginning of the track) and cend points at the end beat marker, i.e. the beat after the last beat of the last beat marker (all beats behind it may be after the end of the track). But this is pretty technical and I can see the issue.

How about introducing two type of iterators? One for editing purpose that only has the anotaded beats between begin() and end() and an "endless" iterator that allows to iterate over the entire int range. Depending on the use case we can take one or another,both with "normal" end() behavior.

cbegin/cend are just methods of the container that return iterators, so I don't see how multiple iterator types would solve that.

Alternatively we may rename the clatest() to cend() and introduce a new one cAnotatonEnd() or something that expresses the implication that it is appropriate to fetch beats after the end of the anotaded beats.

Yes, I'm open to rename cbegin/cend and make cearliest/clatest the new cbegin/cend. But that is unrelated to this PR and out of scope. I'll open a new PR.

@daschuer
Copy link
Member

daschuer commented Oct 27, 2021

Thank you to consider this.

cbegin/cend are just methods of the container that return iterators, so I don't see how multiple iterator types would solve that.

My idea was that we have two or more types of iterators for the differen ways to iterate over the beats. All of them can use begin() and end() as you may expect from any iterator and specialized for the range you need.

Maybe we can also introduce different container types as "view" in the original container.

Like "all annotated beats view" "all beat view unlimited" "measures view" "downbeat view" or whatever we need.

Just an idea ...

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@daschuer
Copy link
Member

Merge? What do you think to the "view" idea?

@Holzhaus
Copy link
Member Author

Merge?

Yup.

What do you think to the "view" idea?

I don't think we need two different classes, but maybe a dedicated iterator for beat markers could make sense. In general, we already have that because you can iterate over the beat marker vector instead of iterating over individual beats. I need to think about that some more.

However, I can open a PR which renames the methods as a first step soon.

@daschuer
Copy link
Member

Thank you.

@daschuer daschuer merged commit c09332b into mixxxdj:main Oct 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants