/*  util.c  */

#include "../I2Ohash.h"

#define MYDEBUG 0

/*--------------------------------------------------------------------*/
/*
   ---------------------------------------------------------
   insert the (key1, key2, value) triple into the hash table

   created -- 98jan29, cca
   ---------------------------------------------------------
*/
void
I2Ohash_insert ( 
   I2Ohash   *hashtable,
   int       key1, 
   int       key2, 
   void      *value 
) {
int   loc, loc1, loc2 ;
I2OP  *i2op, *j2op, *prev ;

if ( hashtable == NULL ) {
   fprintf(stderr, "\n error in I2Ohash_insert(%p,%d,%d,%p)"
           "\n hashtable is NULL \n", hashtable, key1, key2, value) ;
   exit(-1) ;
}
#if MYDEBUG > 0
fprintf(stdout, "\n\n inside I2Ohash_insert(%p,%d,%d,%p)",
        hashtable, key1, key2, value) ;
fflush(stdout) ;
#endif
/*
   ---------------------------------------------------
   get the list to hold the (key1, key2, value) triple
   ---------------------------------------------------
*/
loc1 = (key1 + 1) % hashtable->nlist ;
loc2 = (key2 + 1) % hashtable->nlist ;
loc  = (loc1*loc2) % hashtable->nlist ;
#if MYDEBUG > 0
fprintf(stdout, "\n loc1 = %d, loc2 = %d, loc3 = %d", loc1, loc2, loc) ;
fflush(stdout) ;
#endif
/*
   --------------------------------------------------------
   get the list item to hold the (key1, key2, value) triple
   --------------------------------------------------------
*/
#if MYDEBUG > 0
fprintf(stdout, "\n hashtable->freeI2OP = %p", hashtable->freeI2OP) ;
fflush(stdout) ;
#endif
if ( (i2op = hashtable->freeI2OP) == NULL ) {
   if ( hashtable->grow <= 0 ) { 
      fprintf(stderr, "\n fatal error in I2Ohash_insert(%p,%d,%d,%p)"
              "\n no free list items, grow = %d",
              hashtable, key1, key2, value, hashtable->grow) ;
      exit(-1) ;
   }
   i2op = I2OP_init(hashtable->grow, I2OP_FORWARD) ;
   hashtable->freeI2OP = i2op + 1 ;
   i2op->next = hashtable->baseI2OP ;
   hashtable->baseI2OP = i2op ;
   i2op = hashtable->freeI2OP ;
}
hashtable->freeI2OP = i2op->next ;
#if MYDEBUG > 0
fprintf(stdout, "\n i2op = %p, hashtable->freeI2OP = %p", 
        i2op, hashtable->freeI2OP) ;
fflush(stdout) ;
#endif
i2op->value0 = key1  ;
i2op->value1 = key2  ;
i2op->value2 = value ;
i2op->next   = NULL  ;
#if MYDEBUG > 0
fprintf(stdout, "\n i2op : value0 %d, value1 %d, value2 %p, next %p",
        i2op->value0, i2op->value1, i2op->value2, i2op->next) ;
fflush(stdout) ;
#endif
/*
   --------------------------------------------
   insert the (key1, key2, value) into its list
   --------------------------------------------
*/
for ( j2op = hashtable->heads[loc], prev = NULL ;
      j2op != NULL ; j2op = j2op->next ) {
#if MYDEBUG > 0
   fprintf(stdout, "\n j2op : value0 %d, value1 %d, value2 %p, next %p",
           j2op->value0, j2op->value1, j2op->value2, j2op->next) ;
   fflush(stdout) ;
#endif
   if (  j2op->value0 > key1
      || (j2op->value0 == key1 && j2op->value1 >= key2 ) ) {
      break ;
   }
   prev = j2op ;
}
if ( prev == NULL ) {
#if MYDEBUG > 0
   fprintf(stdout, "\n   heads[%d] = %p", loc, i2op) ;
#endif
   hashtable->heads[loc] = i2op ;
} else {
#if MYDEBUG > 0
   fprintf(stdout, "\n   %p->next = %p", prev, i2op) ;
#endif
   prev->next = i2op ;
}
#if MYDEBUG > 0
   fprintf(stdout, "\n   %p->next = %p", i2op, j2op) ;
#endif
i2op->next = j2op ;
hashtable->nitem++ ;

return ; }

