sliver_tree/_live_index_cache library
Internal: lazy live-index-in-parent cache backing
TreeController.getIndexInParent.
Pure stamp algebra and storage. The controller owns the refresh loop, because a refresh needs both the raw sibling list (NodeStore) and the pending-deletion flags (AnimationCoordinator), neither of which this component knows anything about. That split is what keeps it standalone-testable.
Validity model
One monotonic generation; a per-PARENT stamp recording the generation
at which that parent's child list was last refreshed (a scalar serves
the root list, which has no nid); and a per-CHILD slot stamp recording
the generation at which that nid's cached index was written. A cached
answer is trusted only when BOTH stamps equal the current generation.
The slot stamp is what makes reads self-protecting: a refresh writes slots only for live members actually in the list, so a key whose parent link and sibling list disagree (a transient mid-mutation state) reads -1, and a recycled nid's previous-life slot is stale by construction because every adopt happens inside a mutator that bumps before the next read.
Invariants
generationstarts at 1 and NEVER rewinds. Zero-filled fresh or regrown stamp slots are therefore stale by construction: no init fill pass exists, ever. A rewound generation meeting a surviving stamp is the only way to manufacture a false-valid slot.resetdrops every array and zeroes the roots stamp; it does not touch the generation (monotonic covers it).- Mutators bump AFTER their last raw-list write and before
notifications (exit placement). Entry-only bumping is unsound: a
user comparator can read
getIndexInParentmid-mutation, and an entry-bumped refresh against a half-mutated list would be trusted after the method returns. With exit placement such a refresh is discarded by the exit bump, so mid-window reads are self-healing. - A NEW raw-sibling-list mutator must add its own exit bump AND join
the mutation script in
live_index_oracle_fuzz_test.dart. That fuzz guards both rules: it interleaves reads with mutations, so a missing or misplaced bump surfaces as a divergence from its independent oracle. A mutator absent from the script is simply unguarded.
Classes
- LiveIndexCache
- Stamp storage for the live-index cache: no tree knowledge and no refresh logic, just the generation algebra described above.
Constants
- kRootListParentNid → const int
- Sentinel parent nid for the root list, which has no nid of its own.