SystemCall run(block) can now exit the run if it returns false
[io/quag.git] / libs / basekit / source / SHash.c
blob64ddbc12c1f6f1c0c709fe4153e16c575fa7cd61
1 /*#io
2 docCopyright("Steve Dekorte", 2002)
3 docCopyright("Marc Fauconneau", 2007)
4 docLicense("BSD revised")
5 */
7 #define SHASH_C
8 #include "SHash.h"
9 #undef SHASH_C
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
14 void SHash_print(SHash* self)
16 printf("self->log2tableSize = %d\n", self->log2tableSize);
17 printf("self->tableSize = %d\n", self->tableSize);
18 printf("self->numKeys = %d\n", self->numKeys);
20 printf("self->mask = %d\n", self->mask);
21 printf("self->balance = %d\n", self->balance);
22 printf("self->maxLoops = %d\n", SHash_maxLoops(self));
23 printf("self->maxKeys = %d\n", SHash_maxKeys(self));
25 printf("self->nullRecord.key = %d\n", self->nullRecord.key);
26 printf("self->nullRecord.value = %d\n", self->nullRecord.value);
28 printf("\nmemory usage : %d bytes\n", SHash_memorySize(self));
29 printf("\ndensity : %f \n", (self->numKeys*sizeof(SHashRecord))/(double)SHash_memorySize(self));
32 unsigned int i,j;
33 int count[2] = {0,0};
35 for (j = 0; j < 2; j ++)
37 for (i = 0; i < self->tableSize; i ++)
39 SHashRecord *record = SHASH_RECORDS_AT_(self, j, i);
40 if (NULL == record->key)
42 if (NULL == record->value)
43 printf("_");
44 else
45 printf("!");
47 else
49 printf("x");
50 count[j]++;
53 printf("\n");
55 printf("balance : %d / %d [%1.3f]\n", count[0], count[1], (count[0]-count[1])/(double)(count[0]+count[1]) );
59 void SHash_tableInit_(SHash* self, int log2tableSize)
61 if (log2tableSize > 20)
62 printf("ouuups");
63 self->log2tableSize = log2tableSize;
64 self->tableSize = 1<<self->log2tableSize;
65 self->records = (SHashRecord *)io_calloc(1, sizeof(SHashRecord) * self->tableSize * 2);
66 self->mask = self->tableSize-1;
69 SHash *SHash_new(void)
71 SHash *self = (SHash *)io_calloc(1, sizeof(SHash));
72 self->numKeys = 0;
73 SHash_tableInit_(self, 1);
74 //printf("ok");
75 return self;
78 SHash *SHash_clone(SHash *self)
80 SHash *child = SHash_new();
81 SHash_copy_(child, self);
82 return child;
85 void SHash_free(SHash *self)
87 io_free(self->records);
88 io_free(self);
91 size_t SHash_memorySize(SHash *self)
93 return sizeof(SHash) + (self->tableSize * 2 * sizeof(SHashRecord));
96 void SHash_compact(SHash *self)
98 printf("need to implement SHash_compact\n");
101 void SHash_copy_(SHash *self, SHash *other)
103 SHashRecord *records = self->records;
104 memcpy(self, other, sizeof(SHash));
105 self->records = (SHashRecord *)io_realloc(records, sizeof(SHashRecord) * self->tableSize * 2);
106 memcpy(self->records, other->records, sizeof(SHashRecord) * self->tableSize * 2);
109 /* this is where our cuckoo acts :
110 it kicks records out of nests until it finds an empty nest or gets tired
111 returns the empty nest if found, or NULL if it is too tired
113 SHashRecord *SHash_cuckoo_(SHash *self, SHashRecord* thisRecord)
115 unsigned int hash;
116 SHashRecord* record;
117 record = SHash_recordAt_(self, thisRecord->key);
119 if (record != &self->nullRecord && NULL == record->key)
120 return record;
121 else
123 if (SHash_keysAreEqual_(self, thisRecord->key, record->key))
125 return record;
127 else
129 int i;
130 // to balance load
131 if (self->balance)
133 self->balance = 0;
135 hash = SHash_hash_more(self, SHash_hash(self, thisRecord->key));
136 record = SHASH_RECORDS_AT_HASH_(self, 1, hash);
137 if (NULL == record->key)
138 return record;
139 else
140 SHashRecord_swap(record, thisRecord);
142 if (SHash_keysAreEqual_(self, thisRecord->key, record->key))
143 return record;
145 self->balance = 1;
147 for (i = 0; i < SHash_maxLoops(self); i++)
149 hash = SHash_hash(self, thisRecord->key);
150 record = SHASH_RECORDS_AT_HASH_(self, 0, hash);
151 if (NULL == record->key)
152 return record;
153 else
154 SHashRecord_swap(record, thisRecord);
156 if (SHash_keysAreEqual_(self, thisRecord->key, record->key))
157 return record;
159 hash = SHash_hash_more(self, SHash_hash(self, thisRecord->key));
160 record = SHASH_RECORDS_AT_HASH_(self, 1, hash);
161 if (NULL == record->key)
162 return record;
163 else
164 SHashRecord_swap(record, thisRecord);
166 if (SHash_keysAreEqual_(self, thisRecord->key, record->key))
167 return record;
170 // the cuckoo is tired ^^
171 return NULL;
175 return NULL;
178 void SHash_grow(SHash *self)
180 unsigned int oldTableSize = self->tableSize;
181 SHashRecord* oldRecords = self->records;
183 self->records = NULL;
184 while (self->records == NULL)
186 unsigned int i;
188 SHash_tableInit_(self, self->log2tableSize + 1);
190 // enumerate old records
192 i = 0;
193 while (i < oldTableSize*2)
195 SHashRecord thisRecord = oldRecords[i];
196 i++;
198 if (thisRecord.key)
200 SHashRecord *record = SHash_cuckoo_(self, &thisRecord);
201 if (!record) // collision
203 io_free(self->records);
204 self->records = NULL;
205 break; // grow & rehash
207 *record = thisRecord;
211 io_free(oldRecords);
214 void SHash_growWithRecord(SHash *self, SHashRecord* thisRecord)
216 // put the value anywhere, SHash_grow will rehash
217 unsigned int i,j;
219 for (j = 0; j < 2; j ++)
220 for (i = 0; i < self->tableSize; i ++)
222 SHashRecord *record = SHASH_RECORDS_AT_(self, j, i);
224 if (record != &self->nullRecord && NULL == record->key)
226 *record = *thisRecord;
227 self->numKeys ++;
228 SHash_grow(self);
229 return;
233 // we can never be there
234 return;
237 void SHash_removeValue_(SHash *self, void *value)
239 SHashRecord *record;
240 int index = 0;
242 while (index < self->tableSize*2)
244 record = self->records + index;
245 index ++;
247 if (record->key && record->value == value)
249 self->numKeys --;
250 memset(record, 0, sizeof(SHashRecord));
251 return;
256 void *SHash_firstKeyForValue_(SHash *self, void *v)
258 unsigned int i,j;
260 for (j = 0; j < 2; j ++)
261 for (i = 0; i < self->tableSize; i ++)
263 SHashRecord *record = SHASH_RECORDS_AT_(self, j, i);
265 if (record->key && record->value == v)
266 return record->key;
268 return NULL;