Make the container hash table a total order - #168
Open
jerrytron wants to merge 2 commits into
Open
Conversation
container_hash_t compared on the hash alone, and binary_emitter sorts that table with std::sort, which is not stable. Two entries sharing a hash could come out in either order depending on the standard library, so the same story compiled to different bytes under libstdc++ than under libc++ - which makes comparing output between builds useless as a correctness check. It is not only cosmetic. story_impl.cpp's upper_bound() returns the last entry whose key is <= the target, so when entries share a hash the runtime resolves the path to whichever one the sort happened to leave last. The ties are common and are not hash collisions between different paths: build_container_hash_map() recurses into indexed children carrying the parent's name unchanged, so one path string is emitted once per indexed child at a different offset. One story measured here has 164 entries under 128 distinct hashes, and all 26 collisions are a repeated path. Tie-breaking on the offset makes the order total, so every toolchain agrees. key() still returns the hash alone, because the runtime's binary search looks up by hash and must keep matching every entry in a run. Whether the highest-offset entry is the RIGHT container for a repeated path is a separate question this does not answer; it only makes the answer the same everywhere. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Owner
|
Good spot; I changed it to references to avoid future |
The body fits on one line under the project's .clang-format, so the format job wants it there. Produced with clang-format rather than by hand; no behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
container_hash_tcompares on the hash alone, andbinary_emittersorts that table withstd::sort, which is not stable. Two entries sharing a hash can come out in either order depending on the standard library — so the same story compiles to different bytes under libstdc++ than under libc++, which makes comparing compiler output between builds useless as a correctness check.It is not only cosmetic.
story_impl.cpp'supper_bound()returns the last entry whose key is<=the target, so when entries share a hash the runtime resolves the path to whichever one the sort happened to leave last.The ties are common, and are not hash collisions
build_container_hash_map()recurses into indexed children carrying the parent's name unchanged, so one path string is emitted once per indexed child at a different offset. One story measured here has 164 entries under 128 distinct hashes, and all 26 collisions are a repeated path rather than two different paths colliding.This change
Tie-break on the offset, making the order total, so every toolchain agrees.
key()still returns the hash alone, because the runtime's binary search looks up by hash and must keep matching every entry in a run.Whether the highest-offset entry is the right container for a repeated path is a separate question this does not try to answer — it only makes the answer the same everywhere. After this, a story compiled by three different toolchains produced identical bytes; before, it did not.
ctestpasses.