#ifdef DOC_BUILD_INTERNAL
#endif
#include <math.h>
#include "ohash.h"
const uint32_t ohash_MIN_CAPACITY = 16U;
const uint32_t ohash_MAX_CAPACITY = 1U << 31;
uint32_t ohash_GetCapacity(OHASH Ohash)
{
  return Ohash->capacity;
}
uint32_t ohash_GetResizeThreshold(OHASH Ohash)
{
  return Ohash->resize_thd;
}
uint32_t ohash_GetCleanupThreshold(OHASH Ohash)
{
  return Ohash->cleanup_thd;
}
uint32_t ohash_GetNumberElems(OHASH Ohash)
{
  return Ohash->elements;
}
uint32_t ohash_GetNumberDeleted(OHASH Ohash)
{
  return Ohash->deleted;
}
uint32_t ohash_IncreaseNumberElems(OHASH Ohash)
{
  return ++(Ohash->elements);
}
uint32_t ohash_DecreaseNumberElems(OHASH Ohash)
{
  return --(Ohash->elements);
}
uint32_t ohash_IncreaseNumberDeleted(OHASH Ohash)
{
  return ++(Ohash->deleted);
}
uint32_t ohash_DecreaseNumberDeleted(OHASH Ohash)
{
  return --(Ohash->deleted);
}
OHASH_ENTRY ohash_GetData(OHASH Ohash)
{
  return Ohash->data;
}
OHASH_ENTRY_STRUCT ohash_GetEntryAtIndex(OHASH Ohash, uint32_t Idx)
{
  return Ohash->data[Idx];
}
OHASH_DATA_TYPE ohash_GetDataAtIndex(OHASH Ohash, uint32_t Idx)
{
  return Ohash->data[Idx].data;
}
void ohash_SetDataAtIndex(OHASH Ohash, uint32_t Idx, OHASH_DATA_TYPE Data)
{
#ifdef SPASS_CHECK
  if(ohash_GetOccupancyAtIndex(Ohash,Idx) != ohash_ENTRY_OCCUPIED){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: entry wasn't oocupied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  Ohash->data[Idx].data = Data;
}
OHASH_KEY_TYPE ohash_GetKeyAtIndex(OHASH Ohash, uint32_t Idx)
{
  return Ohash->data[Idx].key;
}
OHASH_HASH_TYPE ohash_GetHashAtIndex(OHASH Ohash, uint32_t Idx)
{
  return Ohash->data[Idx].hash;
}
OHASH_ENTRY_OCCUPANCY ohash_GetOccupancyAtIndex(OHASH Ohash, uint32_t Idx)
{
  return Ohash->data[Idx].occ;
}
OHASH_HASH_FCT ohash_GetHashFct(OHASH Ohash)
{
  return Ohash->hash_fct;
}
OHASH_ELEM_EQUAL ohash_GetElemEqFct(OHASH Ohash)
{
  return Ohash->elem_eq_fct;
}
OHASH_ELEM_EQUAL_ENV ohash_GetElemEqFctEnv(OHASH Ohash)
{
  return Ohash->elem_eq_fct_env;
}
OHASH_DATA_TYPE ohash_GetElemEqEnv(OHASH Ohash)
{
  return Ohash->elem_eq_env;
}
MEMORY ohash_GetMemory(OHASH Ohash)
{
  return Ohash->mem;
}
OHASH ohash_RemoveEntryAtIndex(OHASH Ohash, uint32_t Idx)
{
  OHASH_ENTRY data;
  data = ohash_GetData(Ohash);
  data[Idx].occ = ohash_ENTRY_DELETED;
  data[Idx].key = (intptr_t)NULL;
  data[Idx].data = (intptr_t)NULL;
  data[Idx].hash = 0;
  ohash_DecreaseNumberElems(Ohash);
  ohash_IncreaseNumberDeleted(Ohash);
  return Ohash;
}
OHASH ohash_CreatePow2(MEMORY Mem, uint32_t CapacityPow2,
         OHASH_HASH_FCT HashFct, OHASH_ELEM_EQUAL ElemEqFct, OHASH_ELEM_EQUAL_ENV ElemEqFctEnv, OHASH_DATA_TYPE ElemEqEnv);
OHASH ohash_CreateGeneral(MEMORY Mem, uint32_t Capacity,
     OHASH_HASH_FCT HashFct, OHASH_ELEM_EQUAL ElemEqFct, OHASH_ELEM_EQUAL_ENV ElemEqFctEnv, OHASH_DATA_TYPE ElemEqEnv)
{
  #ifdef SPASS_CHECK
  #ifndef SPASS_NO_MEMORY_MANAGEMENT
  if(Mem == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Mem was NULL.", __func__);
    misc_FinishErrorReport();
  }
  #endif
  if(Capacity > ohash_MAX_CAPACITY){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Capacity is too large to create a fitting hash map.", __func__);
    misc_FinishErrorReport();
  }
  if(ElemEqFct == NULL && ElemEqFctEnv == NULL ){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: ElemEq was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t calculated_capacity;
  uint32_t i;
  if(Capacity < ohash_MIN_CAPACITY){
    calculated_capacity = ohash_MIN_CAPACITY;
  }else{
    i = 1;
    calculated_capacity = Capacity-1;
    while(calculated_capacity >>= 1) i++;
    calculated_capacity = ((uint32_t)1) << i;
    misc_ASSERT(calculated_capacity >= Capacity);
  }
  return ohash_CreatePow2(Mem, calculated_capacity, HashFct, ElemEqFct, ElemEqFctEnv, ElemEqEnv);
}
OHASH ohash_CreateWithEnv(MEMORY Mem, uint32_t Capacity,
     OHASH_HASH_FCT HashFct, OHASH_ELEM_EQUAL_ENV ElemEq, OHASH_DATA_TYPE ElemEqEnv)
{
  return ohash_CreateGeneral(Mem, Capacity, HashFct,(OHASH_ELEM_EQUAL) NULL, ElemEq, ElemEqEnv);
}
OHASH ohash_Create(MEMORY Mem, uint32_t Capacity,
     OHASH_HASH_FCT HashFct, OHASH_ELEM_EQUAL ElemEq)
{
  return ohash_CreateGeneral(Mem, Capacity, HashFct, ElemEq,(OHASH_ELEM_EQUAL_ENV) NULL, (OHASH_DATA_TYPE) NULL);
}
OHASH ohash_CreatePow2(MEMORY Mem, uint32_t CapacityPow2,
         OHASH_HASH_FCT HashFct, OHASH_ELEM_EQUAL ElemEqFct, OHASH_ELEM_EQUAL_ENV ElemEqFctEnv, OHASH_DATA_TYPE ElemEqEnv)
{
  OHASH ohash;
  unsigned size;
  size = sizeof(OHASH_STRUCT) + CapacityPow2 * sizeof(OHASH_ENTRY_STRUCT);
  if (size>memory_GetDynmaxSize(Mem)) {
    ohash = (OHASH)malloc(size);
    if (ohash == (OHASH)NULL) {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n Memory Error. Out of memory in ohash.");
      misc_UserErrorReport("\n %s\n", Mem->outofmem);
      misc_FinishUserErrorReport();
    }
  }
  else
    ohash = (OHASH) memory_Malloc(Mem, size);
  memset(ohash,0, sizeof(OHASH_STRUCT) +
  CapacityPow2 * sizeof(OHASH_ENTRY_STRUCT));
  ohash->capacity = CapacityPow2;
  ohash->elements = 0;
  ohash->deleted = 0;
  ohash->resize_thd = (CapacityPow2/4);
  ohash->cleanup_thd = (CapacityPow2/12);
  ohash->mem = Mem;
  ohash->hash_fct = HashFct;
  ohash->elem_eq_fct = ElemEqFct;
  ohash->elem_eq_fct_env = ElemEqFctEnv;
  ohash->elem_eq_env = ElemEqEnv;
  return ohash;
}
void ohash_Free(OHASH Ohash)
{
  unsigned size;
  size = sizeof(OHASH_STRUCT) + ohash_GetCapacity(Ohash) * sizeof(OHASH_ENTRY_STRUCT);
  if (size > memory_GetDynmaxSize(ohash_GetMemory(Ohash)))
    free(Ohash);
  else
    memory_Free(ohash_GetMemory(Ohash), Ohash,size);
}
void ohash_Delete(OHASH Ohash, OHASH_DELETE_KEY_FCT DeleteKey,
    OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t i;
  MEMORY mem;
#ifdef SPASS_CHECK
  uint32_t elements, deleted;
  elements = 0;
  deleted = 0;
#endif
  mem = ohash_GetMemory(Ohash);
  for(i = 0; i < ohash_GetCapacity(Ohash); ++i){
    if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_OCCUPIED) {
      if (DeleteKey)
 DeleteKey(mem, ohash_GetKeyAtIndex(Ohash,i));
      if (DeleteData)
 DeleteData(mem, ohash_GetDataAtIndex(Ohash,i));
#ifdef SPASS_CHECK
      elements++;
#endif
    }
#ifdef SPASS_CHECK
    else if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_DELETED){
      deleted++;
    }
#endif
  }
#ifdef SPASS_CHECK
  if(ohash_GetNumberElems(Ohash) != elements){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of occupied entries was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberElems(Ohash), elements);
    misc_FinishErrorReport();
  }
  if(ohash_GetNumberDeleted(Ohash) != deleted){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of entries marked as deleted was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberDeleted(Ohash), deleted);
    misc_FinishErrorReport();
  }
