/*******************************************************************************
 * Simplified Wrapper and Interface Generator  (SWIG)
 * 
 * Author : David Beazley
 *
 * Department of Computer Science        
 * University of Chicago
 * 1100 E 58th Street
 * Chicago, IL  60637
 * beazley@cs.uchicago.edu
 *
 * Please read the file LICENSE for the copyright and terms by which SWIG
 * can be used and distributed.
 *******************************************************************************/

#include "internal.h"

/*******************************************************************************
 * $Header: /cvsroot/SWIG1.1/SWIG/hash.cxx,v 1.3 1999/11/05 21:45:13 beazley Exp $
 *
 * File : hash.cxx
 *
 * A very simple Hash table class.  Could probably make it more elegant with
 * templates, but templates are pure evil...
 *******************************************************************************/

#define INIT_SIZE   119

// -----------------------------------------------------------------------------
// Hash::Hash()
//
// Constructor.  Creates a new hash table. 
// 
// Inputs : None
//
// Output : New Hash object.
//
// Side Effects : None
// -----------------------------------------------------------------------------

Hash::Hash() {
  int i;
  hashsize = INIT_SIZE;
  hashtable = new Node *[hashsize];
  for (i = 0; i < hashsize; i++) {
    hashtable[i] = 0;
  }
  index = -1;
  current = 0;
}

// -----------------------------------------------------------------------------
// Hash::~Hash()
//
// Destructor.
// 
// Inputs : None
//
// Output : None
//
// Side Effects : Total destruction.
// -----------------------------------------------------------------------------

Hash::~Hash() {
  int   i;
  Node *n,*next;

  for (i = 0; i < hashsize; i++) {
    if (hashtable[i]) {
      n = hashtable[i];
      while (n) {
	next = n->next;
	delete n;
	n = next;
      }
    }
  }
  delete [] hashtable;
}

// -----------------------------------------------------------------------------
// int Hash::h1(const char *key)
// 
// Hashing function.
//
// Inputs : ASCII character string.
//
// Output : Hash table index.
//
// Side Effects : None
// -----------------------------------------------------------------------------

int Hash::h1(const char *key) {
  int h = 0;
  const char *c;

  c = key;
  while (*c) {
    h = (128*h + *c) % hashsize;
    c++;
  }
  return h;
}

// -----------------------------------------------------------------------------
// int Hash::add(const char *k, void *obj)
// 
// Adds a new object to the hash table.
//
// Inputs : 
//          k     = Hash key
//          obj   = Pointer to an object
//
// Output : 0 on success, -1 if item is already in hash table.
//
// Side Effects : 
//          Makes a new hash table entry.
// -----------------------------------------------------------------------------

int Hash::add(const char *k, void *obj) {

  int  hv;
  Node *n,*prev;

  hv = h1(k);                                  // Get hash value
  n = hashtable[hv];
  prev = n;
  while (n) {
    if (strcmp(n->key,k) == 0) return -1;      // Already in hash table
    prev = n;
    n = n->next;
  }

  // Safe to add this to the table

  n = new Node(k,obj,0);
  if (prev) prev->next = n;
  else hashtable[hv] = n;
  return 0;
}

// -----------------------------------------------------------------------------
// int Hash::add(const char *k, void *obj, void (*d)(void *))
// 
// Adds a new object to the hash table.  Allows additional specification of
// a callback function for object deletion.
//
// Inputs :
//          k       = Hash key
//          obj     = Object pointer
//          d       = Deletion function
//
// Output : 0 on success, -1 if item is already in hash table.
//
// Side Effects :
//          Adds an entry to the hash table
// -----------------------------------------------------------------------------

int Hash::add(const char *k, void *obj, void (*d)(void *)) {

  int  hv;
  Node *n,*prev;

  hv = h1(k);                                  // Get hash value
  n = hashtable[hv];
  prev = n;
  while (n) {
    if (strcmp(n->key,k) == 0) return -1;      // Already in hash table
    prev = n;
    n = n->next;
  }

  // Safe to add this to the table

  n = new Node(k,obj,d);
  if (prev) prev->next = n;
  else hashtable[hv] = n;
  return 0;
}

