ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
/*---------------------------------------------------------------------------
 * Object Table
 *
 *---------------------------------------------------------------------------
 * The OTable:
 *
 *   This table is a lookup-by-name table of all (non destructed)
 *   objects in the game. Similar to the shared string table, this one
 *   is even simpler because object names are unique by name and address.
 *
 *   Note: if you change an object name, you must remove it and reenter it.
 *
 *   The hash index is computed from the object name, and if the object
 *   is found in the index chain, it is moved to the head of the chain
 *   to speed up further lookups.
 *
 *   The size of the hash table is given by OTABLE_SIZE in config.h. It does
 *   not need to be prime, and should probably be set to 1/4 of the number
 *   of objects in the game.
 *
 *   The table links are not counted in the object's refcount.
 *
 *   TODO: Maybe make the object table size dynamic (start with 128 and double
 *   TODO:: as required). This also requires to store the hashvalue in
 *   TODO:: the object.
 *---------------------------------------------------------------------------
 */

#include "driver.h"
#include "typedefs.h"

#include <stdio.h>

#include "otable.h"

#include "backend.h"
#include "gcollect.h"
#include "hash.h"
#include "object.h"
#include "strfuns.h"
#include "simulate.h"
#include "svalue.h"
#include "xalloc.h"

#include "../mudlib/sys/debug_info.h"

/*=========================================================================*/
/*                           OBJECT TABLE                                  */
/*-------------------------------------------------------------------------*/

#if !( (OTABLE_SIZE) & (OTABLE_SIZE)-1 )
#    define ObjHash(s) (whashstr((s), 100) & ((OTABLE_SIZE)-1) )
#else
#    define ObjHash(s) (whashstr((s), 100) % OTABLE_SIZE)
#endif
/* Hash the string <s> and compute the appropriate table index
 */

static object_t ** obj_table = NULL;
  /* Pointer to the (allocated) hashtable.
   */

static long objs_in_table = 0;
  /* Number of objects in the table.
   */

static long obj_searches = 0;
static long obj_probes = 0;
static long objs_found = 0;
  /* Total number of object lookups, of visited objects, and
   * the number of successfull lookups.
   */

static long user_obj_lookups = 0;
static long user_obj_found = 0;
  /* Number of externally requested lookups, and how many succeeded.
   */

/*-------------------------------------------------------------------------*/
static object_t *
find_obj_n (char *s)

/* Lookup the object with name <s> in the table and return the pointer
 * to its structure. If it is not in the table, return NULL.
 *
 * The call updates the statistics and also moves the found object
 * to the head of its hash chain.
 */

{
    object_t * curr, *prev;

    int h = ObjHash(s);

    curr = obj_table[h];
    prev = NULL;

    obj_searches++;

    while (curr)
    {
        obj_probes++;
        if (!strcmp(curr->name, s)) /* found it */
        {
            if (prev) /* not at head of list */
            {
                prev->next_hash = curr->next_hash;
                curr->next_hash = obj_table[h];
                obj_table[h] = curr;
            }
            objs_found++;
            return curr;
        }
        prev = curr;
        curr = curr->next_hash;
    }

    /* Not found */
    return NULL;

} /* find_obj_n() */

/*-------------------------------------------------------------------------*/
void
enter_object_hash (object_t *ob)

/* Add the object <ob> to the table. There must not be an object
 * with the same name in the table already (not even <ob> itself).
 */

{
#ifdef DEBUG
    object_t * s;
#endif
    int h = ObjHash(ob->name);

#ifdef DEBUG
    s = find_obj_n(ob->name);
    if (s)
    {
        if (s != ob)
            fatal("Duplicate object \"%s\" in object hash table.\n"
                 , ob->name);
        else
            fatal( "Entering object \"%s\" twice in object table.\n"
                 , ob->name);
    }
    if (ob->next_hash)
        fatal( "Object \"%s\" not found in object table but next link not null"
             , ob->name);
#endif

    ob->next_hash = obj_table[h];
    obj_table[h] = ob;
    objs_in_table++;
}

