diff --git a/src/qcommon/common.cpp b/src/qcommon/common.cpp index 60c844ee..40be3c07 100644 --- a/src/qcommon/common.cpp +++ b/src/qcommon/common.cpp @@ -1135,6 +1135,13 @@ int Z_Size(void *pvAddress) return pMemory->iSize; } +memtag_t Z_Tag(void *pvAddress) +{ + zoneHeader_t *pMemory = ((zoneHeader_t *)pvAddress) - 1; + + return pMemory->eTag; +} + // Frees a block of memory... // @@ -1368,6 +1375,62 @@ const char *CopyString( const char *in, memtag_t eTag ) { return out; } +/* +======================== +StringPool + +Growing pool for allocating immutable C strings in Zone Memory +that avoids too many allocations and fragmentation +======================== +*/ + +typedef struct stringPool_s { + unsigned int size; + unsigned int tail; + struct stringPool_s *next; + char buffer[0]; +} stringPool_t; + +stringPool_t *Z_StringPoolNew(unsigned int size, memtag_t eTag) { + unsigned int size_ = PAD(size, 16); + stringPool_t *chunk = (stringPool_t *)Z_Malloc(offsetof(stringPool_t, buffer) + size_, eTag, qfalse); + + chunk->size = size_; + chunk->tail = 0; + chunk->next = NULL; + + return chunk; +} + +void Z_StringPoolFree(stringPool_t * pool) { + stringPool_t *chunk = pool; + + while (chunk) { + stringPool_t *nextChunk = chunk->next; + Z_Free(chunk); + chunk = nextChunk; + } +} + +const char *Z_StringPoolAdd(stringPool_t * pool, const char * string) { + stringPool_t *chunk = pool; + unsigned int len = strlen(string) + 1; + + while (chunk->size < chunk->tail + len) { + if (!chunk->next) { + unsigned int size = 2 * MAX(len, chunk->size); + memtag_t eTag = Z_Tag(chunk); + chunk->next = Z_StringPoolNew(size, eTag); + } + + chunk = chunk->next; + } + + memcpy(chunk->buffer + chunk->tail, string, len); + chunk->tail += len; + + return chunk->buffer + chunk->tail - len; +} /* ============================================================================== diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index 55110349..0630d748 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -195,13 +195,6 @@ typedef struct fileInPack_s { struct fileInPack_s* next; // next file in the hash } fileInPack_t; -typedef struct stringBuffer_s { - unsigned int size; - unsigned int tail; - struct stringBuffer_s *next; - char buffer[0]; -} stringBuffer_t; - enum { PACKGVC_UNKNOWN = 0, PACKGVC_1_02 = 1, @@ -222,7 +215,7 @@ typedef struct { int hashSize; // hash table size (power of 2) fileInPack_t* *hashTable; // hash table fileInPack_t* buildBuffer; // buffer with the filenames etc. - stringBuffer_t* namesBuffer; // buffer with filenames + stringPool_t* namesBuffer; // buffer with filenames int gvc; // game-version compatibility qboolean isJKA; // jka assets } pack_t; @@ -333,45 +326,6 @@ static inline qboolean FS_CheckHandle(const char *fname, fileHandle_t f, module_ #define FS_CHECKHANDLE(f, module, retval) if (!FS_CheckHandle(__FUNCTION__, f, module)) return retval; -static stringBuffer_t *FS_NewStringBuffer(unsigned int size) { - unsigned int size_ = PAD(size, 16); - stringBuffer_t *buffer = (stringBuffer_t *)Z_Malloc(offsetof(stringBuffer_t, buffer) + size_, TAG_FILESYS, qfalse); - - buffer->size = size_; - buffer->tail = 0; - buffer->next = NULL; - - return buffer; -} - -static void FS_FreeStringBuffer(stringBuffer_t * buffer) { - stringBuffer_t *chunk = buffer; - - while (chunk) { - stringBuffer_t *nextChunk = chunk->next; - Z_Free(chunk); - chunk = nextChunk; - } -} - -static const char *FS_AppendStringBuffer(stringBuffer_t * buffer, const char * string) { - stringBuffer_t *chunk = buffer; - unsigned int len = strlen(string) + 1; - - while (chunk->size < chunk->tail + len) { - if (!chunk->next) { - chunk->next = FS_NewStringBuffer(2 * MAX(len, chunk->size)); - } - - chunk = chunk->next; - } - - memcpy(chunk->buffer + chunk->tail, string, len); - chunk->tail += len; - - return chunk->buffer + chunk->tail - len; -} - /* ============== FS_Initialized @@ -2007,7 +1961,7 @@ of a zip file. static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean assetsJKA ) { fileInPack_t *buildBuffer; - stringBuffer_t *namesBuffer; + stringPool_t *namesBuffer; pack_t *pack; unzFile uf; int err; @@ -2031,7 +1985,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass fs_packFiles += gi.number_entry; buildBuffer = (struct fileInPack_s *)Z_Malloc((int)((gi.number_entry * sizeof(fileInPack_t))), TAG_FILESYS, qtrue); - namesBuffer = FS_NewStringBuffer(gi.number_entry * 16); + namesBuffer = Z_StringPoolNew(gi.number_entry * 16, TAG_FILESYS); fs_headerLongs = (int *)Z_Malloc( gi.number_entry * sizeof(int), TAG_FILESYS, qtrue ); // get the hash table size from the number of files in the zip @@ -2083,7 +2037,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass } Q_strlwr( filename_inzip ); hash = FS_HashFileName(filename_inzip, pack->hashSize); - buildBuffer[i].name = FS_AppendStringBuffer(namesBuffer, filename_inzip); + buildBuffer[i].name = Z_StringPoolAdd(namesBuffer, filename_inzip); // store the file position in the zip buildBuffer[i].pos = unzGetOffset(uf); buildBuffer[i].len = file_info.uncompressed_size; @@ -3182,7 +3136,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass if (!found) { // server has no interest in the file unzClose(pak->handle); - FS_FreeStringBuffer(pak->namesBuffer); + Z_StringPoolFree(pak->namesBuffer); Z_Free(pak->buildBuffer); Z_Free(pak); continue; @@ -3440,7 +3394,7 @@ void FS_Shutdown( qboolean closemfp, qboolean keepModuleFiles ) { if ( p->pack ) { unzClose(p->pack->handle); - FS_FreeStringBuffer( p->pack->namesBuffer ); + Z_StringPoolFree( p->pack->namesBuffer ); Z_Free( p->pack->buildBuffer ); Z_Free( p->pack ); } diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 8fd53666..0a71577c 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -777,6 +777,13 @@ MISC const char *CopyString( const char *in ); const char *CopyString( const char *in, memtag_t eTag ); + +struct stringPool_s; +typedef struct stringPool_s stringPool_t; +stringPool_t *Z_StringPoolNew(unsigned int size, memtag_t eTag); +void Z_StringPoolFree(stringPool_t * pool); +const char *Z_StringPoolAdd(stringPool_t * pool, const char * string); + void Info_Print( const char *s ); void Com_BeginRedirect (char *buffer, size_t buffersize, void (*flush)(char *), qboolean silent);