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

Fix #5399: iterator increment operator does not skip first item #5400

Merged
merged 2 commits into from
Oct 12, 2024

Conversation

dalboris
Copy link
Contributor

@dalboris dalboris commented Oct 8, 2024

Description

Fixes #5399

I fixed this bug by ensuring that the increment operator calls advance() one more time if advance() had never been called before (like operator* and operator-> already did). I encapsulated this logic in a helper function init().

Alternatively, the init() function could directly be called in the constructor, which would make more sense and be more performant since it avoids the extra check on all operators. But I'm not sure how to do this since the constructor is defined via a macro. This is why I used the same method as operator* and operator-> already did.

Suggested changelog entry:

* Fix iterator increment operator does not skip first item

@Skylion007
Copy link
Collaborator

This is a BC breaking change, right?

@dalboris
Copy link
Contributor Author

dalboris commented Oct 8, 2024

Yes, it is a breaking change, but I doubt anyone was relying on the previous behavior, since it was clearly broken. Generic C++ algorithm or ranges-view may fail with the current implementation. In my case, I was using drop(range, 1) which basically did nothing: the returned range still included the first item.

Note: this shouldn't be merged just yet as I realized another problem: init() should be called first in the post-fix increment. I'm adding a test for that too.

@dalboris
Copy link
Contributor Author

dalboris commented Oct 8, 2024

Oh, my bad, I guess you're asking about binary compatibilty. No, I do not think this change breaks binary compatibility, as it does not add any member variables. It only adds a private member method and changes the implementation of the existing public methods.

@dalboris
Copy link
Contributor Author

dalboris commented Oct 8, 2024

So just to clarify, the values before this change were:

def test_iterable(doc):
    assert doc(m.get_iterable) == "get_iterable() -> Iterable"
    lins = [1, 2, 3]
    i = m.get_first_item_from_iterable(lins)
    assert i == 1 # Before this fix, this failed with i being equal to 3 instead
    i = m.get_second_item_from_iterable(lins)
    assert i == 2 # Before this fix, this failed with i being equal to 1 instead

@dalboris
Copy link
Contributor Author

dalboris commented Oct 8, 2024

As far as I'm concerned, it's ready for merging.

Copy link
Collaborator

@rwgk rwgk left a comment

Choose a reason for hiding this comment

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

Thanks for the fix!

Pretty amazing that nobody complained before.

I convinced myself that this is correct by locally adding more tests, but I don't think we need to add them here. What you have appears to be to the point.

@Skylion007 could you please confirm that your "BC breaking change" concerns are addressed?

To me this looks like a regular plain bug fix.

rwgk added a commit to rwgk/stuff that referenced this pull request Oct 10, 2024
@rwgk rwgk merged commit f290765 into pybind:master Oct 12, 2024
80 checks passed
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs changelog Possibly needs a changelog entry
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]: iterator increment operator does not skip first item
3 participants