// -----------------------------------------------------------------------------
// void *Hash::lookup(const char *k)
// 
// Looks up a value in the hash table.  Returns a pointer to the object if found.
//
// Inputs : k   = key value
//
// Output : Pointer to object or NULL if not found.
//
// Side Effects : None
// -----------------------------------------------------------------------------

void *Hash::lookup(const char *k) {
  int hv;
  Node *n;

  hv = h1(k);                                // Get hash value
  n = hashtable[hv];

  while (n) {
    if (strcmp(n->key,k) == 0) return n->object;
    n = n->next;
  }

  return 0;
}

// -----------------------------------------------------------------------------
// void Hash::remove(const char *k)
//
// Removes an item from the hash table.  Does nothing if item isn't in the
// hash table to begin with.
// 
// Inputs : k = Key value
//
// Output : None
//
// Side Effects : Deletes item from hash table.
// -----------------------------------------------------------------------------

void Hash::remove(const char *k) {

  int  hv;
  Node *n,*prev;

  hv = h1(k);                                  // Get hash value
  n = hashtable[hv];
  prev = 0;
  while (n) {
    if (strcmp(n->key,k) == 0) {
      // Found it, kill the thing
      if (prev) {
	prev->next = n->next;
      } else {
	hashtable[hv] = n->next;
      }
      delete n;
      return;
    }
    prev = n;
    n = n->next;
  }
}

// -----------------------------------------------------------------------------
// void *Hash::first()
//
// Gets the first item from the hash table or NULL if empty.
// 
// Inputs : None
//
// Output : First object in hash table or NULL if hash table is empty.
//
// Side Effects : Resets an internal iterator variable on the hash table.
// -----------------------------------------------------------------------------

void *Hash::first() {
  index = 0;
  current = 0;

  while (!hashtable[index] && (index < hashsize))
    index++;

  if (index >= hashsize) return 0;
  current = hashtable[index];
  return current->object;
}


// -----------------------------------------------------------------------------
// char *Hash::firstkey()
//
// Gets the first key from the hash table or NULL if empty.
// 
// Inputs : None
//
// Output : First key in hash table or NULL if hash table is empty.
//
// Side Effects : Resets an internal iterator variable on the hash table.
// -----------------------------------------------------------------------------

char *Hash::firstkey() {
  index = 0;
  current = 0;

  while ((index < hashsize) && (!hashtable[index]))
    index++;

  if (index >= hashsize) return 0;
  current = hashtable[index];
  return current->key;
}

// -----------------------------------------------------------------------------
// void *Hash::next()
// 
// Returns the next item in the hash table or NULL if there are no more entries.
// A call to first() should generally be made before using this function.
//
// Inputs : None
//
// Output : Pointer to next object or NULL if there are no more objects.
//
// Side Effects : Updates an iterator variable private to the hash table.
// -----------------------------------------------------------------------------

void *Hash::next() {
  if (index < 0) return first();
  
  // Try to move to the next entry

  current = current->next;

  if (current) {
    return current->object;
  } else {
    index++;
    while ((index < hashsize) && (!hashtable[index]))
      index++;
    if (index >= hashsize) return 0;
    current = hashtable[index];
    return current->object;
  }
}


// -----------------------------------------------------------------------------
// char *Hash::nextkey()
// 
// Returns the next key in the hash table or NULL if there are no more entries.
// A call to firstkey() should generally be made before using this function.
//
// Inputs : None
//
// Output : Pointer to next key or NULL if there are no more objects.
//
// Side Effects : Updates an iterator variable private to the hash table.
// -----------------------------------------------------------------------------

char *Hash::nextkey() {
  if (index < 0) return firstkey();
  
  // Try to move to the next entry

  current = current->next;

  if (current) {
    return current->key;
  } else {
    index++;
    while (!hashtable[index] && (index < hashsize))
      index++;
    if (index >= hashsize) return 0;
    current = hashtable[index];
    return current->key;
  }
}


