# UNDF: UNDF-2026-000000991 --- a/sv_main.c +++ b/sv_main.c @@ -1468,12 +1468,21 @@ SV_SoundIndex ================ */ +// Hash lookup for SV_SoundIndex: avoids O(S) linear scan on every sound reference. +#define SV_SOUND_PRECACHE_HASHSIZE 512 +static int sv_sound_precache_hashtable[SV_SOUND_PRECACHE_HASHSIZE]; +static int sv_sound_precache_hashnext[MAX_SOUNDS]; + +static unsigned SV_SoundPrecacheHash(const char *s) +{ + unsigned hash = 0; + for (; *s; s++) + hash = hash * 31 + (unsigned char)*s; + return hash % SV_SOUND_PRECACHE_HASHSIZE; +} + int SV_SoundIndex(const char *s, int precachemode) { - int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP) ? 256 : MAX_SOUNDS); + int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP) ? 256 : MAX_SOUNDS); char filename[MAX_QPATH]; if (!s || !*s) return 0; @@ -1481,7 +1490,12 @@ int SV_SoundIndex(const char *s, int precachemode) // return 0; dp_strlcpy(filename, s, sizeof(filename)); - for (i = 1;i < limit;i++) + // Hash lookup: O(1) average instead of O(S) linear scan. + unsigned h = SV_SoundPrecacheHash(filename); + for (i = sv_sound_precache_hashtable[h]; i >= 0; i = sv_sound_precache_hashnext[i]) + if (!strcmp(sv.sound_precache[i], filename)) + return i; + // Not found: scan for empty slot to insert (precache mode) + for (i = 1;i < limit;i++) { if (!sv.sound_precache[i][0]) { @@ -1503,8 +1517,11 @@ int SV_SoundIndex(const char *s, int precachemode) MSG_WriteString(&sv.reliable_datagram, filename); } + // Insert into hash table + sv_sound_precache_hashnext[i] = sv_sound_precache_hashtable[h]; + sv_sound_precache_hashtable[h] = i; return i; } - if (!strcmp(sv.sound_precache[i], filename)) - return i; } Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);