1) tweak hash tables
[IRC.git] / Robust / src / Runtime / DSTM / interface / clookup.c
1 #include "clookup.h"
2 #define INLINE    inline __attribute__((always_inline))
3
4 chashtable_t *chashCreate(unsigned int size, double loadfactor) {
5   chashtable_t *ctable;
6   chashlistnode_t *nodes;
7   int i;
8
9   if((ctable = calloc(1, sizeof(chashtable_t))) == NULL) {
10     printf("Calloc error %s %d\n", __FILE__, __LINE__);
11     return NULL;
12   }
13
14   // Allocate space for the hash table
15   if((nodes = calloc(size, sizeof(chashlistnode_t))) == NULL) {
16     printf("Calloc error %s %d\n", __FILE__, __LINE__);
17     free(ctable);
18     return NULL;
19   }
20
21   ctable->table = nodes;
22   ctable->loadfactor = loadfactor;
23   ctable->size = size;
24   ctable->threshold=size*loadfactor;
25   ctable->mask = (size << 1)-1;
26   ctable->numelements = 0; // Initial number of elements in the hash
27
28
29   return ctable;
30 }
31
32 //Finds the right bin in the hash table
33 static INLINE unsigned int chashFunction(chashtable_t *table, unsigned int key) {
34   return ( key & (table->mask))>>1; //throw away low order bit
35 }
36
37 //Store objects and their pointers into hash
38 unsigned int chashInsert(chashtable_t *table, unsigned int key, void *val) {
39   unsigned int newsize;
40   int index;
41   chashlistnode_t *ptr, *node;
42
43   if(table->numelements > (table->threshold)) {
44     //Resize
45     newsize = table->size << 1;
46     chashResize(table,newsize);
47   }
48
49   ptr = table->table;
50   table->numelements++;
51   index = chashFunction(table, key);
52 #ifdef DEBUG
53   printf("chashInsert(): DEBUG -> index = %d, key = %d, val = %x\n", index, key, val);
54 #endif
55   if(ptr[index].next == NULL && ptr[index].key == 0) {  // Insert at the first position in the hashtable
56     ptr[index].key = key;
57     ptr[index].val = val;
58   } else { // Insert in the beginning of linked list
59     if ((node = calloc(1, sizeof(chashlistnode_t))) == NULL) {
60       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
61       return 1;
62     }
63     node->key = key;
64     node->val = val;
65     node->next = ptr[index].next;
66     ptr[index].next = node;
67   }
68   return 0;
69 }
70
71 // Search for an address for a given oid
72 INLINE void * chashSearch(chashtable_t *table, unsigned int key) {
73   //REMOVE HASH FUNCTION CALL TO MAKE SURE IT IS INLINED HERE
74   chashlistnode_t *node = &table->table[(key & table->mask)>>1];
75
76   do {
77     if(node->key == key) {
78       return node->val;
79     }
80     node = node->next;
81   } while(node != NULL);
82
83   return NULL;
84 }
85
86 unsigned int chashRemove(chashtable_t *table, unsigned int key) {
87   return chashRemove2(table, key)==NULL;
88
89 }
90
91 void * chashRemove2(chashtable_t *table, unsigned int key) {
92   int index;
93   chashlistnode_t *curr, *prev;
94   chashlistnode_t *ptr, *node;
95   void *value;
96
97   ptr = table->table;
98   index = chashFunction(table,key);
99   curr = &ptr[index];
100
101   for (; curr != NULL; curr = curr->next) {
102     if (curr->key == key) {         // Find a match in the hash table
103       table->numelements--;  // Decrement the number of elements in the global hashtable
104       if ((curr == &ptr[index]) && (curr->next == NULL)) {  // Delete the first item inside the hashtable with no linked list of chashlistnode_t
105         curr->key = 0;
106         value=curr->val;
107         curr->val = NULL;
108       } else if ((curr == &ptr[index]) && (curr->next != NULL)) { //Delete the first item with a linked list of chashlistnode_t  connected
109         curr->key = curr->next->key;
110         value=curr->val;
111         curr->val = curr->next->val;
112         node = curr->next;
113         curr->next = curr->next->next;
114         free(node);
115       } else {                                          // Regular delete from linked listed
116         prev->next = curr->next;
117         value=curr->val;
118         free(curr);
119       }
120       return value;
121     }
122     prev = curr;
123   }
124   return NULL;
125 }
126
127 unsigned int chashResize(chashtable_t *table, unsigned int newsize) {
128   chashlistnode_t *node, *ptr, *curr, *next;    // curr and next keep track of the current and the next chashlistnodes in a linked list
129   unsigned int oldsize;
130   int isfirst;    // Keeps track of the first element in the chashlistnode_t for each bin in hashtable
131   int i,index;
132   chashlistnode_t *newnode;
133
134   ptr = table->table;
135   oldsize = table->size;
136
137   if((node = calloc(newsize, sizeof(chashlistnode_t))) == NULL) {
138     printf("Calloc error %s %d\n", __FILE__, __LINE__);
139     return 1;
140   }
141
142   table->table = node;          //Update the global hashtable upon resize()
143   table->size = newsize;
144   table->threshold = newsize * table->loadfactor;
145   table->mask = (newsize << 1)-1;
146
147   for(i = 0; i < oldsize; i++) {                        //Outer loop for each bin in hash table
148     curr = &ptr[i];
149     isfirst = 1;
150     while (curr != NULL) {                      //Inner loop to go through linked lists
151       if (curr->key == 0) {             //Exit inner loop if there the first element for a given bin/index is NULL
152         break;                  //key = val =0 for element if not present within the hash table
153       }
154       next = curr->next;
155
156       index = chashFunction(table, curr->key);
157 #ifdef DEBUG
158       printf("DEBUG(resize) -> index = %d, key = %d, val = %x\n", index, curr->key, curr->val);
159 #endif
160       // Insert into the new table
161       if(table->table[index].next == NULL && table->table[index].key == 0) {
162         table->table[index].key = curr->key;
163         table->table[index].val = curr->val;
164         table->numelements++;
165       } else {
166         if((newnode = calloc(1, sizeof(chashlistnode_t))) == NULL) {
167           printf("Calloc error %s, %d\n", __FILE__, __LINE__);
168           return 1;
169         }
170         newnode->key = curr->key;
171         newnode->val = curr->val;
172         newnode->next = table->table[index].next;
173         table->table[index].next = newnode;
174         table->numelements++;
175       }
176
177       //free the linked list of chashlistnode_t if not the first element in the hash table
178       if (isfirst != 1) {
179         free(curr);
180       }
181
182       isfirst = 0;
183       curr = next;
184     }
185   }
186
187   free(ptr);            //Free the memory of the old hash table
188   return 0;
189 }
190
191 //Delete the entire hash table
192 void chashDelete(chashtable_t *ctable) {
193   int i, isFirst;
194   chashlistnode_t *ptr, *curr, *next;
195   ptr = ctable->table;
196
197   for(i=0 ; i<ctable->size ; i++) {
198     curr = &ptr[i];
199     isFirst = 1 ;
200     while(curr  != NULL) {
201       next = curr->next;
202       if(isFirst != 1) {
203         free(curr);
204       }
205       isFirst = 0;
206       curr = next;
207     }
208   }
209
210   free(ptr);
211   ptr = NULL;
212   free(ctable);
213   ctable = NULL;
214 }