#endif
  ohash_Free(Ohash);
}
OHASH ohash_Clean(OHASH Ohash, OHASH_DELETE_KEY_FCT DeleteKey, OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t i;
  OHASH_ENTRY data;
  MEMORY mem;
#ifdef SPASS_CHECK
  uint32_t elements, deleted;
  elements = 0;
  deleted = 0;
#endif
  mem = ohash_GetMemory(Ohash);
  data = ohash_GetData(Ohash);
  for(i=0; i < ohash_GetCapacity(Ohash); ++i) {
    if(data[i].occ == ohash_ENTRY_OCCUPIED) {
      if (DeleteKey)
 DeleteKey(mem, data[i].key);
      if (DeleteData)
 DeleteData(mem, data[i].data);
      data[i].occ = ohash_ENTRY_EMPTY;
      data[i].key = (OHASH_KEY_TYPE)NULL;
      data[i].data = (OHASH_DATA_TYPE)NULL;
      data[i].hash = (OHASH_HASH_TYPE)0U;
#ifdef SPASS_CHECK
      elements++;
#endif
    }else if(data[i].occ == ohash_ENTRY_DELETED){
      data[i].occ = ohash_ENTRY_EMPTY;
#ifdef SPASS_CHECK
      deleted++;
#endif
    }
  }
#ifdef SPASS_CHECK
  if(ohash_GetNumberElems(Ohash) != elements){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of occupied entries was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberElems(Ohash), elements);
    misc_FinishErrorReport();
  }
  if(ohash_GetNumberDeleted(Ohash) != deleted){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of entries marked as deleted was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberDeleted(Ohash), deleted);
    misc_FinishErrorReport();
  }
