ref: f6c1c4765e7f9785fb8b764bd65e801522c10ba4
parent: d5b2877a8e4d1c189cf77a8951f847f853327a7d
author: Simon Howard <[email protected]>
date: Fri Mar 24 15:39:08 EST 2006
Generate a hash table for fast lump name lookups. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 436
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// $Id: w_wad.c 434 2006-03-24 19:55:04Z fraggle $
+// $Id: w_wad.c 436 2006-03-24 20:39:08Z fraggle $
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
@@ -66,7 +66,7 @@
static const char
-rcsid[] = "$Id: w_wad.c 434 2006-03-24 19:55:04Z fraggle $";
+rcsid[] = "$Id: w_wad.c 436 2006-03-24 20:39:08Z fraggle $";
#include <ctype.h>
@@ -82,27 +82,20 @@
#include "w_wad.h"
-
-
-
-
-
//
// GLOBALS
//
// Location of each lump on disk.
-lumpinfo_t* lumpinfo;
-int numlumps = 0;
-#define strcmpi strcasecmp
+lumpinfo_t *lumpinfo;
+int numlumps = 0;
-void string_to_upper (char* s)
-{
- while (*s) { *s = toupper(*s); s++; }
-}
+// Hash table for fast lookups
-int filelength (FILE *handle)
+static lumpinfo_t **lumphash;
+
+static int FileLength (FILE *handle)
{
long savedpos;
long length;
@@ -120,10 +113,7 @@
}
-void
-ExtractFileBase
-( char* path,
- char* dest )
+static void ExtractFileBase(char *path, char *dest)
{
char* src;
int length;
@@ -151,9 +141,27 @@
}
}
+// Hash function used for lump names.
+// Must be mod'ed with table size.
+// Can be used for any 8-character names.
+// by Lee Killough
+static unsigned int W_LumpNameHash(const char *s)
+{
+ unsigned int hash;
+ ((hash = toupper(s[0]), s[1]) &&
+ (hash = hash*3+toupper(s[1]), s[2]) &&
+ (hash = hash*2+toupper(s[2]), s[3]) &&
+ (hash = hash*2+toupper(s[3]), s[4]) &&
+ (hash = hash*2+toupper(s[4]), s[5]) &&
+ (hash = hash*2+toupper(s[5]), s[6]) &&
+ (hash = hash*2+toupper(s[6]),
+ hash = hash*2+toupper(s[7]))
+ );
+ return hash;
+}
//
// LUMP BASED ROUTINES.
@@ -206,12 +214,12 @@
startlump = numlumps;
- if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
+ if (strcasecmp(filename+strlen(filename)-3 , "wad" ) )
{
// single lump file
fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0);
fileinfo->filepos = 0;
- fileinfo->size = filelength(handle);
+ fileinfo->size = FileLength(handle);
ExtractFileBase (filename, fileinfo->name);
numlumps++;
}
@@ -264,6 +272,12 @@
Z_Free(fileinfo);
+ if (lumphash != NULL)
+ {
+ Z_Free(lumphash);
+ lumphash = NULL;
+ }
+
return true;
}
@@ -337,42 +351,46 @@
int W_CheckNumForName (char* name)
{
- union {
- char s[9];
- int x[2];
-
- } name8;
-
- int v1;
- int v2;
- lumpinfo_t* lump_p;
+ lumpinfo_t *lump_p;
+ int i;
- // make the name into two integers for easy compares
- strncpy (name8.s,name,8);
+ // Do we have a hash table yet?
- // in case the name was a fill 8 chars
- name8.s[8] = 0;
+ if (lumphash != NULL)
+ {
+ int hash;
+
+ printf("looking up %s\n", name);
- // case insensitive
- string_to_upper (name8.s);
+ // We do! Excellent.
- v1 = name8.x[0];
- v2 = name8.x[1];
-
-
- // scan backwards so patch lump files take precedence
- lump_p = lumpinfo + numlumps;
-
- while (lump_p-- != lumpinfo)
+ hash = W_LumpNameHash(name) % numlumps;
+
+ for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next)
+ {
+ if (!strncasecmp(lump_p->name, name, 8))
+ {
+ return lump_p - lumpinfo;
+ }
+ }
+ }
+ else
{
- if ( *(int *)lump_p->name == v1
- && *(int *)&lump_p->name[4] == v2)
- {
- return lump_p - lumpinfo;
- }
+ // We don't have a hash table generate yet. Linear search :-(
+ //
+ // scan backwards so patch lump files take precedence
+
+ for (i=numlumps-1; i >= 0; --i)
+ {
+ if (!strncasecmp(lumpinfo[i].name, name, 8))
+ {
+ return i;
+ }
+ }
}
// TFB. Not found.
+
return -1;
}
@@ -564,4 +582,37 @@
#endif
+
+// Generate a hash table for fast lookups
+
+void W_GenerateHashTable(void)
+{
+ int i;
+
+ // Free the old hash table, if there is one
+
+ if (lumphash != NULL)
+ {
+ Z_Free(lumphash);
+ }
+
+ // Generate hash table
+
+ lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL);
+ memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps);
+
+ for (i=0; i<numlumps; ++i)
+ {
+ unsigned int hash;
+
+ hash = W_LumpNameHash(lumpinfo[i].name) % numlumps;
+
+ // Hook into the hash table
+
+ lumpinfo[i].next = lumphash[hash];
+ lumphash[hash] = &lumpinfo[i];
+ }
+
+ // All done!
+}