void SuperHashTable::doDeleteElement(unsigned v)
{
#ifdef HASHSIZE_POWER2
    unsigned hm = (tablesize - 1);
#endif
    unsigned hs = tablesize;
    unsigned vn = v;
    table[v] = NULL;
    while (1)
    {
        vn++;
        if (vn==hs) vn = 0;
        void *et2 = table[vn];
        if (!et2)
            break;
#ifdef HASHSIZE_POWER2
        unsigned vm = getHashFromElement(et2) & hm;
        if (((vn+hs-vm) & hm)>=((vn+hs-v) & hm))  // diff(vn,vm)>=diff(vn,v)
#else
            unsigned vm = getHashFromElement(et2) % hs;
        if (((vn+hs-vm) % hs)>=((vn+hs-v) % hs))  // diff(vn,vm)>=diff(vn,v)
#endif
        {
            table[v] = et2;
            v = vn;
            table[v] = NULL;
        }
    }
    tablecount--;
}
void SuperHashTable::expand(unsigned newsize)
{
    if (newsize < tablesize)
        throw MakeStringException(0, "HashTable expanded beyond 2^32 items");
    void * *newtable = (void * *) checked_malloc(newsize*sizeof(void *),-603);
    memset(newtable,0,newsize*sizeof(void *));
    void * *oldtable = table;
    unsigned i;
    for (i = 0; i < tablesize; i++)
    {
        void *et = oldtable[i];
        if (et)
        {
#ifdef HASHSIZE_POWER2
            unsigned v = getHashFromElement(et) & (newsize - 1);
#else
            unsigned v = getHashFromElement(et) % newsize;
#endif
            while (newtable[v])
            {
                v++;
                if (v==newsize)
                    v = 0;
            }
            newtable[v] = et;
        }
    }
    free(table);
    table = newtable;
    tablesize = newsize;
}
unsigned SuperHashTable::doFindExact(const void *et) const
{
    unsigned i = cache;
    if (i>=tablesize || table[i]!=et)
    {
#ifdef HASHSIZE_POWER2
        i = getHashFromElement(et) & (tablesize - 1);
#else
        i = getHashFromElement(et) % tablesize;
#endif
        unsigned is = i;
        for (;;)
        {
            const void * cur = table[i];
            if (!cur || cur == et)
                break;
            i++;
            if (i==tablesize)
                i = 0;
            if (i==is)
                break;
        }
        setCache(i);
    }
    return i;
}
bool SuperHashTable::doAdd(void * donor, bool replace)
{
    unsigned vs = getHashFromElement(donor);
    unsigned vm = doFind(vs, getFindParam(donor));
    void *et = table[vm];
    if (et)
    {
        if (replace)
        {
            onRemove(et);
            table[vm] = donor;
            onAdd(donor);
            return true;
        }
        else
            return false;
    }
    else
    {
        unsigned tablelim = getTableLimit(tablesize);
        if (tablecount>=tablelim)
        {
            expand();
            vm = doFind(vs, getFindParam(donor));
        }
        tablecount++;
        table[vm] = donor;
        onAdd(donor);
    }
    return true;
}
unsigned SuperHashTable::doFindExact(const void *et) const
{
    unsigned i = cache;
    if (i>=tablesize || table[i]!=et)
    {
#ifdef HASHSIZE_POWER2
        i = getHashFromElement(et) & (tablesize - 1);
#else
        i = getHashFromElement(et) % tablesize;
#endif
        unsigned is = i;
        while (table[i]!=et)
        {
            i++;
            if (i==tablesize)
                i = 0;
            if (!table[i] || i==is)
                break;
        }
    }
    return i;
}
void *SuperHashTable::addOrFind(void * donor)
{
    unsigned vs = getHashFromElement(donor);
    unsigned vm = doFind(vs, getFindParam(donor));
    void *et = table[vm];
    if(!et)
    {
        unsigned tablelim = getTableLimit(tablesize);
        if (tablecount>=tablelim)
        {
            expand();
            vm = doFind(vs, getFindParam(donor));
        }
        tablecount++;
        table[vm] = donor;
        onAdd(donor);
        return donor;
    } 
    return et;
}
void *SuperHashTable::findElement(const void * findEt) const
{
    unsigned vm = doFindElement(getHashFromElement(findEt), findEt);
    void *et = table[vm];
    return et;
}
void SuperHashTable::addNew(void * donor)
{
    addNew(donor, getHashFromElement(donor));
}