#ifndef _OHASH_H_
#define _OHASH_H_ 
#include <math.h>
#include "memory.h"
#include "misc.h"
#include "strings.h"
#include "array.h"
typedef enum{
  ohash_ENTRY_EMPTY = 0,
  ohash_ENTRY_DELETED = 1,
  ohash_ENTRY_OCCUPIED = 2,
} OHASH_ENTRY_OCCUPANCY;
typedef intptr_t OHASH_KEY_TYPE;
typedef intptr_t OHASH_DATA_TYPE;
typedef uint32_t OHASH_HASH_TYPE;
typedef OHASH_HASH_TYPE (*OHASH_HASH_FCT)(const OHASH_KEY_TYPE);
typedef BOOL (*OHASH_ELEM_EQUAL)(const OHASH_KEY_TYPE, const OHASH_KEY_TYPE);
typedef BOOL (*OHASH_ELEM_EQUAL_ENV)(const OHASH_KEY_TYPE, const OHASH_KEY_TYPE, const OHASH_DATA_TYPE);
typedef void (*OHASH_DELETE_KEY_FCT)(MEMORY,OHASH_KEY_TYPE);
typedef void (*OHASH_DELETE_DATA_FCT)(MEMORY,OHASH_DATA_TYPE);
typedef BOOL (*OHASH_FILTER_FCT)(intptr_t,OHASH_KEY_TYPE,OHASH_DATA_TYPE);
typedef struct OHASH_ENTRY_TYPE {
  OHASH_ENTRY_OCCUPANCY occ;
  OHASH_KEY_TYPE key;
  OHASH_DATA_TYPE data;
  OHASH_HASH_TYPE hash;
} OHASH_ENTRY_STRUCT, *OHASH_ENTRY;
typedef struct OHASH_TYPE {
  uint32_t capacity;
  uint32_t elements;
  uint32_t deleted;
  uint32_t resize_thd;
  uint32_t cleanup_thd;
  OHASH_HASH_FCT hash_fct;
  OHASH_ELEM_EQUAL elem_eq_fct;
  OHASH_ELEM_EQUAL_ENV elem_eq_fct_env;
  OHASH_DATA_TYPE elem_eq_env;
  MEMORY mem;
  OHASH_ENTRY_STRUCT data[];
} OHASH_STRUCT, *OHASH;
uint32_t ohash_GetCapacity(OHASH Ohash);
uint32_t ohash_GetNumberElems(OHASH Ohash);
uint32_t ohash_GetNumberDeleted(OHASH Ohash);
OHASH_ENTRY ohash_GetData(OHASH Ohash);
OHASH_ENTRY_STRUCT ohash_GetEntryAtIndex(OHASH Ohash, uint32_t Idx);
OHASH_DATA_TYPE ohash_GetDataAtIndex(OHASH Ohash, uint32_t Idx);
void ohash_SetDataAtIndex(OHASH Ohash, uint32_t Idx,
        OHASH_DATA_TYPE Data);
