2 docCopyright("Steve Dekorte", 2002)
3 docCopyright("Marc Fauconneau", 2007)
4 docLicense("BSD revised")
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
));
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
)
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)
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
));
75 PHash_tableInit_(self
, 1);
80 PHash
*PHash_clone(PHash
*self
)
82 PHash
*child
= PHash_new();
83 PHash_copy_(child
, self
);
87 void PHash_free(PHash
*self
)
89 io_free(self
->records
);
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
)
119 record
= PHash_recordAt_(self
, thisRecord
->key
);
121 if (record
!= &self
->nullRecord
&& NULL
== record
->key
)
125 if (PHashKey_isEqual_(thisRecord
->key
, record
->key
))
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
)
142 PHashRecord_swap(record
, thisRecord
);
144 if (PHashKey_isEqual_(thisRecord
->key
, record
->key
))
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
)
156 PHashRecord_swap(record
, thisRecord
);
158 if (PHashKey_isEqual_(thisRecord
->key
, record
->key
))
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
)
166 PHashRecord_swap(record
, thisRecord
);
168 if (PHashKey_isEqual_(thisRecord
->key
, record
->key
))
172 // the cuckoo is tired ^^
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
)
190 PHash_tableInit_(self
, self
->log2tableSize
+ 1);
192 // enumerate old records
195 while (i
< oldTableSize
*2)
197 PHashRecord thisRecord
= oldRecords
[i
];
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
;
216 void PHash_growWithRecord(PHash
*self
, PHashRecord
* thisRecord
)
218 // put the value anywhere, PHash_grow will rehash
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
;
235 // we can never be there
239 void PHash_removeValue_(PHash
*self
, void *value
)
244 while (index
< self
->tableSize
*2)
246 record
= self
->records
+ index
;
249 if (record
->key
&& record
->value
== value
)
252 memset(record
, 0, sizeof(PHashRecord
));
258 void *PHash_firstKeyForValue_(PHash
*self
, void *v
)
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
)