#13292
Page maps previously allowed a 100% load factor. Once live entries
and tombstones filled every slot, a missing-key lookup or insertion
could scan the entire map.
Reserve 20% of each offset hash map as insertion headroom and track
that budget separately from the live count. Port the allocation-free
in-place rehash from Zig HashMapUnmanaged so canonical insertion can
rebuild fragmented probes and restore tombstone-exhausted headroom
without growing the page. Assumed-capacity insertion now applies the
same guard, preventing the headroom counter from wrapping.
Pass the exact requested hyperlink count into map layout before
load-factor scaling, avoiding a redundant power-of-two rounding step.
Screen-level recovery now grows only when live hyperlinks actually fill
usable capacity.
ReleaseFast terminal benchmarks compare main with the combined map
changes:
| workload | before | after | speedup |
|---|---:|---:|---:|
| map churn | 1.253 s | 12.5 ms | 100x |
| full OSC 8 stream | 3.576 s | 75.6 ms | 47x |
| clear and redraw | 299.1 ms | 118.3 ms | 2.5x |
Co-authored-by: Tim Culverhouse <tim@timculverhouse.com>
It's possible for the hyperlink or string capacity to be exceeded in a
single row, in which case it doesn't matter if we move the row to a new
page, it will still be a problem. This was causing actual crashes under
some circumstances.
Fixes#2500
Based on #2508
This separates out the concept of a "hyperlink" from a "hyperlink page
entry." The difference is that the former has real Zig slices into
things like strings and the latter has offsets into terminal page
memory.
From this separation, the Page structure now has an `insertHyperlink`
function that takes a hyperlink and converts it to a page entry.
This does a couple things: (1) it moves page memory management out of
Screen and into Page which is historically more appropriate and (2) it
let's us more easily test hyperlinks from the Page unit tests.
Finally, this PR makes some error sets explicit.
Fixes#1991
To check if a hyperlink from another page is already present in our
page's set, we need to dupe the hyperlink struct. If the hyperlink is
already present in our page, this dupe is a waste and is freed.
In the case where the hyperlink is present AND we don't have enough
memory to dupe the hyperlink to check if its present, we'd previous
simply crash out and fail rendering. Debug builds would crash with
integrity errors.
This commit resolves the issue by falling back to a slow path when our
string allocation table is full and iterating over the hyperlink map to
check one by one if we have the hyperlink. This O(N) is much slower than
allocating (in this case) but N is usually low on top of this case being
rare.
A better solution would probably be to ensure we always have some % of
available space free in our string allocation table. This would result
in some wasteful page reallocs but would speed up the render loop. We
can look into that later.