#endif
  Ohash->elements = 0U;
  Ohash->deleted = 0U;
  return Ohash;
}
uint32_t ohash_SearchOrInsertDirectly(OHASH Ohash, OHASH_KEY_TYPE Key,
          OHASH_DATA_TYPE Data,
          OHASH_HASH_TYPE Hash,
          BOOL* Inserted)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if((ohash_GetNumberElems(Ohash) + ohash_GetNumberDeleted(Ohash)) >= ohash_GetCapacity(Ohash)){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: map is already full", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t h,i,cap,k;
  OHASH_ENTRY data;
  OHASH_ELEM_EQUAL elemeqfct;
  OHASH_ELEM_EQUAL_ENV elemeqfctenv;
  OHASH_DATA_TYPE elemeqenv;
  i = 0;
  cap = ohash_GetCapacity(Ohash);
  data = ohash_GetData(Ohash);
  elemeqfct = ohash_GetElemEqFct(Ohash);
  elemeqfctenv = ohash_GetElemEqFctEnv(Ohash);
  elemeqenv = ohash_GetElemEqEnv(Ohash);
  *Inserted = FALSE;
  h = ohash_InitLinearProbe(Hash,cap);
  misc_ASSERT(h < cap);
  do {
    switch(data[h].occ) {
    case ohash_ENTRY_EMPTY:
      data[h].occ = ohash_ENTRY_OCCUPIED;
      data[h].key = Key;
      data[h].data = Data;
      data[h].hash = Hash;
      ohash_IncreaseNumberElems(Ohash);
      *Inserted = TRUE;
      return h;
    case ohash_ENTRY_DELETED:
      k = ohash_LinearProbe(Hash, h, i, cap);
      misc_ASSERT(k < cap);
      i++;
      do {
 switch(data[k].occ) {
 case ohash_ENTRY_EMPTY:
   i = cap-1;
   break;
 case ohash_ENTRY_OCCUPIED:
   if (data[k].hash == Hash && (elemeqenv ? elemeqfctenv(Key, data[k].key, elemeqenv) : elemeqfct(Key, data[k].key))) {
     return k;
   }
 default:
   break;
 }
 k = ohash_LinearProbe(Hash, k, i, cap);
 misc_ASSERT(k < cap);
      } while(++i != cap);
      data[h].occ = ohash_ENTRY_OCCUPIED;
      data[h].key = Key;
      data[h].data = Data;
      data[h].hash = Hash;
      ohash_DecreaseNumberDeleted(Ohash);
      ohash_IncreaseNumberElems(Ohash);
      *Inserted = TRUE;
      return h;
    case ohash_ENTRY_OCCUPIED:
      if (data[h].hash == Hash && (elemeqenv ? elemeqfctenv(Key, data[h].key, elemeqenv) : elemeqfct(Key, data[h].key))) {
 return h;
      }
      break;
    default:
      break;
    }
    h = ohash_LinearProbe(Hash, h, i, cap);
    misc_ASSERT(h < cap);
  } while(++i != cap);
  misc_StartErrorReport();
  misc_ErrorReport("\n In %s: should be unreachable", __func__);
  misc_FinishErrorReport();
  return UINT32_MAX;
}
OHASH ohash_InsertDirectly(OHASH Ohash, OHASH_KEY_TYPE Key,
      OHASH_DATA_TYPE Data,
      OHASH_HASH_TYPE Hash,
      OHASH_DELETE_KEY_FCT DeleteKey,
      OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if((ohash_GetNumberElems(Ohash) + ohash_GetNumberDeleted(Ohash)) >= ohash_GetCapacity(Ohash)){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: map is already full", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t idx;
  BOOL inserted;
  OHASH_ENTRY data;
  data = ohash_GetData(Ohash);
  idx = ohash_SearchOrInsertDirectly(Ohash,Key,Data,Hash,&inserted);
  if(!inserted){
    if (DeleteKey)
      DeleteKey(ohash_GetMemory(Ohash), data[idx].key);
    if (DeleteData)
      DeleteData(ohash_GetMemory(Ohash), data[idx].data);
    data[idx].occ = ohash_ENTRY_OCCUPIED;
    data[idx].key = Key;
    data[idx].data = Data;
    data[idx].hash = Hash;
  }
  return Ohash;
}
OHASH ohash_Cleanup(OHASH Ohash)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  OHASH newhash;
  uint32_t i, oldcap;
#ifdef SPASS_CHECK
  uint32_t elements, deleted;
  elements = 0;
  deleted = 0;
#endif
  oldcap = ohash_GetCapacity(Ohash);
  newhash = ohash_CreateGeneral(ohash_GetMemory(Ohash), oldcap, ohash_GetHashFct(Ohash), ohash_GetElemEqFct(Ohash),ohash_GetElemEqFctEnv(Ohash), ohash_GetElemEqEnv(Ohash));
  for(i = 0; i < oldcap; i++){
    if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_OCCUPIED){
      newhash = ohash_InsertDirectly(newhash, ohash_GetKeyAtIndex(Ohash,i), ohash_GetDataAtIndex(Ohash,i), ohash_GetHashAtIndex(Ohash,i), NULL, NULL);
#ifdef SPASS_CHECK
      elements++;
#endif
    }
#ifdef SPASS_CHECK
    else if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_DELETED){
      deleted++;
    }
