/**\file n_hash.h
 * Hash functions and table
 *\author Castagnier Mickael
 *\version 2.0
 *\date 16/03/2015
 */

#ifndef NILOREA_HASH_HEADER_GUARD
#define NILOREA_HASH_HEADER_GUARD

#ifdef __cplusplus
extern "C" {
#endif 

/**\defgroup HASH_TABLE HASH_TABLE: hash table with multiples predefined type
   \addtogroup HASH_TABLE 
  @{
*/


#if defined( LINUX ) || defined( AIX ) || defined( SOLARIS )
#include <arpa/inet.h>
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#include <string.h>
#undef _X_OPEN_SOURCE
#else
#include <string.h>
#endif
#endif

#include <stdint.h>
#include "n_log.h"
#include "n_list.h"

#if defined(_MSC_VER)
/*! force inline attribute for MSVC */
#define FORCE_INLINE    __forceinline
#include <stdlib.h>
/*! compatibility with existing rot func */
#define ROTL32(x,y)     _rotl(x,y)
/*! compatibility with existing func */
#define BIG_CONSTANT(x) (x)

#else   

#ifdef SOLARIS
/*! force inline attribute for SOLARIS */
#define FORCE_INLINE __attribute__((always_inline))
#else
/*! force inline attribute for WIN32 MINGW or LINUX */
#define FORCE_INLINE inline __attribute__((always_inline))
#endif


/*! missing ROTL fix 32bit */
#define ROTL32(x,y)     rotl32(x,y)
/*! missing ROTL constant fix 64bit */
#define BIG_CONSTANT(x) (x##LLU)

#endif /* if defined MSVC ... */

   /*! value of integral type inside the hash node */
#define HASH_INT       0
   /*! value of double type inside the hash node */
#define HASH_DOUBLE    1 
   /*! value of char * type inside the hash node */
#define HASH_STRING    2 
   /*! value of pointer type inside the hash node */
#define HASH_PTR       3
   /*! value of unknow type inside the hash node */
#define HASH_UNKNOWN    4


   /*! union of the value of a node */
   union HASH_VALUE
   {
      /*! integral type */
      int    ival ;
      /*! double type */
      double fval ;
      /*! pointer type */
      void   *ptr ;
      /*! char *type */
      char   *string ;
   };


   /*! structure of a hash table node */
   typedef struct HASH_NODE
   {
      /*! key of the node */
      char *key ;
      /*! type of the node */
      int type ;
      /*! data inside the node */
      union HASH_VALUE data ;
   } HASH_NODE ;


   /*! structure of a hash table */
   typedef struct HASH_TABLE
   {
      /*! size of the hash table */
      int size ,
      /*! total number of used keys in the table */
          nb_keys ;
      /*! preallocated table */
      LIST **hash_table;
   } HASH_TABLE ;



   /* murmur hash func 32bit */
   void MurmurHash3_x86_32  ( const void * key, int len, uint32_t seed, void * out );
   /* murmur hash func 128bit */
   void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );

   /* get the type of the node */
   char *ht_node_type( HASH_NODE *node );

   /* new hash table allocator */
   HASH_TABLE *new_ht( int size );

   /* put an integer */
   int ht_put_int( HASH_TABLE *table , char * key , int    val );
   /* put a double */
   int ht_put_double( HASH_TABLE *table , char * key , double val );
   /* put a a pointer */
   int ht_put_ptr( HASH_TABLE *table , char * key , void  *val , void (*destructor)( void *ptr ) );
   /* put an char *string */
   int ht_put_string( HASH_TABLE *table , char * key , char  *val );

   /* get a given key's node */
   HASH_NODE *ht_get_node( HASH_TABLE *table , char *key ) ;
   /* get an int from a key's node */
   int ht_get_int( HASH_TABLE *table , char * key , int *val );
   /* get a double from a key's node */
   int ht_get_double( HASH_TABLE *table , char * key , double *val );
   /* get a pointer from a key's node */
   int ht_get_ptr( HASH_TABLE *table , char * key , void  **val );
   /* get a char *string from a key's node */
   int ht_get_string( HASH_TABLE *table , char * key , char  **val );

   /* remove given's key node from the table */
   int ht_remove( HASH_TABLE *table , char *key );
   /* empty a hash table. char *strings are also freed */
   int empty_ht( HASH_TABLE *table );
   /* destroy a hash table*/
   int destroy_ht( HASH_TABLE **table );
 
/*@}*/
   
#ifdef __cplusplus
} 
#endif

#endif