/*--------------------------------------------------------------------*/
/*
   ------------------------------------------------
   locate the first (key1,key2,*) in the hash table

   return value --
      0 -- no (key1,key2,*) value triple
      1 -- (key1,key2,value) value triple found,
           value put into *pvalue

   created -- 98jan29, cca
   ------------------------------------------------
*/
int
I2Ohash_locate ( 
   I2Ohash   *hashtable,
   int       key1,
   int       key2,
   void      **pvalue 
) {
int   loc, loc1, loc2, rc ;
I2OP   *i2op ;
/*
   ---------------
   check the input
   ---------------
*/
if ( hashtable == NULL || pvalue == NULL ) {
   fprintf(stderr, "\n error in I2Ohash_locate(%p,%d,%d,%p)"
           "\n hashtable or pvalue is NULL\n",
           hashtable, key1, key2, pvalue) ;
   exit(-1) ;
}
#if MYDEBUG > 0
fprintf(stdout, "\n\n inside I2Ohash_locate(%p,%d,%d,%p)",
        hashtable, key1, key2, pvalue) ;
fflush(stdout) ;
#endif
loc1 = (key1 + 1) % hashtable->nlist ;
loc2 = (key2 + 1) % hashtable->nlist ;
loc  = (loc1*loc2) % hashtable->nlist ;
#if MYDEBUG > 0
fprintf(stdout, "\n loc1 = %d, loc2 = %d, loc3 = %d", loc1, loc2, loc) ;
fflush(stdout) ;
#endif
/*
   ---------------------------------------------
   find the location of the first (key,*) triple
   ---------------------------------------------
*/
for ( i2op = hashtable->heads[loc] ; 
      i2op != NULL ; 
      i2op = i2op->next ) {
#if MYDEBUG > 0
   fprintf(stdout, 
      "\n  i2op = %p, value0 = %d, value1 = %d, value2 = %p, next = %p",
           i2op, i2op->value0, i2op->value1, i2op->value2, i2op->next) ;
   fflush(stdout) ;
#endif
   if (  i2op->value0 > key1 
     || (i2op->value0 == key1 && i2op->value1 >= key2) ) {
      break ;
   }
}
rc = 0 ;
if ( i2op != NULL && i2op->value0 == key1 && i2op->value1 == key2 ) {
/*
   --------------------------
   (key,*) found, set *pvalue
   --------------------------
*/
   *pvalue = i2op->value2 ;
   rc = 1 ;
}
return(rc) ; }

/*--------------------------------------------------------------------*/
/*
   --------------------------------------------------
   remove the first (key1,key2,*) from the hash table

   return value --
      0 -- no (key1,key2,*) value triple
      1 -- (key1,key2,value) value triple found,
           value put into *pvalue

   created -- 98jan29, cca
   --------------------------------------------------
*/
int
I2Ohash_remove ( 
   I2Ohash   *hashtable,
   int       key1,
   int       key2,
   void      **pvalue 
) {
int   loc, loc1, loc2, rc ;
I2OP   *i2op, *prev ;
/*
   ---------------
   check the input
   ---------------
*/
if ( hashtable == NULL || pvalue == NULL ) {
   fprintf(stderr, "\n error in I2Ohash_remove(%p,%d,%d,%p)"
           "\n hashtable or pvalue is NULL\n",
           hashtable, key1, key2, pvalue) ;
   exit(-1) ;
}
loc1 = (key1 + 1) % hashtable->nlist ;
loc2 = (key2 + 1) % hashtable->nlist ;
loc  = (loc1*loc2) % hashtable->nlist ;
/*
   ---------------------------------------------------
   find the location of the first (key1,key2,*) triple
   ---------------------------------------------------
*/
for ( i2op = hashtable->heads[loc], prev = NULL ;
      i2op != NULL ;
      i2op = i2op->next ) {
   if (  i2op->value0 > key1 
     || (i2op->value0 == key1 && i2op->value1 >= key2) ) {
      break ;
   }
   prev = i2op ;
}
rc = 0 ;
if ( i2op != NULL && i2op->value0 == key1 && i2op->value1 == key2 ) {
/*
   ----------------------------------
   (key,*) found, remove, set *pvalue
   ----------------------------------
*/
   if ( prev == NULL ) {
      hashtable->heads[loc] = i2op->next ;
   } else {
      prev->next = i2op->next ;
   }
   i2op->next = hashtable->freeI2OP ;
   hashtable->freeI2OP = i2op ;
   hashtable->nitem-- ;
   *pvalue = i2op->value2 ;
   rc = 1 ;
}
return(rc) ; }

/*--------------------------------------------------------------------*/
/*
   ---------------------------------------------------------------
   return a measure of the nonuniform distribution of the entries.
   a value of 1.0 is best.

   created -- 98jan29, cca
   ---------------------------------------------------------------
*/
double
I2Ohash_measure (
   I2Ohash   *hashtable
) {
double   measure ;
int      count, loc ;
I2OP      *i2op ;

if ( hashtable == NULL ) {
   fprintf(stderr, "\n fatal error in I2Ohash_measure(%p)"
           "\n hashtable is NULL\n", hashtable) ;
   exit(-1) ;
}
measure = 0.0 ;
for ( loc = 0 ; loc < hashtable->nlist ; loc++ ) {
   if ( (i2op = hashtable->heads[loc]) != NULL ) {
      count = 0 ;
      while ( i2op != NULL ) {
         count++ ;
         i2op = i2op->next ;
      }
      measure += count*count ;
   }
}
measure = sqrt(measure) ;
measure *= sqrt((double) hashtable->nlist)/hashtable->nitem ;

return(measure) ; }

/*--------------------------------------------------------------------*/
