suntzu/bin/
suntzu/cnf/
suntzu/lib/
suntzu/lib/etc/
suntzu/lib/etc/boards/
suntzu/lib/house/
suntzu/lib/misc/
suntzu/lib/plralias/ZZZ/
suntzu/lib/plrfiles/
suntzu/lib/plrobjs/
suntzu/lib/plrobjs/ZZZ/
suntzu/lib/world/gld/
suntzu/lib/world/trg/
suntzu/src.1/
suntzu/src.1/doc/
suntzu/src/
suntzu/src/doc/
/***************************************************************************
 *   File: htree.c                                                         *
 *  Usage: Generalized hash tree code for fast lookups                     *
 *                                                                         *
 * This code is released under the CircleMud License                       *
 * Written by Elie Rosenblum <fnord@cosanostra.net>                        *
 * Copyright (c) 7-Oct-2004                                                *
 ***************************************************************************/

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "db.h"
#include "htree.h"

#define HTREE_TEST_CYCLES 3000	/* How many lookups to do in the test run */

struct htree_node *HTREE_NULL = NULL;
int htree_total_nodes = 0;
int htree_depth_used = 0;

struct htree_node *htree_init()
{
  struct htree_node *newnode;
  int i;

  if (! HTREE_NULL) {
    htree_total_nodes++;
    CREATE(HTREE_NULL, struct htree_node, 1);
    for (i = 0; i < HTREE_NODE_SUBS; i++) {
      HTREE_NULL->subs[i] = HTREE_NULL;
    }
    HTREE_NULL->content = NOWHERE;
    HTREE_NULL->parent = NULL;
  }

  if (! htree_depth_used)
    htree_depth_used = 1;

  htree_total_nodes++;
  CREATE(newnode, struct htree_node, 1);
  memcpy(newnode->subs, HTREE_NULL->subs, HTREE_NODE_SUBS * sizeof(struct htree_node *));
  newnode->content = NOWHERE;
  newnode->parent = HTREE_NULL;

  return newnode;
}

void htree_free(struct htree_node *root)
{
  int i;

  if (! root || root == HTREE_NULL)
    return;

  for (i = 0; i < HTREE_NODE_SUBS; i++)
    htree_free(root->subs[i]);

  free(root);
}

void htree_add(struct htree_node *root, IDXTYPE index, IDXTYPE content)
{
  struct htree_node *tmp;
  int i, depth;

  if (! root)
    return;

  tmp = root;
  depth = 0;
  while (index) {
    depth++;
    i = index & HTREE_NODE_MASK;
    index >>= HTREE_NODE_BITS;
    if (tmp->subs[i] == HTREE_NULL) {
      htree_total_nodes++;
      CREATE(tmp->subs[i], struct htree_node, 1);
      memcpy(tmp->subs[i]->subs, HTREE_NULL->subs, HTREE_NODE_SUBS * sizeof(struct htree_node *));
      tmp->subs[i]->content = NOWHERE;
      tmp->subs[i]->parent = HTREE_NULL;
    }
    tmp = tmp->subs[i];
  }

  if (tmp == HTREE_NULL) /* We fell off somehow! Time to crap our pants */
    return;

  if (depth > htree_depth_used)
    htree_depth_used = depth;

  tmp->content = content;
}

struct htree_node *htree_find_node(struct htree_node *root, IDXTYPE index)
{
  struct htree_node *tmp;
  int i;
  
  tmp = root;
  while (index) {
    i = index & HTREE_NODE_MASK;
    index >>= HTREE_NODE_BITS;
    tmp = tmp->subs[i];
  }

  return tmp;
}

void htree_del(struct htree_node *root, IDXTYPE index)
{
  struct htree_node *tmp;

  tmp = htree_find_node(root, index);
  tmp->content = NOWHERE;
}

IDXTYPE htree_find(struct htree_node *root, IDXTYPE index)
{
  struct htree_node *tmp;

  tmp = htree_find_node(root, index);
  return tmp->content;
}

room_rnum real_room_old(room_vnum vnum)
{
  room_rnum bot, top, mid;
  bot = 0;
  top = top_of_world;

  /* perform binary search on world-table */
  for (;;) {
    mid = (bot + top) / 2;

    if ((world + mid)->number == vnum)
      return (mid);

    if (bot >= top)
      return (NOWHERE);
    if ((world + mid)->number > vnum)
      top = mid - 1;
    else
      bot = mid + 1;
  }
}

void htree_test()
{
  int i, n, l;
  struct timeval start, finish;
  float t1, t2;

  gettimeofday(&start, NULL);
  for (i = 0; i < HTREE_TEST_CYCLES; i++) {
    n = rand_number(1, top_of_world);
    l = real_room_old(world[n].number);
  }
  gettimeofday(&finish, NULL);
  if (start.tv_usec > finish.tv_usec) {
    finish.tv_sec -= 1;
    finish.tv_usec += 1000000;
  }
  t1 = ((float)finish.tv_sec + ((float)finish.tv_usec) / 1000000) -
       ((float)start.tv_sec + ((float)start.tv_usec) / 1000000);
  gettimeofday(&start, NULL);
  for (i = 0; i < HTREE_TEST_CYCLES; i++) {
    n = rand_number(1, top_of_world);
    l = real_room(world[n].number);
  }
  gettimeofday(&finish, NULL);
  if (start.tv_usec > finish.tv_usec) {
    finish.tv_sec -= 1;
    finish.tv_usec += 1000000;
  }
  t2 = ((float)finish.tv_sec + ((float)finish.tv_usec) / 1000000) -
       ((float)start.tv_sec + ((float)start.tv_usec) / 1000000);
  log("htree stats (global): %d nodes, %d bytes (depth %d/%d used/possible)", htree_total_nodes, htree_total_nodes * sizeof(struct htree_node), htree_depth_used, HTREE_MAX_DEPTH);
  log("htree_test: htree speedup factor: %.0f%%", t1 * 100 / t2);
}