Updating built in Io code to use += instead of x = x + y
[io/quag.git] / libs / basekit / source / PHash.c
blobf9b44e365eaa6b0f77ffa1def62636dbbf906dea
1 /*#io
2 docCopyright("Steve Dekorte", 2002)
3 docCopyright("Marc Fauconneau", 2007)
4 docLicense("BSD revised")
5 */
7 #define PHASH_C
8 #include "PHash.h"
9 #undef PHASH_C
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
14 void PHash_print(PHash* 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", PHash_maxLoops(self));
23 printf("self->maxKeys = %d\n", PHash_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", PHash_memorySize(self));
29 printf("\ndensity : %f \n", (self->numKeys*sizeof(PHashRecord))/(double)PHash_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 PHashRecord *record = PHASH_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 PHash_tableInit_(PHash* self, int log2tableSize)
61 if (log2tableSize > 20)
62 printf("ouuups");
63 self->log2tableSize = log2tableSize;
64 self->tableSize = 1<<self->log2tableSize;
65 self->records = (PHashRecord *)io_calloc(1, sizeof(PHashRecord) * self->tableSize * 2);
66 memset(self->records, 0x0, sizeof(PHashRecord) * self->tableSize * 2);
67 self->mask = self->tableSize-1;
70 PHash *PHash_new(void)
72 PHash *self = (PHash *)io_calloc(1, sizeof(PHash));
73 memset(self, 0x0, sizeof(PHash));
74 self->numKeys = 0;
75 PHash_tableInit_(self, 1);
76 //printf("ok");
77 return self;
80 PHash *PHash_clone(PHash *self)
82 PHash *child = PHash_new();
83 PHash_copy_(child, self);
84 return child;
87 void PHash_free(PHash *self)
89 io_free(self->records);
90 io_free(self);
93 size_t PHash_memorySize(PHash *self)
95 return sizeof(PHash) + (self->tableSize * 2 * sizeof(PHashRecord));
98 void PHash_compact(PHash *self)
100 printf("need to implement PHash_compact\n");
103 void PHash_copy_(PHash *self, PHash *other)
105 PHashRecord *records = self->records;
106 memcpy(self, other, sizeof(PHash));
107 self->records = (PHashRecord *)io_realloc(records, sizeof(PHashRecord) * self->tableSize * 2);
108 memcpy(self->records, other->records, sizeof(PHashRecord) * self->tableSize * 2);
111 /* this is where our cuckoo acts :
112 it kicks records out of nests until it finds an empty nest or gets tired
113 returns the empty nest if found, or NULL if it is too tired
115 PHashRecord *PHash_cuckoo_(PHash *self, PHashRecord* thisRecord)
117 unsigned int hash;
118 PHashRecord* record;
119 record = PHash_recordAt_(self, thisRecord->key);
121 if (record != &self->nullRecord && NULL == record->key)
122 return record;
123 else
125 if (PHashKey_isEqual_(thisRecord->key, record->key))
127 return record;
129 else
131 int i;
132 // to balance load
133 if (self->balance)
135 self->balance = 0;
137 hash = PHash_hash_more(self, PHash_hash(self, thisRecord->key));
138 record = PHASH_RECORDS_AT_HASH_(self, 1, hash);
139 if (NULL == record->key)
140 return record;
141 else
142 PHashRecord_swap(record, thisRecord);
144 if (PHashKey_isEqual_(thisRecord->key, record->key))
145 return record;
147 self->balance = 1;
149 for (i = 0; i < PHash_maxLoops(self); i++)
151 hash = PHash_hash(self, thisRecord->key);
152 record = PHASH_RECORDS_AT_HASH_(self, 0, hash);
153 if (NULL == record->key)
154 return record;
155 else
156 PHashRecord_swap(record, thisRecord);
158 if (PHashKey_isEqual_(thisRecord->key, record->key))
159 return record;
161 hash = PHash_hash_more(self, PHash_hash(self, thisRecord->key));
162 record = PHASH_RECORDS_AT_HASH_(self, 1, hash);
163 if (NULL == record->key)
164 return record;
165 else
166 PHashRecord_swap(record, thisRecord);
168 if (PHashKey_isEqual_(thisRecord->key, record->key))
169 return record;
172 // the cuckoo is tired ^^
173 return NULL;
177 return NULL;
180 void PHash_grow(PHash *self)
182 unsigned int oldTableSize = self->tableSize;
183 PHashRecord* oldRecords = self->records;
185 self->records = NULL;
186 while (self->records == NULL)
188 unsigned int i;
190 PHash_tableInit_(self, self->log2tableSize + 1);
192 // enumerate old records
194 i = 0;
195 while (i < oldTableSize*2)
197 PHashRecord thisRecord = oldRecords[i];
198 i++;
200 if (thisRecord.key)
202 PHashRecord *record = PHash_cuckoo_(self, &thisRecord);
203 if (!record) // collision
205 io_free(self->records);
206 self->records = NULL;
207 break; // grow & rehash
209 *record = thisRecord;
213 io_free(oldRecords);
216 void PHash_growWithRecord(PHash *self, PHashRecord* thisRecord)
218 // put the value anywhere, PHash_grow will rehash
219 unsigned int i,j;
221 for (j = 0; j < 2; j ++)
222 for (i = 0; i < self->tableSize; i ++)
224 PHashRecord *record = PHASH_RECORDS_AT_(self, j, i);
226 if (record != &self->nullRecord && NULL == record->key)
228 *record = *thisRecord;
229 self->numKeys ++;
230 PHash_grow(self);
231 return;
235 // we can never be there
236 return;
239 void PHash_removeValue_(PHash *self, void *value)
241 PHashRecord *record;
242 int index = 0;
244 while (index < self->tableSize*2)
246 record = self->records + index;
247 index ++;
249 if (record->key && record->value == value)
251 self->numKeys --;
252 memset(record, 0, sizeof(PHashRecord));
253 return;
258 void *PHash_firstKeyForValue_(PHash *self, void *v)
260 unsigned int i,j;
262 for (j = 0; j < 2; j ++)
263 for (i = 0; i < self->tableSize; i ++)
265 PHashRecord *record = PHASH_RECORDS_AT_(self, j, i);
267 if (record->key && record->value == v)
268 return record->key;
270 return NULL;