https://gitlab.synchro.net/main/sbbs/-/commit/a607bbabdc95b262d2d29c26
Added Files:
src/hash/fnv1a.c fnv1a.h fnv1a_test.c
Modified Files:
.gitignore src/doors/syncconquer/door/soundio_termgfx.cpp src/doors/syncdoom/i_termmusic.c src/doors/syncduke/syncduke_io.c syncduke_stubs.c src/doors/syncmoo1/syncmoo1_audio.c src/doors/syncmoo1/tests/CMakeLists.txt test_audio.c src/doors/termgfx/CMakeLists.txt src/doors/termgfx/test/CMakeLists.txt src/doors/termgfx/text.c src/hash/CMakeLists.txt GNUmakefile objects.mk
Removed Files:
src/doors/termgfx/hash.c hash.h
Log Message:
hash: add FNV-1a, and collapse the doors' six copies onto it
Six sites across the door tree had grown their own 32-bit FNV-1a: the
termgfx text renderer's per-cell glyph signature, termgfx's own hash.c, SyncDOOM's term_hash(), two open-coded loops in SyncDuke, and
SyncConquer's sa_fnv1a(). Four of the six were the same length-taking
function byte-for-byte; one stopped at a NUL instead, and one folded its
fields in one at a time.
Duplication is the lesser problem. These hashes are promises: each one
names a SyncTERM client-cache entry after the bytes it holds, so
identical content has to produce an identical name across sessions,
across hosts and across doors. A constant that drifts in one copy does
not fail loudly, it silently stops hitting the cache - or lands two
unrelated clips on one name.
FNV-1a belongs beside crc16/crc32/md5/sha1/sha256 rather than in the
door tree, so it lands in the hash library as fnv1a32(), a resumable fnv1a32_update() for callers whose input is not one contiguous buffer (SyncDuke's HUD signature folds a line count, then each row, then each
row's text), and fnv1a32_str() for the NUL-terminated case, which the
text renderer calls for every character cell of every frame. The 64-bit
width comes along at the same price: 32 bits is more likely than not to
collide somewhere past about 77,000 keys, which is ample for a door's
handful of music lumps and thin for anything open-ended.
Every replaced call site keeps its exact prior value, so nothing already
in a client's cache is invalidated. The one exception is SyncDuke's HUD signature, which now folds its integers as bytes rather than as whole
words; it is compared only against the previous frame's value inside a
single process, and never stored.
fnv1a_test.c pins the published vectors for both widths, checks that fnv1a32_str() agrees with the strlen() form, and checks that chaining is
exact at every split of a test buffer. `gmake fnv1a_test` runs it, as
does termgfx's opt-in CTest suite; SyncMOO1's test_audio asserts the same 32-bit vectors through its own path.
termgfx compiles the hash library's fnv1a.c directly and re-exports its directory, rather than taking a dependency on the whole library, which
would pull crc/md5/sha and their xpdev link into every door.
Co-Authored-By: Claude Opus 5 (1M context) <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net