#endif
  }
#ifdef SPASS_CHECK
  if(ohash_GetNumberElems(Ohash) != elements){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of occupied entries was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberElems(Ohash), elements);
    misc_FinishErrorReport();
  }
  if(ohash_GetNumberDeleted(Ohash) != deleted){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of entries marked as deleted was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberDeleted(Ohash), deleted);
    misc_FinishErrorReport();
  }
#endif
  ohash_Delete(Ohash, NULL, NULL);
  return newhash;
}
OHASH ohash_Extend(OHASH Ohash)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  OHASH newhash;
  uint32_t i, newcap, oldcap;
#ifdef SPASS_CHECK
  uint32_t elements, deleted;
  elements = 0;
  deleted = 0;
#endif
  oldcap = ohash_GetCapacity(Ohash);
  newcap = oldcap*2;
#ifdef SPASS_CHECK
  if(oldcap >= newcap){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: extending the capacity caused an integer overflow.", __func__);
    misc_FinishErrorReport();
  }
#endif
  newhash = ohash_CreateGeneral(ohash_GetMemory(Ohash), newcap, ohash_GetHashFct(Ohash), ohash_GetElemEqFct(Ohash),ohash_GetElemEqFctEnv(Ohash), ohash_GetElemEqEnv(Ohash));
  for(i = 0; i < oldcap; i++){
    if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_OCCUPIED){
      newhash = ohash_InsertDirectly(newhash, ohash_GetKeyAtIndex(Ohash,i), ohash_GetDataAtIndex(Ohash,i), ohash_GetHashAtIndex(Ohash,i), NULL, NULL);
#ifdef SPASS_CHECK
      elements++;
#endif
    }