/*-------------------------------------------------------------------------*/
void
remove_object_hash (object_t *ob)

/* Remove object <ob> from the table, where it must be in.
 */

{
    object_t * s;
    int h = ObjHash(ob->name);

    s = find_obj_n(ob->name);

    if (s != ob)
        fatal( "Remove object \"%s\": found a different object!"
             , ob->name);

    obj_table[h] = ob->next_hash;
    ob->next_hash = NULL;
    objs_in_table--;
}

/*-------------------------------------------------------------------------*/
object_t *
lookup_object_hash (char *s)

/* Lookup an object by name <s>. If found, return its pointer, if not,
 * return NULL.
 */

{
    object_t * ob = find_obj_n(s);
    user_obj_lookups++;
    if (ob)
        user_obj_found++;
    return ob;
}

/*-------------------------------------------------------------------------*/
size_t
show_otable_status (strbuf_t * sbuf, Bool verbose)

/* Return the amount of memory used by the object table.
 * If <verbose> is TRUE, also print the statistics to the current user.
 */

{
    if (verbose)
    {
#if defined(__MWERKS__) && !defined(WARN_ALL)
#    pragma warn_largeargs off
#endif
        strbuf_add(sbuf, "\nObject name hash table status:\n");
        strbuf_add(sbuf, "------------------------------\n");
        strbuf_addf(sbuf
                   , "Average hash chain length                   %.2f\n"
                   , (float) objs_in_table / (float) OTABLE_SIZE);
        strbuf_addf(sbuf
                   , "Searches/average search length       %ld (%.2f)\n"
                   , obj_searches
                   , (float) obj_probes / (float) obj_searches);
        strbuf_addf(sbuf, "External lookups succeeded (succeed) %ld (%ld)\n"
                   , (long)user_obj_lookups, (long)user_obj_found);
#if defined(__MWERKS__)
#    pragma warn_largeargs reset
#endif
    }
    /* objs_in_table * sizeof(object_t) is already accounted for
       in tot_alloc_object_size.  */
    strbuf_addf(sbuf, "hash table overhead\t\t\t %9ld\n",
                (long)(OTABLE_SIZE * sizeof(object_t *)));
    return OTABLE_SIZE * sizeof(object_t *);
}

/*-------------------------------------------------------------------------*/
void
otable_dinfo_status (svalue_t *svp, int value)

/* Return the object table information for debug_info(DINFO_DATA, DID_STATUS).
 * <svp> points to the svalue block for the result, this function fills in
 * the spots for the object table.
 * If <value> is -1, <svp> points indeed to a value block; other it is
 * the index of the desired value and <svp> points to a single svalue.
 */

{
#define ST_NUMBER(which,code) \
    if (value == -1) svp[which].u.number = code; \
    else if (value == which) svp->u.number = code

    ST_NUMBER(DID_ST_OTABLE, objs_in_table);
    ST_NUMBER(DID_ST_OTABLE_SLOTS, OTABLE_SIZE);
    ST_NUMBER(DID_ST_OTABLE_SIZE, OTABLE_SIZE * sizeof(object_t *));

#undef ST_NUMBER
} /* otable_dinfo_status() */

/*=========================================================================*/
/*                           GENERAL ROUTINES                              */

/*-------------------------------------------------------------------------*/
void
init_otable (void)

/* Allocate and initialise the hash table
 */

{
    int x;
    obj_table = xalloc(sizeof(object_t *) * OTABLE_SIZE);

    for (x = 0; x < OTABLE_SIZE; x++)
        obj_table[x] = NULL;
}

/*-------------------------------------------------------------------------*/
#ifdef GC_SUPPORT
void
note_otable_ref (void)

/* GC support: mark the memory used by the hashtable as used.
 */

{
    note_malloced_block_ref((char *)obj_table);
}

#endif /* GC_SUPPORT */


/***************************************************************************/