w_wad: replace unordered_map with verstable hashmap for lumpnumcache + convert back to C from C++

Thanks Alug! 014a22e933
This commit is contained in:
NepDisk 2026-02-24 11:10:28 -05:00
parent 7ec95f7d96
commit 569404dfe1
6 changed files with 2189 additions and 51 deletions

View file

@ -1667,6 +1667,10 @@ freely, subject to the following restrictions:
- stb_vorbis + stb_rect_pack
Copyright (c) 2017 Sean Barrett
https://github.com/nothings/stb
- Verstable
Copyright (c) 2026 Jackson Allan
https://github.com/JacksonAllan/Verstable
--------------------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining a copy

View file

@ -94,7 +94,7 @@ add_executable(BLANKART MACOSX_BUNDLE WIN32
v_video.c
s_sound.c
sounds.c
w_wad.cpp
w_wad.c
filesrch.c
mserv.c
http-mserv.c

View file

@ -1370,6 +1370,7 @@ static void I_Fork(void)
INT32 I_StartupSystem(void)
{
int SDLlinked = SDL_GetVersion();
W_Startup();
I_StartupConsole();
#ifdef NEWSIGNALHANDLER
// This is useful when debugging. It lets GDB attach to

2119
src/verstable.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -90,34 +90,29 @@ typedef struct
#define LUMPNUMCACHESIZE 2048 // should be reasonable ig
#define LUMPNUMCACHENAME 32
#include <unordered_map>
#include <string>
#include <cstring>
#define NAME lumpnum_map
#define KEY_TY char *
#define KEY_GET_CONST
#define VAL_TY lumpnum_t
#define HASH_FN vt_hash_string
#define CMPR_FN vt_cmpr_string
#define KEY_DTOR_FN free
#include "verstable.h"
struct LumpnumNameHash
{
std::size_t operator()(const std::string& str) const
{
// hopefully this is fast enough but should be
return static_cast<std::size_t>(HASH32(str.c_str(), str.length()));
}
};
#define NAME folder_map
#define KEY_TY char *
#define KEY_GET_CONST
#define VAL_TY UINT16
#define HASH_FN vt_hash_string
#define CMPR_FN vt_cmpr_string
#define KEY_DTOR_FN free
#include "verstable.h"
struct LumpnumStringEquals
{
bool operator()(const std::string& str1, const std::string& str2) const
{
//return fastcmp(str1.c_str(), str2.c_str());
return str1 == str2;
}
};
static lumpnum_map lumpnumcache;
static std::unordered_map<std::string, lumpnum_t, LumpnumNameHash, LumpnumStringEquals> lumpnumcache(LUMPNUMCACHESIZE);
// gotta wrap this in a struct due to external C linkage
struct FolderCache {
std::unordered_map<std::string, UINT16, LumpnumNameHash, LumpnumStringEquals> map;
};
typedef struct FolderCache {
folder_map map;
} FolderCache;
//===========================================================================
// GLOBALS
@ -132,6 +127,8 @@ wadfile_t *wadfiles[MAX_WADFILES]; // 0 to numwadfiles-1 are valid
// being ejected
void W_Shutdown(void)
{
lumpnum_map_cleanup(&lumpnumcache);
while (numwadfiles--)
{
wadfile_t *wad = wadfiles[numwadfiles];
@ -147,14 +144,24 @@ void W_Shutdown(void)
}
}
delete wad->startfolders;
delete wad->endfolders;
folder_map_cleanup(&wad->startfolders->map);
free(wad->startfolders);
folder_map_cleanup(&wad->endfolders->map);
free(wad->endfolders);
Z_Free(wad->lumpinfo);
Z_Free(wad);
}
}
// the lumpnum cache needs to be initialized before use
// call this as early as possible!
void W_Startup(void)
{
lumpnum_map_init(&lumpnumcache);
lumpnum_map_reserve(&lumpnumcache, LUMPNUMCACHESIZE);
}
//===========================================================================
// LUMP BASED ROUTINES
//===========================================================================
@ -457,7 +464,7 @@ boolean W_MakeFileHash(const char *filename, boolean openwad, UINT64 *ret)
// Invalidates the cache of lump numbers. Call this whenever a wad is added.
FUNCINLINE static ATTRINLINE void W_InvalidateLumpnumCache(void)
{
lumpnumcache.clear();
lumpnum_map_clear(&lumpnumcache);
}
FUNCINLINE static ATTRINLINE UINT32 W_HashLumpName(const char *name, size_t len)
@ -656,7 +663,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
namelen = strlen(trimname);
// Allocate the lump's long and full name (save on memory).
lump_p->longname = lump_p->fullname = static_cast<char*>(Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL));
lump_p->longname = lump_p->fullname = (char*)Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->longname, trimname, namelen);
lump_p->longname[namelen-1] = '\0';
lump_p->hash.longname = lump_p->hash.fullname = W_HashLumpName(lump_p->longname, strlen(lump_p->longname));
@ -785,7 +792,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
// Look for central directory end signature near end of file.
// Contains entry number (number of lumps), and central directory start offset.
fseek(handle, 0, SEEK_END);
if (!ResFindSignature(handle, pat_end, std::max<long>(0, ftell(handle) - (22 + 65536))))
if (!ResFindSignature(handle, pat_end, (long)max(0, ftell(handle) - (22 + 65536))))
{
CONS_Alert(CONS_ERROR, "Missing central directory\n");
return NULL;
@ -844,7 +851,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
dotpos = fullname + strlen(fullname); // Watch for files without extension.
memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
strncpy(lump_p->name, trimname, std::min<size_t>(8, dotpos - trimname));
strncpy(lump_p->name, trimname, (size_t)min(8, dotpos - trimname));
lump_p->namelength = strlen(lump_p->name);
lump_p->hash.name = W_HashLumpName(lump_p->name, lump_p->namelength);
@ -1049,8 +1056,10 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, boole
fseek(handle, 0, SEEK_END);
wadfile->filesize = (unsigned)ftell(handle);
wadfile->type = type;
wadfile->startfolders = new FolderCache();
wadfile->endfolders = new FolderCache();
wadfile->startfolders = (FolderCache *)malloc(sizeof(FolderCache));
folder_map_init(&wadfile->startfolders->map);
wadfile->endfolders = (FolderCache *)malloc(sizeof(FolderCache));
folder_map_init(&wadfile->endfolders->map);
// already generated, just copy it over
wadfile->hash = filehash;
@ -1391,9 +1400,9 @@ UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlum
size_t namelen;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
auto it = wadfiles[wad]->startfolders->map.find(name);
if (it != wadfiles[wad]->startfolders->map.end())
return it->second;
folder_map_itr it = folder_map_get(&wadfiles[wad]->startfolders->map, name);
if (!folder_map_is_end(it))
return it.data->val;
namelen = strlen(name);
@ -1405,12 +1414,12 @@ UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlum
if (lump_p->fullnamelength == namelen)
i++;
wadfiles[wad]->startfolders->map[name] = i;
folder_map_insert(&wadfiles[wad]->startfolders->map, strdup(name), i);
return i;
}
}
wadfiles[wad]->startfolders->map[name] = INT16_MAX;
folder_map_insert(&wadfiles[wad]->startfolders->map, strdup(name), INT16_MAX);
return INT16_MAX;
}
@ -1423,9 +1432,9 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
size_t namelen;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
auto it = wadfiles[wad]->endfolders->map.find(name);
if (it != wadfiles[wad]->endfolders->map.end())
return it->second;
folder_map_itr it = folder_map_get(&wadfiles[wad]->endfolders->map, name);
if (!folder_map_is_end(it))
return it.data->val;
namelen = strlen(name);
@ -1435,7 +1444,7 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
break;
}
wadfiles[wad]->endfolders->map[name] = i;
folder_map_insert(&wadfiles[wad]->endfolders->map, strdup(name), i);
return i;
}
@ -1458,16 +1467,16 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
FUNCINLINE static ATTRINLINE lumpnum_t CheckLumpInCache(const char *name)
{
auto it = lumpnumcache.find(name);
if (it != lumpnumcache.end())
return it->second;
lumpnum_map_itr it = lumpnum_map_get(&lumpnumcache, name);
if (!lumpnum_map_is_end(it))
return it.data->val;
return LUMPERROR;
}
FUNCINLINE static ATTRINLINE void AddLumpToCache(lumpnum_t lumpnum, const char *name)
{
lumpnumcache.emplace(name, lumpnum);
lumpnum_map_insert(&lumpnumcache, strdup(name), lumpnum);
}
//
@ -1498,12 +1507,16 @@ lumpnum_t W_CheckNumForName(const char *name)
break; //found it
}
if (check == INT16_MAX) return LUMPERROR;
if (check == INT16_MAX)
{
return LUMPERROR;
}
else
{
// Update the cache.
lumpnum_t lumpnum = (i << 16) | check;
lumpnumcache.insert({name, lumpnum});
AddLumpToCache(lumpnum, name);
return lumpnum;
}
}
@ -2461,7 +2474,7 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status)
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
if (!ResFindSignature(fp, pat_end, std::max<long>(0, ftell(fp) - (22 + 65536))))
if (!ResFindSignature(fp, pat_end, (long)max(0, ftell(fp) - (22 + 65536))))
return true;
fseek(fp, -4, SEEK_CUR);
@ -2502,7 +2515,7 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status)
dotpos = fullname + strlen(fullname); // Watch for files without extension.
memset(lumpname, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
strncpy(lumpname, trimname,std::min<size_t>(8, dotpos - trimname));
strncpy(lumpname, trimname,(size_t)min(8, dotpos - trimname));
if (! W_VerifyName(lumpname, checklist, status))
verified = false;

View file

@ -152,6 +152,7 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
// =========================================================================
void W_Startup(void);
void W_Shutdown(void);
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened