/**CFile****************************************************************

  FileName    [vecGen.h]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hash maps.]

  Synopsis    [Hash maps.]

  Author      [Aaron P. Hurst, Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - Jan 26, 2011.]

  Revision    [$Id: vecGen.h,v 1.00 2005/06/20 00:00:00 ahurst Exp $]

***********************************************************************/
 
#ifndef ABC__misc__hash__hashGen_h
#define ABC__misc__hash__hashGen_h


////////////////////////////////////////////////////////////////////////
///                          INCLUDES                                ///
////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include "misc/extra/extra.h"

ABC_NAMESPACE_HEADER_START


////////////////////////////////////////////////////////////////////////
///                         PARAMETERS                               ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                         BASIC TYPES                              ///
////////////////////////////////////////////////////////////////////////

typedef struct Hash_Gen_t_       Hash_Gen_t;
typedef struct Hash_Gen_Entry_t_ Hash_Gen_Entry_t;

struct Hash_Gen_Entry_t_
{
  char *                          key;
  void *                          data;
  struct Hash_Gen_Entry_t_ *     pNext;
};

typedef int (*Hash_GenHashFunction_t)(void* key, int nBins);
typedef int (*Hash_GenCompFunction_t)(void* key, void* data);

struct Hash_Gen_t_ 
{
  int                             nSize;
  int                             nBins;
  Hash_GenHashFunction_t          fHash;
  Hash_GenCompFunction_t          fComp;
  int                             fFreeKey;
  Hash_Gen_Entry_t **             pArray;
};



////////////////////////////////////////////////////////////////////////
///                      MACRO DEFINITIONS                           ///
////////////////////////////////////////////////////////////////////////

#define Hash_GenForEachEntry( pHash, pEntry, bin )   \
  for(bin=-1, pEntry=NULL; bin < pHash->nBins; (!pEntry)?(pEntry=pHash->pArray[++bin]):(pEntry=pEntry->pNext)) \
    if (pEntry)

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    [Default hash function for strings.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static int Hash_DefaultHashFuncStr( void * key, int nBins )
{
    const char* p = (const char*)key;
    int h=0;

    for( ; *p ; ++p )
        h += h*5 + *p;
  
    return (unsigned)h % nBins; 
}

static int Hash_DefaultCmpFuncStr( void * key1, void * key2 )
{
    return strcmp((const char*)key1, (const char*) key2);
}

/**Function*************************************************************

  Synopsis    [Default hash function for (long) integers.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static int Hash_DefaultHashFuncInt( void * key, int nBins )
{
    return (long)key % nBins;
}

/**Function*************************************************************

  Synopsis    [Default comparison function for (long) integers.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static int Hash_DefaultCmpFuncInt( void * key1, void* key2 )
{
    return (long)key1 - (long)key2;
}

/**Function*************************************************************

  Synopsis    [Allocates a hash map with the given number of bins.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline Hash_Gen_t * Hash_GenAlloc( 
  int nBins, 
  int (*Hash_FuncHash)(void *, int),
  int (*Hash_FuncComp)(void *, void *),
  int fFreeKey)
{
  Hash_Gen_t * p;
  assert(nBins > 0);
  p = ABC_CALLOC( Hash_Gen_t, 1 );
  p->nBins  = nBins;
  p->fHash  = Hash_FuncHash? Hash_FuncHash : (int (*)(void *, int))Hash_DefaultHashFuncStr;
  p->fComp  = Hash_FuncComp? Hash_FuncComp : (int (*)(void *, void *))Hash_DefaultCmpFuncStr;
  p->fFreeKey = fFreeKey;
  p->nSize  = 0;
  p->pArray = ABC_CALLOC( Hash_Gen_Entry_t *, nBins );
  return p;
}

/**Function*************************************************************

  Synopsis    [Returns 1 if a key already exists.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Hash_GenExists( Hash_Gen_t *p, void * key )
{
  int bin;
  Hash_Gen_Entry_t *pEntry;

  // find the bin where this key would live
  bin = (*(p->fHash))(key, p->nBins);

  // search for key
  pEntry = p->pArray[bin];
  while(pEntry) {
    if ( !p->fComp(pEntry->key,key) ) {
      return 1;
    }
    pEntry = pEntry->pNext;
  }

  return 0;
}

/**Function*************************************************************

  Synopsis    [Finds or creates an entry with a key and writes value.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Hash_GenWriteEntry( Hash_Gen_t *p, void * key, void * data )
{
  int bin;
  Hash_Gen_Entry_t *pEntry, **pLast;

  // find the bin where this key would live
  bin = (*(p->fHash))(key, p->nBins);

  // search for key
  pLast = &(p->pArray[bin]);
  pEntry = p->pArray[bin];
  while(pEntry) {
    if ( !p->fComp(pEntry->key,key) ) {
      pEntry->data = data;
      return;
    }
    pLast = &(pEntry->pNext);
    pEntry = pEntry->pNext;
  }

  // this key does not currently exist
  // create a new entry and add to bin
  p->nSize++;
  (*pLast) = pEntry = ABC_ALLOC( Hash_Gen_Entry_t, 1 );
  pEntry->pNext = NULL;
  pEntry->key  = (char *)key;
  pEntry->data = data;

  return;
}


/**Function*************************************************************

  Synopsis    [Finds or creates an entry with a key.]

  Description [fCreate specifies whether a new entry should be created.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline Hash_Gen_Entry_t * Hash_GenEntry( Hash_Gen_t *p, void * key, int fCreate )
{
  int bin;
  Hash_Gen_Entry_t *pEntry, **pLast;

  // find the bin where this key would live
  bin = (*(p->fHash))(key, p->nBins);

  // search for key
  pLast = &(p->pArray[bin]);
  pEntry = p->pArray[bin];
  while(pEntry) {
    if ( !p->fComp(pEntry->key,key) )
      return pEntry;
    pLast = &(pEntry->pNext);
    pEntry = pEntry->pNext;
  }

  // this key does not currently exist
  if (fCreate) {
    // create a new entry and add to bin
    p->nSize++;
    (*pLast) = pEntry = ABC_ALLOC( Hash_Gen_Entry_t, 1 );
    pEntry->pNext = NULL;
    pEntry->key  = (char *)key;
    pEntry->data = NULL;
    return pEntry;
  }

  return NULL;
}

/**Function*************************************************************

  Synopsis    [Deletes an entry.]

  Description [Returns data, if there was any.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void* Hash_GenRemove( Hash_Gen_t *p, void * key )
{
  int    bin;
  void * data;
  Hash_Gen_Entry_t *pEntry, **pLast;

  // find the bin where this key would live
  bin = (*(p->fHash))(key, p->nBins);

  // search for key
  pLast = &(p->pArray[bin]);
  pEntry = p->pArray[bin];
  while(pEntry) {
    if ( !p->fComp(pEntry->key,key) ) {
      p->nSize--;
      data = pEntry->data;
      *pLast = pEntry->pNext;
      if (p->fFreeKey)
        ABC_FREE(pEntry->key);
      ABC_FREE(pEntry);
      return data;
    }
    pLast = &(pEntry->pNext);
    pEntry = pEntry->pNext;
  }
    
  // could not find key
  return NULL;
}

/**Function*************************************************************

  Synopsis    [Frees the hash.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Hash_GenFree( Hash_Gen_t *p ) 
{
  int bin;
  Hash_Gen_Entry_t *pEntry, *pTemp;

  // free bins
  for(bin = 0; bin < p->nBins; bin++) {
    pEntry = p->pArray[bin];
    while(pEntry) {
      pTemp = pEntry;
      if( p->fFreeKey )
        ABC_FREE(pTemp->key);
      pEntry = pEntry->pNext;
      ABC_FREE( pTemp );
    }
  }
 
  // free hash
  ABC_FREE( p->pArray );
  ABC_FREE( p );
}

////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////



ABC_NAMESPACE_HEADER_END

#endif