#ifdef SPASS_CHECK
    else if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_DELETED){
      deleted++;
    }
#endif
  }
#ifdef SPASS_CHECK
  if(ohash_GetNumberElems(Ohash) != elements){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of occupied entries was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberElems(Ohash), elements);
    misc_FinishErrorReport();
  }
  if(ohash_GetNumberDeleted(Ohash) != deleted){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: the number of entries marked as deleted was wrong. (marked: %"PRIu32", actual: %"PRIu32")", __func__, ohash_GetNumberDeleted(Ohash), deleted);
    misc_FinishErrorReport();
  }
#endif
  ohash_Delete(Ohash, NULL, NULL);
  return newhash;
}
OHASH ohash_Insert(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_DATA_TYPE Data,
     OHASH_DELETE_KEY_FCT DeleteKey,
     OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  if (ohash_GetNumberElems(Ohash) + ohash_GetNumberDeleted(Ohash) >= ohash_GetResizeThreshold(Ohash)){
    Ohash = ohash_Extend(Ohash);
  }
  Ohash = ohash_InsertDirectly(Ohash, Key, Data, ohash_GetHashFct(Ohash)(Key),
          NULL, NULL);
  return Ohash;
}
OHASH ohash_InsertWithHash(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_HASH_TYPE Hash, OHASH_DATA_TYPE Data,
     OHASH_DELETE_KEY_FCT DeleteKey,
     OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) != NULL && ohash_GetHashFct(Ohash)(Key) != Hash){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash has an internal hash function and the external hash value was not equivalent to the one computed with the function.", __func__);
    misc_FinishErrorReport();
  }
