Buffer incoming opcodes and the filtered interdiff opcodes.
Review Request #15202 — Created July 29, 2026 and updated
The existing interdiff filtering algorithm tracks a single pending
opcode to process the next iteration, and yieldsfiltered-equal
opcodes as they're calculated.In preparation for some additional work on the algorithm that will
require opcode backtracking, this change switches to a
DiffOpcodeBuffer, which provides peek, consume, and queue operations
for the opcodes. This replaces the oldpending_opcode, simplifies the
opcode loop, and gives us some look-ahead features we'll be using.
filtered-equalopcodes are no longer yielded as they're calculated.
Instead, they're added to a list, which tracks the original tag for
processing (in the upcoming algorithm changes). When it's time to yield
an opcode, it will first flush the filtered opcodes, turning them into
filtered-equalas they're yielded, and once that's flushed the new
non-filtered opcode will be yielded.At the moment, this doesn't change anything about the processing of
interdiffs. The upcoming changes will take advantage of this to
backtrack and buffer opcodes through some new heuristics.
Unit tests pass.
| Summary | ID |
|---|---|
| 8f967eee7c4fb49d827f164a5f8f5b07ae06140e |
| Description | From | Last Updated |
|---|---|---|
|
This needs to be updated--no longer a one-entry buffer. |
|
|
|
On release-9.x we have a DiffOpcode type alias (in differ.py). Can we port that over to use here? |
|
|
|
I feel like this might be cleaner (and potentially more resilient to future re-queuing changes) if we also make filtered_buffer … |
|
|
|
This is out of date. Perhaps something like "One or more opcodes were queued for re-processing. Take the next one, … |
|
|
|
This is emitting a filtered-equal without buffering it. Is that intentional? According to the description, filtered_buffer is supposed to retain … |
|
|
|
'collections.deque' imported but unused Column: 1 Error code: F401 |
|
-
-
-
-
I feel like this might be cleaner (and potentially more resilient to future re-queuing changes) if we also make
filtered_buffera deque and drain it instead of yielding all and then clearing. That way if there's ever any writes during a flush, we don't silently discard those entries.pending_opcodes: deque[DiffOpcode] = deque() filtered_opcodes: deque[DiffOpcode] = deque() ... def _flush_filtered() -> Iterator[DiffOpcode]: while filtered_opcodes: _tag, i1, i2, i1, i2 = filtered_opcodes.popleft() yield 'filtered-equal', i1, i2, j1, j2That also makes both pending/filtered have the same shape.
-
This is out of date. Perhaps something like "One or more opcodes were queued for re-processing. Take the next one, in order, before pulling anything new from the generator"?
-
This is emitting a filtered-equal without buffering it. Is that intentional?
According to the description,
filtered_bufferis supposed to retain the original tag of filtered opcodes. This one emits directly, losing the original tag, so this opcode is invisible to any future backtracking.If Phase 1 are never candidates for reconsideration, we should have a comment, because otherwise there's a weird asymmetry with Phase 2's "Queue it as a filtered-equal" step.
- Change Summary:
-
Reworked this to use the new
DiffOpcodeBuffer. - Summary:
-
Buffer filtered interdiff opcodes and add a queue of pending opcodes.Buffer incoming opcodes and the filtered interdiff opcodes.
- Description:
-
The existing interdiff filtering algorithm tracks a single pending
opcode to process the next iteration, and yields filtered-equalopcodes as they're calculated. In preparation for some additional work on the algorithm that will
~ require opcode backtracking, this change switches the pending opcodes to ~ a dequeand adds a buffer for filtered opcodes.~ ~ The
pending_opcodesqueue may contain zero or more opcodes to process.~ require opcode backtracking, this change switches to a ~ DiffOpcodeBuffer, which provides peek, consume, and queue operations~ for the opcodes. This replaces the old pending_opcode, simplifies the~ opcode loop, and gives us some look-ahead features we'll be using. - If populated, they will always be used over pulling from the provided - opcodes generator. While in the current algorithm this will only ever - have a max of one, the upcoming changes will re-queue opcodes for - processing at times. filtered-equalopcodes are no longer yielded as they're calculated.~ Instead, they're added to a buffer, which tracks the original tag for ~ Instead, they're added to a list, which tracks the original tag for processing (in the upcoming algorithm changes). When it's time to yield ~ an opcode, it will first yield anything in the buffer, turning them into ~ filtered-equalopcodes as they're yielded.~ an opcode, it will first flush the filtered opcodes, turning them into ~ filtered-equalas they're yielded, and once that's flushed the new+ non-filtered opcode will be yielded. At the moment, this doesn't change anything about the processing of
interdiffs. The upcoming changes will take advantage of this to backtrack and buffer opcodes through some new heuristics. - Commits:
-
Summary ID 38f55153a34169f7598ed6d3ec4873f4d983406e 3956148e2ac06cb8f7f37a2c9779abfc5b2f2fb9 - Depends On:
-
- Diff:
Revision 2 (+74 -66)
- Change Summary:
-
- Removed an unused import.
- Changed an immediate
filtered-equalyield to a buffer.
- Commits:
-
Summary ID 3956148e2ac06cb8f7f37a2c9779abfc5b2f2fb9 8f967eee7c4fb49d827f164a5f8f5b07ae06140e - Diff:
-
Revision 3 (+80 -74)