You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.4 KiB
238 lines
5.4 KiB
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "lp_lib.h"
|
|
#include "lp_utils.h"
|
|
#include "lp_report.h"
|
|
#include "lp_Hash.h"
|
|
|
|
#ifdef FORTIFY
|
|
# include "lp_fortify.h"
|
|
#endif
|
|
|
|
|
|
#define HASH_START_SIZE 5000 /* Hash table size for row and column name storage */
|
|
#define NUMHASHPRIMES 45
|
|
|
|
STATIC hashtable *create_hash_table(int size, int base)
|
|
{
|
|
int i;
|
|
int HashPrimes[ ] = {
|
|
29, 229, 883, 1671, 2791, 4801, 8629, 10007,
|
|
15289, 25303, 34843, 65269, 99709, 129403, 147673, 166669,
|
|
201403, 222163, 242729, 261431, 303491, 320237, 402761, 501131,
|
|
602309, 701507, 800999, 900551, 1000619, 1100837, 1200359, 1300021,
|
|
1400017, 1500007, 1750009, 2000003, 2500009, 3000017, 4000037, 5000011,
|
|
6000011, 7000003, 8000009, 9000011, 9999991};
|
|
hashtable *ht;
|
|
|
|
/* Find a good size for the hash table */
|
|
if(size < HASH_START_SIZE)
|
|
size = HASH_START_SIZE;
|
|
for(i = 0; i < NUMHASHPRIMES-1; i++)
|
|
if(HashPrimes[i] > size)
|
|
break;
|
|
size = HashPrimes[i];
|
|
|
|
/* Then allocate and initialize memory */
|
|
ht = (hashtable *) calloc(1 , sizeof(*ht));
|
|
ht->table = (hashelem **) calloc(size, sizeof(*(ht->table)));
|
|
ht->size = size;
|
|
ht->base = base;
|
|
ht->count = base-1;
|
|
|
|
return(ht);
|
|
}
|
|
|
|
STATIC void free_hash_item(hashelem **hp)
|
|
{
|
|
free((*hp)->name);
|
|
free(*hp);
|
|
*hp = NULL;
|
|
}
|
|
|
|
STATIC void free_hash_table(hashtable *ht)
|
|
{
|
|
hashelem *hp, *thp;
|
|
|
|
hp = ht->first;
|
|
while(hp != NULL) {
|
|
thp = hp;
|
|
hp = hp->nextelem;
|
|
free_hash_item(&thp);
|
|
}
|
|
free(ht->table);
|
|
free(ht);
|
|
}
|
|
|
|
|
|
/* make a good hash function for any int size */
|
|
/* inspired by Aho, Sethi and Ullman, Compilers ..., p436 */
|
|
#define HASH_1 sizeof(unsigned int)
|
|
#define HASH_2 (sizeof(unsigned int) * 6)
|
|
#define HASH_3 (((unsigned int)0xF0) << ((sizeof(unsigned int) - 1) * CHAR_BIT))
|
|
|
|
STATIC int hashval(const char *string, int size)
|
|
{
|
|
unsigned int result = 0, tmp;
|
|
|
|
for(; *string; string++) {
|
|
result = (result << HASH_1) + *string;
|
|
if((tmp = result & HASH_3) != 0) {
|
|
/* if any of the most significant bits is on */
|
|
result ^= tmp >> HASH_2; /* xor them in in a less significant part */
|
|
result ^= tmp; /* and reset the most significant bits to 0 */
|
|
}
|
|
}
|
|
return(result % size);
|
|
} /* hashval */
|
|
|
|
|
|
STATIC hashelem *findhash(const char *name, hashtable *ht)
|
|
{
|
|
hashelem *h_tab_p;
|
|
for(h_tab_p = ht->table[hashval(name, ht->size)];
|
|
h_tab_p != NULL;
|
|
h_tab_p = h_tab_p->next)
|
|
if(strcmp(name, h_tab_p->name) == 0) /* got it! */
|
|
break;
|
|
return(h_tab_p);
|
|
} /* findhash */
|
|
|
|
|
|
STATIC hashelem *puthash(const char *name, int index, hashelem **list, hashtable *ht)
|
|
{
|
|
hashelem *hp = NULL;
|
|
int hashindex;
|
|
|
|
if(list != NULL) {
|
|
hp = list[index];
|
|
if(hp != NULL)
|
|
list[index] = NULL;
|
|
}
|
|
|
|
if((hp = findhash(name, ht)) == NULL) {
|
|
|
|
hashindex = hashval(name, ht->size);
|
|
hp = (hashelem *) calloc(1, sizeof(*hp));
|
|
allocCHAR(NULL, &hp->name, (int) (strlen(name) + 1), FALSE);
|
|
strcpy(hp->name, name);
|
|
hp->index = index;
|
|
ht->count++;
|
|
if(list != NULL)
|
|
list[index] = hp;
|
|
|
|
hp->next = ht->table[hashindex];
|
|
ht->table[hashindex] = hp;
|
|
if(ht->first == NULL)
|
|
ht->first = hp;
|
|
if(ht->last != NULL)
|
|
ht->last->nextelem = hp;
|
|
ht->last = hp;
|
|
|
|
}
|
|
return(hp);
|
|
}
|
|
|
|
STATIC void drophash(const char *name, hashelem **list, hashtable *ht) {
|
|
hashelem *hp, *hp1, *hp2;
|
|
int hashindex;
|
|
|
|
if((hp = findhash(name, ht)) != NULL) {
|
|
hashindex = hashval(name, ht->size);
|
|
if((hp1 = ht->table[hashindex]) != NULL) {
|
|
hp2 = NULL;
|
|
while((hp1 != NULL) && (hp1 != hp)) {
|
|
hp2 = hp1;
|
|
hp1 = hp1->next;
|
|
}
|
|
if(hp1 == hp) {
|
|
if(hp2 != NULL)
|
|
hp2->next = hp->next;
|
|
else
|
|
ht->table[hashindex] = hp->next;
|
|
}
|
|
|
|
hp1 = ht->first;
|
|
hp2 = NULL;
|
|
while((hp1 != NULL) && (hp1 != hp)) {
|
|
hp2 = hp1;
|
|
hp1 = hp1->nextelem;
|
|
}
|
|
if(hp1 == hp) {
|
|
if(hp2 != NULL)
|
|
hp2->nextelem = hp->nextelem;
|
|
else {
|
|
ht->first = hp->nextelem;
|
|
if (ht->first == NULL)
|
|
ht->last = NULL;
|
|
}
|
|
}
|
|
if(list != NULL)
|
|
list[hp->index] = NULL;
|
|
free_hash_item(&hp);
|
|
ht->count--;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC hashtable *copy_hash_table(hashtable *ht, hashelem **list, int newsize)
|
|
{
|
|
hashtable *copy;
|
|
hashelem *elem, *new_elem;
|
|
|
|
if(newsize < ht->size)
|
|
newsize = ht->size;
|
|
|
|
copy = create_hash_table(newsize, ht->base);
|
|
if (copy != NULL) {
|
|
elem = ht->first;
|
|
while (elem != NULL) {
|
|
if((new_elem = puthash(elem->name, elem->index, list, copy)) == NULL) {
|
|
free_hash_table(copy);
|
|
return(NULL);
|
|
}
|
|
elem = elem ->nextelem;
|
|
}
|
|
}
|
|
|
|
return(copy);
|
|
}
|
|
|
|
STATIC int find_row(lprec *lp, char *name, MYBOOL Unconstrained_rows_found)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if (lp->rowname_hashtab != NULL)
|
|
hp = findhash(name, lp->rowname_hashtab);
|
|
else
|
|
hp = NULL;
|
|
|
|
if (hp == NULL) {
|
|
if(Unconstrained_rows_found) { /* just ignore them in this case */
|
|
return(-1);
|
|
}
|
|
else {
|
|
return(-1);
|
|
}
|
|
}
|
|
return(hp->index);
|
|
}
|
|
|
|
STATIC int find_var(lprec *lp, char *name, MYBOOL verbose)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if (lp->colname_hashtab != NULL)
|
|
hp = findhash(name, lp->colname_hashtab);
|
|
else
|
|
hp = NULL;
|
|
|
|
if (hp == NULL) {
|
|
if(verbose)
|
|
report(lp, SEVERE, "find_var: Unknown variable name '%s'\n", name);
|
|
return(-1);
|
|
}
|
|
return(hp->index);
|
|
}
|
|
|