#endif
  if (ohash_GetNumberElems(Ohash) + ohash_GetNumberDeleted(Ohash) >= ohash_GetResizeThreshold(Ohash)){
    Ohash = ohash_Extend(Ohash);
  }
  Ohash = ohash_InsertDirectly(Ohash, Key, Data, Hash, NULL, NULL);
  return Ohash;
}
OHASH ohash_Remove(OHASH Ohash, OHASH_KEY_TYPE Key,
     OHASH_DELETE_KEY_FCT DeleteKey,
     OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  return ohash_RemoveWithHash(Ohash, Key, ohash_GetHashFct(Ohash)(Key),
         DeleteKey, DeleteData);
}
OHASH ohash_RemoveWithHash(OHASH Ohash, OHASH_KEY_TYPE Key,
      OHASH_HASH_TYPE Hash,
      OHASH_DELETE_KEY_FCT DeleteKey,
      OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) != NULL && ohash_GetHashFct(Ohash)(Key) != Hash){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash has an internal hash function and the external hash value was not equivalent to the one computed with the function.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t h,i,cap;
  OHASH_ENTRY data;
  OHASH_HASH_TYPE keyhash;
  OHASH_DATA_TYPE elemeqenv;
  i = 0;
  data = ohash_GetData(Ohash);
  cap = ohash_GetCapacity(Ohash);
  elemeqenv = ohash_GetElemEqEnv(Ohash);
  keyhash = Hash;
  h = ohash_InitLinearProbe(keyhash,cap);
  misc_ASSERT(h < cap);
  do {
    misc_ASSERT(h < ohash_GetCapacity(Ohash));
    if(data[h].occ == ohash_ENTRY_OCCUPIED &&
       data[h].hash == keyhash &&
       (elemeqenv ? ohash_GetElemEqFctEnv(Ohash)(Key, data[h].key, elemeqenv) : ohash_GetElemEqFct(Ohash)(Key, data[h].key))) {
      if (DeleteKey)
        DeleteKey(ohash_GetMemory(Ohash), data[h].key);
      if (DeleteData)
        DeleteData(ohash_GetMemory(Ohash), data[h].data);
      data[h].occ = ohash_ENTRY_DELETED;
      data[h].key = (intptr_t)NULL;
      data[h].data = (intptr_t)NULL;
      data[h].hash = 0;
      ohash_DecreaseNumberElems(Ohash);
      ohash_IncreaseNumberDeleted(Ohash);
      if(ohash_GetNumberDeleted(Ohash) >= ohash_GetCleanupThreshold(Ohash)){
 return ohash_Cleanup(Ohash);
      }else{
 return Ohash;
      }
    }else if(data[h].occ == ohash_ENTRY_EMPTY){
      return Ohash;
    }
    h = ohash_LinearProbe(keyhash, h, i, cap);
    misc_ASSERT(h < cap);
  } while(++i != cap);
  misc_StartErrorReport();
  misc_ErrorReport("\n In %s: should be unreachable", __func__);
  misc_FinishErrorReport();
  return Ohash;
}
OHASH ohash_RemoveIfTrue(OHASH Ohash,
    OHASH_FILTER_FCT Filter,
    intptr_t State,
    OHASH_DELETE_KEY_FCT DeleteKey,
    OHASH_DELETE_DATA_FCT DeleteData)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(Filter == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Filter was NULL.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t i,cap;
  OHASH_ENTRY data;
  data = ohash_GetData(Ohash);
  cap = ohash_GetCapacity(Ohash);
  for(i = 0; i < cap; i++){
    if(data[i].occ == ohash_ENTRY_OCCUPIED &&
       Filter(State,data[i].key,data[i].data)) {
      if (DeleteKey)
        DeleteKey(ohash_GetMemory(Ohash), data[i].key);
      if (DeleteData)
        DeleteData(ohash_GetMemory(Ohash), data[i].data);
      data[i].occ = ohash_ENTRY_DELETED;
      data[i].key = (intptr_t)NULL;
      data[i].data = (intptr_t)NULL;
      data[i].hash = 0;
      ohash_DecreaseNumberElems(Ohash);
      ohash_IncreaseNumberDeleted(Ohash);
    }
  }
  if(ohash_GetNumberDeleted(Ohash) >= ohash_GetCleanupThreshold(Ohash)){
    return ohash_Cleanup(Ohash);
  }else{
    return Ohash;
  }
}
uint32_t ohash_SearchIdx(OHASH Ohash, OHASH_KEY_TYPE Key)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  return ohash_SearchIdxWithHash(Ohash, Key, ohash_GetHashFct(Ohash)(Key));
}
uint32_t ohash_SearchIdxWithHash(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_HASH_TYPE Hash)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) != NULL && ohash_GetHashFct(Ohash)(Key) != Hash){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash has an internal hash function and the external hash value was not equivalent to the one computed with the function.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t h, i, cap;
  OHASH_HASH_TYPE keyhash;
  OHASH_ELEM_EQUAL elemeqfct;
  OHASH_ELEM_EQUAL_ENV elemeqfctenv;
  OHASH_DATA_TYPE elemeqenv;
  keyhash = Hash;
  elemeqfct = ohash_GetElemEqFct(Ohash);
  elemeqfctenv = ohash_GetElemEqFctEnv(Ohash);
  elemeqenv = ohash_GetElemEqEnv(Ohash);
  cap = ohash_GetCapacity(Ohash);
  i = 0;
  h = ohash_InitLinearProbe(keyhash,cap);
  misc_ASSERT(h < cap);
  do {
    if(ohash_GetOccupancyAtIndex(Ohash,h) == ohash_ENTRY_OCCUPIED &&
       ohash_GetHashAtIndex(Ohash,h) == keyhash &&
       (elemeqenv ? elemeqfctenv(Key, ohash_GetKeyAtIndex(Ohash,h), elemeqenv) : elemeqfct(Key, ohash_GetKeyAtIndex(Ohash,h)))) {
      return h;
    }else if(ohash_GetOccupancyAtIndex(Ohash,h) == ohash_ENTRY_EMPTY){
      return UINT32_MAX;
    }
    h = ohash_LinearProbe(keyhash, h, i, cap);
    misc_ASSERT(h < cap);
  } while(++i != cap);
  misc_StartErrorReport();
  misc_ErrorReport("\n In %s: should be unreachable", __func__);
  misc_FinishErrorReport();
  return UINT32_MAX;
}
OHASH_DATA_TYPE ohash_Search(OHASH Ohash, OHASH_KEY_TYPE Key)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t idx;
  idx = ohash_SearchIdxWithHash(Ohash,Key,ohash_GetHashFct(Ohash)(Key));
  if(idx == UINT32_MAX){
    return (OHASH_DATA_TYPE)NULL;
  }else{
    return ohash_GetDataAtIndex(Ohash,idx);
  }
}
OHASH_DATA_TYPE ohash_SearchWithHash(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_HASH_TYPE Hash)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) != NULL && ohash_GetHashFct(Ohash)(Key) != Hash){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash has an internal hash function and the external hash value was not equivalent to the one computed with the function.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t idx;
  idx = ohash_SearchIdxWithHash(Ohash,Key,Hash);
  if(idx == UINT32_MAX){
    return (OHASH_DATA_TYPE)NULL;
  }else{
    return ohash_GetDataAtIndex(Ohash,idx);
  }
}
OHASH_KEY_TYPE ohash_SearchKey(OHASH Ohash, OHASH_KEY_TYPE Key)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t idx;
  idx = ohash_SearchIdxWithHash(Ohash,Key,ohash_GetHashFct(Ohash)(Key));
  if(idx == UINT32_MAX){
    return (OHASH_KEY_TYPE)NULL;
  }else{
    return ohash_GetKeyAtIndex(Ohash,idx);
  }
}
OHASH_KEY_TYPE ohash_SearchKeyWithHash(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_HASH_TYPE Hash)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) != NULL && ohash_GetHashFct(Ohash)(Key) != Hash){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash has an internal hash function and the external hash value was not equivalent to the one computed with the function.", __func__);
    misc_FinishErrorReport();
  }
