fix(stl_bind): correct __delitem__ for negative-step slices and re-enable contiguous erase fast path (#6088)
* fix(stl_bind): correct __delitem__ for negative-step slices and re-enable contiguous erase fast path
The slice __delitem__ binding advanced the erase index by step - 1 for
all steps. That correction is only valid for positive steps, where
erasing shifts later elements down by one. For negative steps the
visited indices are strictly decreasing and erasing never shifts them,
so the extra -1 deleted the wrong elements (e.g. del v[::-2] on
[0,1,2,3] yielded [1,2] instead of [0,2]) and del v[::-1] walked off the
front of the vector (v.begin() - 1, observed SIGBUS).
Switch to the signed slice::compute overload so negative steps stay
signed, advance by step for negative steps and step - 1 for positive
ones, and drop the && false that had disabled the O(n) contiguous fast
path since 2016.
Assisted-by: ClaudeCode:claude-fable-5
* refactor: address review — static_cast and parametrized test
Use static_cast instead of a C-style cast for the slice.compute() size
argument, and convert the __delitem__ slice test to
pytest.mark.parametrize over the slice cases.
Assisted-by: ClaudeCode:claude-fable-5
* test(stl_bind): cover slice deletion edge cases
* fix(stl_bind): erase strided slices in descending order
* Eliminate a variable and avoid redundant index increment (i + 1, ++i).
The control flow handles all relevant boundaries:
- slicelength == 0: excluded by the outer guard.
- slicelength == 1: erases once, decrements to zero, and breaks without touching start.
- Larger slices: updates start exactly when another erase remains.
- slicelength cannot underflow because the loop exits when it reaches zero.
- Mutating slicelength is harmless because it is not used afterward.
- The potentially dangerous final start += step remains eliminated.
It also removes the separate loop counter. The compiler would probably
optimize the former i + 1, ++i mechanics away, but the new source expresses
the real state more directly: "number of erasures remaining."
The unconditional while (true) is safe because entry is strictly guarded by
slicelength > 0, and the decrement guarantees eventual termination.
---------
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2 files changed