OHASH_KEY_TYPE ohash_GetKeyAtIndex(OHASH Ohash, uint32_t Idx);
OHASH_HASH_TYPE ohash_GetHashAtIndex(OHASH Ohash, uint32_t Idx);
OHASH_ENTRY_OCCUPANCY ohash_GetOccupancyAtIndex(OHASH Ohash, uint32_t Idx);
OHASH_HASH_FCT ohash_GetHashFct(OHASH Ohash);
OHASH_ELEM_EQUAL ohash_GetElemEqFct(OHASH Ohash);
MEMORY ohash_GetMemory(OHASH Ohash);
OHASH ohash_Create(MEMORY Mem, uint32_t Size, OHASH_HASH_FCT, OHASH_ELEM_EQUAL);
OHASH ohash_CreateWithEnv(MEMORY Mem, uint32_t Size, OHASH_HASH_FCT, OHASH_ELEM_EQUAL_ENV, OHASH_DATA_TYPE);
void ohash_Delete(OHASH Ohash, OHASH_DELETE_KEY_FCT, OHASH_DELETE_DATA_FCT);
void ohash_Free(OHASH Ohash);
OHASH ohash_Clean(OHASH Ohash, OHASH_DELETE_KEY_FCT, OHASH_DELETE_DATA_FCT);
OHASH ohash_Cleanup(OHASH Ohash);
OHASH ohash_Extend(OHASH Ohash);
OHASH ohash_Insert(OHASH ohash, OHASH_KEY_TYPE key, OHASH_DATA_TYPE data, OHASH_DELETE_KEY_FCT delete_key, OHASH_DELETE_DATA_FCT delete_data);
OHASH ohash_InsertWithHash(OHASH ohash, OHASH_KEY_TYPE key, OHASH_HASH_TYPE Hash, OHASH_DATA_TYPE data, OHASH_DELETE_KEY_FCT delete_key, OHASH_DELETE_DATA_FCT delete_data);
OHASH ohash_Remove(OHASH ohash, OHASH_KEY_TYPE key, OHASH_DELETE_KEY_FCT, OHASH_DELETE_DATA_FCT);
OHASH ohash_RemoveWithHash(OHASH ohash, OHASH_KEY_TYPE key, OHASH_HASH_TYPE Hash, OHASH_DELETE_KEY_FCT, OHASH_DELETE_DATA_FCT);
OHASH ohash_RemoveIfTrue(OHASH ohash, OHASH_FILTER_FCT filter, intptr_t state, OHASH_DELETE_KEY_FCT delete_key, OHASH_DELETE_DATA_FCT delete_data);
OHASH ohash_RemoveEntryAtIndex(OHASH Ohash, uint32_t Idx);
OHASH_DATA_TYPE ohash_Search(OHASH ohash, OHASH_KEY_TYPE key);
OHASH_DATA_TYPE ohash_SearchWithHash(OHASH ohash, OHASH_KEY_TYPE key, OHASH_HASH_TYPE Hash);
OHASH_KEY_TYPE ohash_SearchKey(OHASH ohash, OHASH_KEY_TYPE key);
OHASH_KEY_TYPE ohash_SearchKeyWithHash(OHASH ohash, OHASH_KEY_TYPE key, OHASH_HASH_TYPE Hash);
uint32_t ohash_SearchIdx(OHASH ohash, OHASH_KEY_TYPE key);
uint32_t ohash_SearchIdxWithHash(OHASH ohash, OHASH_KEY_TYPE key, OHASH_HASH_TYPE Hash);
OHASH ohash_SearchOrInsert(OHASH ohash, OHASH_KEY_TYPE key,
          OHASH_DATA_TYPE value, BOOL* inserted,
          uint32_t* idx);
ARRAY ohash_CreateDataArr(MEMORY mem, OHASH ohash, ARRAY * Data);
ARRAY ohash_AppendDataToArr(MEMORY Mem, OHASH Ohash, ARRAY * Data);
void ohash_CreateKeyAndDataArr(MEMORY Mem, OHASH Ohash, ARRAY * Keys, ARRAY * Data);
uint32_t ohash_InitLinearProbe(OHASH_HASH_TYPE Hash, uint32_t Capacity);
uint32_t ohash_LinearProbe(OHASH_HASH_TYPE Hash, uint32_t LastIdx, uint32_t Iteration, uint32_t Capacity);
uint32_t ohash_InitQuadraticProbe(OHASH_HASH_TYPE Hash, uint32_t Capacity);
uint32_t ohash_QuadraticProbe(OHASH_HASH_TYPE Hash, uint32_t LastIdx, uint32_t Iteration, uint32_t Capacity);
void ohash_FPrint(FILE* File, OHASH Ohash);
void ohash_Print(OHASH Ohash);
void ohash_FPrintAll(FILE* File, OHASH Ohash);
void ohash_PrintAll(OHASH Ohash);
OHASH_HASH_TYPE ohash_StringHash(const OHASH_KEY_TYPE);
OHASH_HASH_TYPE ohash_Integer(const intptr_t H);
OHASH_HASH_TYPE ohash_IntegerNew(const intptr_t H);
OHASH_HASH_TYPE ohash_DummyHash(const intptr_t H);
BOOL ohash_IdEq(const intptr_t X, const intptr_t Y);
BOOL ohash_StringEq(const intptr_t X, const intptr_t Y);
#endif