#endif
  uint32_t idx;
  idx = ohash_SearchIdxWithHash(Ohash,Key,Hash);
  if(idx == UINT32_MAX){
    return (OHASH_KEY_TYPE)NULL;
  }else{
    return ohash_GetKeyAtIndex(Ohash,idx);
  }
}
OHASH ohash_SearchOrInsert(OHASH Ohash, OHASH_KEY_TYPE Key, OHASH_DATA_TYPE Data, BOOL* Inserted, uint32_t* Idx)
{
#ifdef SPASS_CHECK
  if(Ohash == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Ohash was NULL", __func__);
    misc_FinishErrorReport();
  }
  if(ohash_GetHashFct(Ohash) == NULL){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: HashFct was NULL so external hash values have to be supplied.", __func__);
    misc_FinishErrorReport();
  }
#endif
  if (ohash_GetNumberElems(Ohash) + ohash_GetNumberDeleted(Ohash) >= ohash_GetResizeThreshold(Ohash)){
    Ohash = ohash_Extend(Ohash);
  }
  *Idx = ohash_SearchOrInsertDirectly(Ohash, Key, Data, ohash_GetHashFct(Ohash)(Key),Inserted);
  return Ohash;
}
ARRAY ohash_CreateDataArr(MEMORY Mem, OHASH Ohash, ARRAY * Data)
{
  *Data = array_Clean(*Data);
  return ohash_AppendDataToArr(Mem, Ohash, Data);
}
ARRAY ohash_AppendDataToArr(MEMORY Mem, OHASH Ohash, ARRAY * Data)
{
  uint32_t i, cap;
  cap = ohash_GetCapacity(Ohash);
  for (i = 0; i < cap; i++) {
    if (ohash_GetOccupancyAtIndex(Ohash, i) == ohash_ENTRY_OCCUPIED) {
      *Data = array_Push(Mem, *Data, (intptr_t)ohash_GetDataAtIndex(Ohash, i));
    }
  }
  return *Data;
}
void ohash_CreateKeyAndDataArr(MEMORY Mem, OHASH Ohash, ARRAY * Keys, ARRAY * Data)
{
  uint32_t i, cap;
  cap = ohash_GetCapacity(Ohash);
  *Keys = array_Clean(*Keys);
  *Data = array_Clean(*Data);
  for (i = 0; i < cap; i++) {
    if (ohash_GetOccupancyAtIndex(Ohash, i) == ohash_ENTRY_OCCUPIED) {
      *Keys = array_Add(Mem, *Keys, (intptr_t)ohash_GetKeyAtIndex(Ohash, i));
      *Data = array_Add(Mem, *Data, (intptr_t)ohash_GetDataAtIndex(Ohash, i));
    }
  }
}
uint32_t ohash_InitLinearProbe(OHASH_HASH_TYPE Hash, uint32_t Capacity)
{
  return Hash & (Capacity - 1);
}
uint32_t ohash_LinearProbe(OHASH_HASH_TYPE Hash, uint32_t LastIdx, uint32_t Iteration, uint32_t Capacity)
{
  return (LastIdx+1) & (Capacity - 1);
}
uint32_t ohash_InitQuadraticProbe(OHASH_HASH_TYPE Hash, uint32_t Capacity)
{
  return Hash & (Capacity - 1);
}
uint32_t ohash_QuadraticProbe(OHASH_HASH_TYPE Hash, uint32_t LastIdx, uint32_t Iteration, uint32_t Capacity)
{
  return (LastIdx+Iteration+1) & (Capacity - 1);
}
void ohash_FPrint(FILE* File, OHASH Ohash)
{
  uint32_t cap, i;
  cap = ohash_GetCapacity(Ohash);
  fprintf(File, "Ohash Cap:%"PRIu32" Elm:%"PRIu32,
   cap, ohash_GetNumberElems(Ohash));
  for(i = 0; i < cap; i++) {
    if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_OCCUPIED) {
      fprintf(File, " (%" PRIiPTR ", %" PRIiPTR ")",
       (intptr_t)ohash_GetKeyAtIndex(Ohash,i),
       (intptr_t)ohash_GetDataAtIndex(Ohash,i));
    }
  }
}
void ohash_Print(OHASH Ohash)
{
  ohash_FPrint(stdout, Ohash);
}
void ohash_FPrintAll(FILE* File, OHASH Ohash)
{
  uint32_t cap, i;
  cap = ohash_GetCapacity(Ohash);
  fprintf(File, "Ohash Cap:%"PRIu32" Elm:%"PRIu32" Del:%"PRIu32,
   cap, ohash_GetNumberElems(Ohash), ohash_GetNumberDeleted(Ohash));
  for(i = 0; i < cap; i++) {
    if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_OCCUPIED) {
      fprintf(File, " (%" PRIiPTR ", %" PRIiPTR ")",
       (intptr_t)ohash_GetKeyAtIndex(Ohash,i),
       (intptr_t)ohash_GetDataAtIndex(Ohash,i));
    }else if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_DELETED) {
      fprintf(File, " (DELETED)");
    }else if(ohash_GetOccupancyAtIndex(Ohash,i) == ohash_ENTRY_EMPTY) {
      fprintf(File, " (EMPTY)");
    }
  }
}
void ohash_PrintAll(OHASH Ohash)
{
  ohash_FPrintAll(stdout, Ohash);
}
OHASH_HASH_TYPE ohash_StringHash(const OHASH_KEY_TYPE S)
{
  char const* i;
  uint32_t hash;
  hash = 2166136261U;
  for (i = (char const*)S; *i != '\0'; ++i) {
    hash = (hash ^ (unsigned char)*i) * 16777619U;
  }
  return (OHASH_HASH_TYPE)hash;
}
OHASH_HASH_TYPE ohash_Integer(const intptr_t H)
{
  uint32_t x;
  x = (uint32_t)H;
  x ^= (x >> 20) ^ (x >> 12);
  return (OHASH_HASH_TYPE) (x ^ (x >> 7) ^ (x >> 4));
}
OHASH_HASH_TYPE ohash_IntegerNew(const intptr_t K)
{
  uint32_t x;
  x = (uint32_t)K;
  x = (x + 0x7ed55d16) + (x<<12);
  x = (x ^ 0xc761c23c) ^ (x>>19);
  x = (x + 0x165667b1) + (x<<5);
  x = (x + 0xd3a2646c) ^ (x<<9);
  x = (x + 0xfd7046c5) + (x<<3);
  x = (x ^ 0xb55a4f09) ^ (x>>16);
  return (OHASH_HASH_TYPE) x;
}
OHASH_HASH_TYPE ohash_DummyHash(const intptr_t H)
{
  return (OHASH_HASH_TYPE) 0xd3a2646c;
}
BOOL ohash_IdEq(const intptr_t X, const intptr_t Y)
{
  return X==Y;
}
BOOL ohash_StringEq(const intptr_t X, const intptr_t Y)
{
  unsigned i;
  char *x, *y;
  i = 0;
  x = (char *)X;
  y = (char *)Y;
  while (x[i] == y[i] && x[i] != '\0')
    i++;
  return (x[i] == y[i]);
}
