/***************************************************************************
* Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming *
* License by Wizards of the Coast. All comments referring to D20, OGL, *
* and SRD refer to the System Reference Document for the Open Gaming *
* system. Any inclusion of these derivatives must include credit to the *
* Mud20 system, the full and complete Open Gaming LIcense, and credit to *
* the respective authors. See ../doc/srd.txt for more information. *
* *
* Emud 2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem. *
* *
* MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey *
* *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* Original Diku Mud copyright (C) 1990 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeld, Tom Madsen, and Katje Nyboe. *
***************************************************************************/
#include "mud.h"
#define MAX_STR_HASH 100000
STR_HASH_DATA *str_hash[MAX_STR_HASH];
unsigned short str_leng_alloc = 0;
/*
Generate a kinky hash index - Scandum
*/
unsigned int get_hash( char *str)
{
unsigned int h;
for (h = str_leng_alloc = 0 ; *str != 0 ; str++, str_leng_alloc++)
{
h -= (4 - (h >> 7)) * *str;
}
h = (h + str_leng_alloc) % MAX_STR_HASH;
return h;
}
char *str_alloc( char *str )
{
unsigned int hash;
STR_HASH_DATA *hash_ptr;
push_call("str_alloc(%p)",str);
hash = get_hash(str);
for (hash_ptr = str_hash[hash] ; hash_ptr ; hash_ptr = hash_ptr->next)
{
if (*str == *((char *) hash_ptr+mud->str_hash_size) && !strcmp(str, (char *) hash_ptr+mud->str_hash_size))
{
hash_ptr->links++;
pop_call();
return (char *) hash_ptr+mud->str_hash_size;
}
}
ALLOCMEM(hash_ptr, unsigned char, str_leng_alloc + mud->str_hash_size + 1);
hash_ptr->links = 1;
hash_ptr->hash = hash;
strcpy( (char *) hash_ptr+mud->str_hash_size, str );
if (str_hash[hash] != NULL)
{
hash_ptr->next = str_hash[hash];
str_hash[hash]->prev = hash_ptr;
}
str_hash[hash] = hash_ptr;
pop_call();
return (char *) hash_ptr+mud->str_hash_size;
}
char *str_dupe( char *str )
{
STR_HASH_DATA *str_ptr;
push_call("str_dupe(%p)",str);
str_ptr = (STR_HASH_DATA *) (str - mud->str_hash_size);
str_ptr->links++;
pop_call();
return str;
}
void str_free( char *str )
{
STR_HASH_DATA *str_ptr;
push_call("str_free(%p)",str);
if (str == NULL)
{
pop_call();
return;
}
str_ptr = (STR_HASH_DATA *) (str - mud->str_hash_size);
if (--str_ptr->links == 0)
{
if (str_ptr->prev)
{
str_ptr->prev->next = str_ptr->next;
}
else
{
str_hash[str_ptr->hash] = str_ptr->next;
}
if (str_ptr->next)
{
str_ptr->next->prev = str_ptr->prev;
}
FREEMEM(str_ptr);
}
pop_call();
return;
}
char *str_hash_status( char *argument )
{
STR_HASH_DATA *hash_ptr;
static char buf[MAX_STRING_LENGTH];
bool hashamounts[MAX_STR_HASH];
int hihash, hihashcnt, usedhash, cnt, strings, links, ulinks, memoryused, memorysaved, maxlink, maxlinkcnt;
push_call("str_hash_status(%p)",argument);
memorysaved = maxlink = maxlinkcnt = strings = ulinks = links = memoryused = hihashcnt = hihash = usedhash = 0;
memset(hashamounts, 0, MAX_STR_HASH);
if (is_number(argument))
{
for (buf[0] = '\0', hash_ptr = str_hash[URANGE(0, atol(argument), MAX_STR_HASH - 1)] ; hash_ptr ; hash_ptr = hash_ptr->next)
{
cat_sprintf(buf, "- %s\n", (char *) hash_ptr+mud->str_hash_size);
}
pop_call();
return buf;
}
for (buf[0] = cnt = 0 ; cnt < MAX_STR_HASH ; cnt++)
{
for (hash_ptr = str_hash[cnt] ; hash_ptr ; hash_ptr = hash_ptr->next)
{
hashamounts[cnt]++;
if (hash_ptr->links == 1)
{
ulinks++;
}
if (*argument == 'd')
{
if (hash_ptr->links > 500)
{
cat_sprintf(buf, "{078}[%6d] links: %s\n\r", hash_ptr->links, (char *) hash_ptr+mud->str_hash_size);
}
if (get_hash((char *) hash_ptr+mud->str_hash_size) != cnt)
{
log_printf("Found a bad string in hash table index: %d", cnt);
log_printf("-- current string --");
log_printf("%s", (char *) hash_ptr+mud->str_hash_size);
log_printf("-- previous string --");
log_printf("%s", hash_ptr->prev ? (char *) hash_ptr->prev+mud->str_hash_size : "(null");
log_printf("-- adjacent string --");
log_printf("%s", hash_ptr->next ? (char *) hash_ptr->next+mud->str_hash_size : "(null");
}
}
if (hash_ptr->links > maxlink)
{
maxlink = hash_ptr->links;
maxlinkcnt = cnt;
}
links += hash_ptr->links;
memoryused += strlen((char *) hash_ptr + mud->str_hash_size) + mud->str_hash_size + 1;
memorysaved += hash_ptr->links * (1 + strlen((char *) hash_ptr + mud->str_hash_size));
}
}
for (cnt = 0 ; cnt < MAX_STR_HASH ; cnt++)
{
strings += hashamounts[cnt];
if (hashamounts[cnt] > hihash)
{
hihash = hashamounts[cnt];
hihashcnt = cnt;
}
if (hashamounts[cnt] > 0)
{
usedhash++;
}
}
cat_sprintf(buf,
"{078}Strings allocated :%10d Total links :%10d\n\r"
"{078}Memory allocated :%10d Memory saved :%10d\n\r"
"{078}Unique links :%10d Average hash :%10.3f\n\r"
"{078}Maximum links :%10d Max links index :%10d\n\r"
"{078}Maximum Hash :%10d Max hash index :%10d\n\r"
"{078}Used Hash: :%10d Hash size :%10d\n\r",
strings,
links,
memoryused,
memorysaved - memoryused,
ulinks,
(float) strings / (float) usedhash,
maxlink,
maxlinkcnt,
hihash,
hihashcnt,
usedhash,
MAX_STR_HASH);
pop_call();
return buf;
}