Use case insensitive string hashing and compare for cvar hashtable + compatnetid support

Based on this commit 27f22e4b5b
This commit is contained in:
NepDisk 2026-04-27 18:24:38 -04:00
parent 9d2b6eda55
commit 0867eff8b0
3 changed files with 92 additions and 55 deletions

View file

@ -1443,11 +1443,20 @@ void VS_Print(vsbuf_t *buf, const char *data)
//
// =========================================================================
static UINT32 xxHashString32(const char *name)
{
size_t len = strlen(name);
char *uname = (char *)alloca(len + 1);
strlcpy(uname, name, len + 1);
strlwr(uname);
return HASH32(uname, len);
}
#define NAME cvar_map_t
#define KEY_TY const char *
#define VAL_TY consvar_t *
#define HASH_FN vt_hash_string
#define CMPR_FN vt_cmpr_string
#define HASH_FN xxHashString32
#define CMPR_FN vt_cmpr_casestring
#include "verstable.h"
#define NAME netvar_map_t
@ -1457,8 +1466,16 @@ void VS_Print(vsbuf_t *buf, const char *data)
#define CMPR_FN vt_cmpr_integer
#include "verstable.h"
#define NAME compatnetvar_map_t
#define KEY_TY UINT16
#define VAL_TY consvar_t *
#define HASH_FN vt_hash_integer
#define CMPR_FN vt_cmpr_integer
#include "verstable.h"
static cvar_map_t cvar_map;
static netvar_map_t netvar_map;
static compatnetvar_map_t compatnetvar_map;
CONSTRUCTOR static void CV_InitMap(void)
{
@ -1468,12 +1485,16 @@ CONSTRUCTOR static void CV_InitMap(void)
netvar_map_t_init(&netvar_map);
netvar_map_t_reserve(&netvar_map, 256);
compatnetvar_map_t_init(&compatnetvar_map);
compatnetvar_map_t_reserve(&compatnetvar_map, 256);
}
DESTRUCTOR static void CV_DestroyMap(void)
{
cvar_map_t_cleanup(&cvar_map);
netvar_map_t_cleanup(&netvar_map);
compatnetvar_map_t_cleanup(&compatnetvar_map);
}
static const char *cv_null_string = "";
@ -1545,11 +1566,17 @@ static consvar_t *CV_FindNetVar(UINT16 netid)
consvar_t *CV_FindLegacyNetVar(UINT16 netid)
{
compatnetvar_map_t_itr it = compatnetvar_map_t_get(&compatnetvar_map, netid);
if (!compatnetvar_map_t_is_end(it))
return it.data->val;
/*
consvar_t *cvar;
for (cvar = consvar_vars; cvar; cvar = cvar->next)
if (cvar->compatnetid == netid)
return cvar;
*/
if (netid == 44542) // ouch this hack
return &cv_karteliminatelast;
@ -1634,6 +1661,8 @@ void CV_RegisterVar(consvar_t *variable)
if (variable->flags & CV_NETVAR)
netvar_map_t_insert(&netvar_map, variable->netid, variable);
if (variable->compatnetid)
compatnetvar_map_t_insert(&compatnetvar_map, variable->compatnetid, variable);
}
/** Finds the string value of a console variable.

View file

@ -441,12 +441,12 @@ License (MIT):
#ifdef __GNUC__
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) // >= GCC 3.1
#define FORCEINLINE __attribute__((always_inline))
#define FORCE_INLINE __attribute__((always_inline))
#else
#define FORCEINLINE
#define FORCE_INLINE
#endif
#else
#define FORCEINLINE
#define FORCE_INLINE
#endif
#ifndef VERSTABLE_H
@ -462,6 +462,8 @@ License (MIT):
#include <stdbool.h>
#include <string.h>
#include "fastcmp.h"
// Two-way concatenation macro.
#define VT_CAT_( a, b ) a##b
#define VT_CAT( a, b ) VT_CAT_( a, b )
@ -485,7 +487,7 @@ License (MIT):
// Extracts a hash fragment from a uint64_t hash code.
// We take the highest four bits so that keys that map (via modulo) to the same bucket have distinct hash fragments.
static inline FORCEINLINE uint16_t vt_hashfrag( uint64_t hash )
static inline FORCE_INLINE uint16_t vt_hashfrag( uint64_t hash )
{
return ( hash >> 48 ) & VT_HASH_FRAG_MASK;
}
@ -493,7 +495,7 @@ static inline FORCEINLINE uint16_t vt_hashfrag( uint64_t hash )
// Standard quadratic probing formula that guarantees that all buckets are visited when the bucket count is a power of
// two (at least in theory, because the displacement limit could terminate the search early when the bucket count is
// high).
static inline FORCEINLINE size_t vt_quadratic( uint16_t displacement )
static inline FORCE_INLINE size_t vt_quadratic( uint16_t displacement )
{
return ( (size_t)displacement * displacement + displacement ) / 2;
}
@ -506,7 +508,7 @@ static inline FORCEINLINE size_t vt_quadratic( uint16_t displacement )
#if defined( __GNUC__ ) && ULLONG_MAX == 0xFFFFFFFFFFFFFFFF
static inline FORCEINLINE int vt_first_nonzero_uint16( uint64_t val )
static inline FORCE_INLINE int vt_first_nonzero_uint16( uint64_t val )
{
const uint16_t endian_checker = 0x0001;
if( *(const char *)&endian_checker ) // Little-endian (the compiler will optimize away the check at -O1 and above).
@ -521,7 +523,7 @@ static inline FORCEINLINE int vt_first_nonzero_uint16( uint64_t val )
#pragma intrinsic(_BitScanForward64)
#pragma intrinsic(_BitScanReverse64)
static inline FORCEINLINE int vt_first_nonzero_uint16( uint64_t val )
static inline FORCE_INLINE int vt_first_nonzero_uint16( uint64_t val )
{
unsigned long result;
@ -539,7 +541,7 @@ static inline FORCEINLINE int vt_first_nonzero_uint16( uint64_t val )
#else
static inline FORCEINLINE int vt_first_nonzero_uint16( uint64_t val )
static inline FORCE_INLINE int vt_first_nonzero_uint16( uint64_t val )
{
int result = 0;
@ -567,7 +569,7 @@ static const uint16_t vt_empty_placeholder_metadatum = VT_EMPTY;
// Fast-hash, as described by https://jonkagstrom.com/bit-mixer-construction and
// https://code.google.com/archive/p/fast-hash.
// In testing, this hash function provided slightly better performance than the Murmur3 mixer.
static inline FORCEINLINE uint64_t vt_hash_integer( uint64_t key )
static inline FORCE_INLINE uint64_t vt_hash_integer( uint64_t key )
{
key ^= key >> 23;
key *= 0x2127599bf4325c37ull;
@ -581,7 +583,7 @@ static inline FORCEINLINE uint64_t vt_hash_integer( uint64_t key )
// * We do not handle endianness, so the result will differ depending on the platform.
// * We omit the code optimized for 32-bit platforms.
static inline FORCEINLINE void vt_wymum( uint64_t *a, uint64_t *b )
static inline FORCE_INLINE void vt_wymum( uint64_t *a, uint64_t *b )
{
#if defined( __SIZEOF_INT128__ )
__uint128_t r = *a;
@ -609,32 +611,32 @@ static inline FORCEINLINE void vt_wymum( uint64_t *a, uint64_t *b )
#endif
}
static inline FORCEINLINE uint64_t vt_wymix( uint64_t a, uint64_t b )
static inline FORCE_INLINE uint64_t vt_wymix( uint64_t a, uint64_t b )
{
vt_wymum( &a, &b );
return a ^ b;
}
static inline FORCEINLINE uint64_t vt_wyr8( const unsigned char *p )
static inline FORCE_INLINE uint64_t vt_wyr8( const unsigned char *p )
{
uint64_t v;
memcpy( &v, p, 8 );
return v;
}
static inline FORCEINLINE uint64_t vt_wyr4( const unsigned char *p )
static inline FORCE_INLINE uint64_t vt_wyr4( const unsigned char *p )
{
uint32_t v;
memcpy( &v, p, 4 );
return v;
}
static inline FORCEINLINE uint64_t vt_wyr3( const unsigned char *p, size_t k )
static inline FORCE_INLINE uint64_t vt_wyr3( const unsigned char *p, size_t k )
{
return ( ( (uint64_t)p[ 0 ] ) << 16 ) | ( ( (uint64_t)p[ k >> 1 ] ) << 8 ) | p[ k - 1 ];
}
static inline FORCEINLINE size_t vt_wyhash( const void *key, size_t len )
static inline FORCE_INLINE size_t vt_wyhash( const void *key, size_t len )
{
const unsigned char *p = (const unsigned char *)key;
uint64_t seed = 0xca813bf4c7abf0a9ull;
@ -693,41 +695,46 @@ static inline FORCEINLINE size_t vt_wyhash( const void *key, size_t len )
return (size_t)vt_wymix( a ^ 0x2d358dccaa6c78a5ull ^ len, b ^ 0x8bb84b93962eacc9ull );
}
static inline FORCEINLINE uint64_t vt_hash_string( const char *key )
static inline FORCE_INLINE uint64_t vt_hash_string( const char *key )
{
return vt_wyhash( key, strlen( key ) );
}
static inline FORCEINLINE bool vt_cmpr_integer( uint64_t key_1, uint64_t key_2 )
static inline FORCE_INLINE bool vt_cmpr_integer( uint64_t key_1, uint64_t key_2 )
{
return key_1 == key_2;
}
static inline FORCEINLINE bool vt_cmpr_string( const char *key_1, const char *key_2 )
static inline FORCE_INLINE bool vt_cmpr_string( const char *key_1, const char *key_2 )
{
return strcmp( key_1, key_2 ) == 0;
return fastcmp( key_1, key_2 );
}
static inline FORCE_INLINE bool vt_cmpr_casestring( const char *key_1, const char *key_2 )
{
return fasticmp( key_1, key_2 );
}
// Default allocation and free functions.
static inline FORCEINLINE void *vt_malloc( size_t size )
static inline FORCE_INLINE void *vt_malloc( size_t size )
{
return malloc( size );
}
static inline FORCEINLINE void vt_free( void *ptr, size_t size )
static inline FORCE_INLINE void vt_free( void *ptr, size_t size )
{
(void)size;
free( ptr );
}
static inline FORCEINLINE void *vt_malloc_with_ctx( size_t size, void *ctx )
static inline FORCE_INLINE void *vt_malloc_with_ctx( size_t size, void *ctx )
{
(void)ctx;
return malloc( size );
}
static inline FORCEINLINE void vt_free_with_ctx( void *ptr, size_t size, void *ctx )
static inline FORCE_INLINE void vt_free_with_ctx( void *ptr, size_t size, void *ctx )
{
(void)size;
(void)ctx;
@ -894,7 +901,7 @@ typedef struct
#if defined( HEADER_MODE ) || defined( IMPLEMENTATION_MODE )
#define VT_API_FN_QUALIFIERS
#else
#define VT_API_FN_QUALIFIERS static inline FORCEINLINE
#define VT_API_FN_QUALIFIERS static inline FORCE_INLINE
#endif
#ifndef IMPLEMENTATION_MODE
@ -966,7 +973,7 @@ VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw ) ( NAME *, VT_CAT( NAME,
// This function must be inlined to ensure that the compiler optimizes away the NAME_fast_forward call if the returned
// iterator is discarded.
#ifdef __GNUC__
static inline FORCEINLINE
static inline FORCE_INLINE
#elif defined( _MSC_VER )
static __forceinline
#else
@ -1083,7 +1090,7 @@ VT_API_FN_QUALIFIERS void VT_CAT( NAME, _init )(
// This function returns the offset of the beginning of the metadata, i.e. the size of the buckets array plus the
// (usually zero) padding.
// It assumes that the bucket count is not zero.
static inline FORCEINLINE size_t VT_CAT( NAME, _metadata_offset )( NAME *table )
static inline FORCE_INLINE size_t VT_CAT( NAME, _metadata_offset )( NAME *table )
{
// Use sizeof, rather than alignof, for C99 compatibility.
return ( ( ( table->buckets_mask + 1 ) * sizeof( VT_CAT( NAME, _bucket ) ) + sizeof( uint16_t ) - 1 ) /
@ -1092,7 +1099,7 @@ static inline FORCEINLINE size_t VT_CAT( NAME, _metadata_offset )( NAME *table )
// Returns the total allocation size, including the buckets array, padding, metadata, and excess metadata.
// As above, this function assumes that the bucket count is not zero.
static inline FORCEINLINE size_t VT_CAT( NAME, _total_alloc_size )( NAME *table )
static inline FORCE_INLINE size_t VT_CAT( NAME, _total_alloc_size )( NAME *table )
{
return VT_CAT( NAME, _metadata_offset )( table ) + ( table->buckets_mask + 1 + 4 ) * sizeof( uint16_t );
}
@ -1163,7 +1170,7 @@ VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _is_end )( VT_CAT( NAME, _itr ) itr )
// other chains might have freed up buckets that could fall in this chain before the final key.
// Returns true if an empty bucket within the range of the displacement limit was found, in which case the final two
// pointer arguments contain the index of the empty bucket and its quadratic displacement from home_bucket.
static inline FORCEINLINE bool VT_CAT( NAME, _find_first_empty )(
static inline FORCE_INLINE bool VT_CAT( NAME, _find_first_empty )(
NAME *table,
size_t home_bucket,
size_t *empty,
@ -1190,7 +1197,7 @@ static inline FORCEINLINE bool VT_CAT( NAME, _find_first_empty )(
// quadratic displacement and returns the index of the bucket containing that key.
// Although the new key could simply be linked to the end of the chain, keeping the chain ordered by displacement
// theoretically improves cache locality during lookups.
static inline FORCEINLINE size_t VT_CAT( NAME, _find_insert_location_in_chain )(
static inline FORCE_INLINE size_t VT_CAT( NAME, _find_insert_location_in_chain )(
NAME *table,
size_t home_bucket,
uint16_t displacement_to_empty
@ -1219,7 +1226,7 @@ static inline FORCEINLINE size_t VT_CAT( NAME, _find_insert_location_in_chain )(
// * Re-linking the key to the chain.
// Returns true if the eviction succeeded, or false if no empty bucket to which to evict the occupying key could be
// found within the displacement limit.
static inline FORCEINLINE bool VT_CAT( NAME, _evict )( NAME *table, size_t bucket )
static inline FORCE_INLINE bool VT_CAT( NAME, _evict )( NAME *table, size_t bucket )
{
// Find the previous key in chain.
size_t home_bucket = HASH_FN( table->buckets[ bucket ].key ) & table->buckets_mask;
@ -1261,7 +1268,7 @@ static inline FORCEINLINE bool VT_CAT( NAME, _evict )( NAME *table, size_t bucke
// Returns an end iterator, i.e. any iterator for which .metadatum == .metadata_end.
// This function just cleans up the library code in functions that return an end iterator as a failure indicator.
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _end_itr )( void )
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _end_itr )( void )
{
VT_CAT( NAME, _itr ) itr = { NULL, NULL, NULL, 0 };
return itr;
@ -1282,7 +1289,7 @@ static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _end_itr )( void )
// inserted because of the maximum load factor or displacement limit constraints.
// If replace is false, then the return value is as described above, except that if the key already exists, the function
// returns an iterator to the existing key.
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert_raw )(
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert_raw )(
NAME *table,
KEY_TY key,
#ifdef VAL_TY
@ -1415,7 +1422,7 @@ static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert_raw )(
// In testing, the no-inline approach showed a performance benefit when inserting existing keys (i.e. replacing).
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes" // Silence warning about combining noinline with static inline FORCEINLINE.
#pragma GCC diagnostic ignored "-Wattributes" // Silence warning about combining noinline with static inline FORCE_INLINE.
__attribute__((noinline)) static inline
#elif defined( _MSC_VER )
__declspec(noinline) static inline
@ -1738,7 +1745,7 @@ VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase )( NAME *table, KEY_TY key )
// Finds the first occupied bucket at or after the bucket pointed to by itr.
// This function scans four buckets at a time, ideally using intrinsics.
static inline FORCEINLINE void VT_CAT( NAME, _fast_forward )( VT_CAT( NAME, _itr ) *itr )
static inline FORCE_INLINE void VT_CAT( NAME, _fast_forward )( VT_CAT( NAME, _itr ) *itr )
{
while( true )
{
@ -1768,7 +1775,7 @@ VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _next )( VT_CAT( NAME, _
// Returns the minimum bucket count required to accommodate a certain number of keys, which is governed by the maximum
// load factor.
static inline FORCEINLINE size_t VT_CAT( NAME, _min_bucket_count_for_size )( size_t size )
static inline FORCE_INLINE size_t VT_CAT( NAME, _min_bucket_count_for_size )( size_t size )
{
if( size == 0 )
return 0;
@ -1893,7 +1900,7 @@ VT_API_FN_QUALIFIERS void VT_CAT( NAME, _cleanup )( NAME *table )
typedef NAME VT_CAT( vt_table_, VT_TEMPLATE_COUNT );
typedef VT_CAT( NAME, _itr ) VT_CAT( vt_table_itr_, VT_TEMPLATE_COUNT );
static inline FORCEINLINE void VT_CAT( vt_init_, VT_TEMPLATE_COUNT )(
static inline FORCE_INLINE void VT_CAT( vt_init_, VT_TEMPLATE_COUNT )(
NAME *table
#ifdef CTX_TY
, CTX_TY ctx
@ -1908,7 +1915,7 @@ static inline FORCEINLINE void VT_CAT( vt_init_, VT_TEMPLATE_COUNT )(
);
}
static inline FORCEINLINE bool VT_CAT( vt_init_clone_, VT_TEMPLATE_COUNT )(
static inline FORCE_INLINE bool VT_CAT( vt_init_clone_, VT_TEMPLATE_COUNT )(
NAME *table,
const NAME* source
#ifdef CTX_TY
@ -1925,22 +1932,22 @@ static inline FORCEINLINE bool VT_CAT( vt_init_clone_, VT_TEMPLATE_COUNT )(
);
}
static inline FORCEINLINE size_t VT_CAT( vt_size_, VT_TEMPLATE_COUNT )( const NAME *table )
static inline FORCE_INLINE size_t VT_CAT( vt_size_, VT_TEMPLATE_COUNT )( const NAME *table )
{
return VT_CAT( NAME, _size )( table );
}
static inline FORCEINLINE size_t VT_CAT( vt_bucket_count_, VT_TEMPLATE_COUNT )( const NAME *table )
static inline FORCE_INLINE size_t VT_CAT( vt_bucket_count_, VT_TEMPLATE_COUNT )( const NAME *table )
{
return VT_CAT( NAME, _bucket_count )( table );
}
static inline FORCEINLINE bool VT_CAT( vt_is_end_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
static inline FORCE_INLINE bool VT_CAT( vt_is_end_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
{
return VT_CAT( NAME, _is_end )( itr );
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_insert_, VT_TEMPLATE_COUNT )(
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_insert_, VT_TEMPLATE_COUNT )(
NAME *table,
KEY_TY key
#ifdef VAL_TY
@ -1957,7 +1964,7 @@ static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_insert_, VT_TEMPLATE_C
);
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_get_or_insert_, VT_TEMPLATE_COUNT )(
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_get_or_insert_, VT_TEMPLATE_COUNT )(
NAME *table,
KEY_TY key
#ifdef VAL_TY
@ -1974,47 +1981,47 @@ static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_get_or_insert_, VT_TEM
);
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_get_, VT_TEMPLATE_COUNT )( const NAME *table, KEY_TY key )
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_get_, VT_TEMPLATE_COUNT )( const NAME *table, KEY_TY key )
{
return VT_CAT( NAME, _get )( table, key );
}
static inline FORCEINLINE bool VT_CAT( vt_erase_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key )
static inline FORCE_INLINE bool VT_CAT( vt_erase_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key )
{
return VT_CAT( NAME, _erase )( table, key );
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_next_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_next_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
{
return VT_CAT( NAME, _next )( itr );
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_erase_itr_, VT_TEMPLATE_COUNT )( NAME *table, VT_CAT( NAME, _itr ) itr )
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_erase_itr_, VT_TEMPLATE_COUNT )( NAME *table, VT_CAT( NAME, _itr ) itr )
{
return VT_CAT( NAME, _erase_itr )( table, itr );
}
static inline FORCEINLINE bool VT_CAT( vt_reserve_, VT_TEMPLATE_COUNT )( NAME *table, size_t bucket_count )
static inline FORCE_INLINE bool VT_CAT( vt_reserve_, VT_TEMPLATE_COUNT )( NAME *table, size_t bucket_count )
{
return VT_CAT( NAME, _reserve )( table, bucket_count );
}
static inline FORCEINLINE bool VT_CAT( vt_shrink_, VT_TEMPLATE_COUNT )( NAME *table )
static inline FORCE_INLINE bool VT_CAT( vt_shrink_, VT_TEMPLATE_COUNT )( NAME *table )
{
return VT_CAT( NAME, _shrink )( table );
}
static inline FORCEINLINE VT_CAT( NAME, _itr ) VT_CAT( vt_first_, VT_TEMPLATE_COUNT )( const NAME *table )
static inline FORCE_INLINE VT_CAT( NAME, _itr ) VT_CAT( vt_first_, VT_TEMPLATE_COUNT )( const NAME *table )
{
return VT_CAT( NAME, _first )( table );
}
static inline FORCEINLINE void VT_CAT( vt_clear_, VT_TEMPLATE_COUNT )( NAME *table )
static inline FORCE_INLINE void VT_CAT( vt_clear_, VT_TEMPLATE_COUNT )( NAME *table )
{
VT_CAT( NAME, _clear )( table );
}
static inline FORCEINLINE void VT_CAT( vt_cleanup_, VT_TEMPLATE_COUNT )( NAME *table )
static inline FORCE_INLINE void VT_CAT( vt_cleanup_, VT_TEMPLATE_COUNT )( NAME *table )
{
VT_CAT( NAME, _cleanup )( table );
}
@ -2116,4 +2123,4 @@ C99 prefixed function API to circumvent this restriction.
#undef IMPLEMENTATION_MODE
#undef VT_API_FN_QUALIFIERS
#undef FORCEINLINE
#undef FORCE_INLINE

View file

@ -466,7 +466,8 @@ FUNCINLINE static ATTRINLINE void W_InvalidateLumpnumCache(void)
lumpnum_map_clear(&lumpnumcache);
}
FUNCINLINE static ATTRINLINE UINT32 W_HashLumpName(const char *name, size_t len)
// This is unfornately duped in command.c since I want this inlined...
FUNCINLINE ATTRINLINE UINT32 W_HashLumpName(const char *name, size_t len)
{
char *uname = (char *)alloca(len + 1);
strlcpy(uname, name, len + 1);