1 //metadoc CHash copyright Steve Dekorte 2009
2 //metadoc CHash license BSD revised
3 //metadoc CHash notes Suggestion to use cuckoo hash and original implementation by Marc Fauconneau
4
5 #define CHASH_C
6 #include "CHash.h"
7 #undef CHASH_C
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12
CHash_new(void)13 CHash *CHash_new(void)
14 {
15 CHash *self = (CHash *)io_calloc(1, sizeof(CHash));
16 CHash_setSize_(self, 8);
17 return self;
18 }
19
CHash_copy_(CHash * self,const CHash * other)20 void CHash_copy_(CHash *self, const CHash *other)
21 {
22 io_free(self->records);
23 memcpy(self, other, sizeof(CHash));
24 self->records = malloc(self->size * sizeof(CHashRecord));
25 memcpy(self->records, other->records, self->size * sizeof(CHashRecord));
26 }
27
CHash_clone(CHash * self)28 CHash *CHash_clone(CHash *self)
29 {
30 CHash *other = CHash_new();
31 CHash_copy_(other, self);
32 return other;
33 }
34
CHash_setSize_(CHash * self,size_t size)35 void CHash_setSize_(CHash *self, size_t size)
36 {
37 self->records = realloc(self->records, size * sizeof(CHashRecord));
38
39 if(size > self->size)
40 {
41 memset(self->records + self->size * sizeof(CHashRecord),
42 0x0, (size - self->size) * sizeof(CHashRecord));
43 }
44
45 self->size = size;
46
47 CHash_updateMask(self);
48 //CHash_show(self);
49 }
50
CHash_updateMask(CHash * self)51 void CHash_updateMask(CHash *self)
52 {
53 self->mask = (intptr_t)(self->size - 1);
54 }
55
CHash_show(CHash * self)56 void CHash_show(CHash *self)
57 {
58 size_t i;
59
60 printf("CHash records:\n");
61 for(i = 0; i < self->size; i++)
62 {
63 CHashRecord *r = CRecords_recordAt_(self->records, i);
64 printf(" %i: %p %p\n", (int)i, r->k, r->v);
65 }
66 }
67
CHash_free(CHash * self)68 void CHash_free(CHash *self)
69 {
70 io_free(self->records);
71 io_free(self);
72 }
73
CHash_setHash1Func_(CHash * self,CHashHashFunc * f)74 void CHash_setHash1Func_(CHash *self, CHashHashFunc *f)
75 {
76 self->hash1 = f;
77 }
78
CHash_setHash2Func_(CHash * self,CHashHashFunc * f)79 void CHash_setHash2Func_(CHash *self, CHashHashFunc *f)
80 {
81 self->hash2 = f;
82 }
83
CHash_setEqualFunc_(CHash * self,CHashEqualFunc * f)84 void CHash_setEqualFunc_(CHash *self, CHashEqualFunc *f)
85 {
86 self->equals = f;
87 }
88
CHash_insert_(CHash * self,CHashRecord * x)89 int CHash_insert_(CHash *self, CHashRecord *x)
90 {
91 int n;
92
93 for (n = 0; n < CHASH_MAXLOOP; n ++)
94 {
95 CHashRecord *r;
96
97 //pos = self->hash1(x->k) & self->mask;
98 //printf("1 x->k = %p-> %i\n", x->k, pos);
99 r = CHash_record1_(self, x->k);
100 CHashRecord_swapWith_(x, r); //x ↔ T1 [h1 (x)]
101 if(x->k == 0x0) { self->keyCount ++; return 0; }
102
103 //pos = self->hash2(x->k) & self->mask;
104 //printf("2 x->k = %p-> %i\n\n", x->k, pos);
105 r = CHash_record2_(self, x->k);
106 CHashRecord_swapWith_(x, r); //x ↔ T2 [h2 (x)]
107 if(x->k == 0x0) { self->keyCount ++; return 0; }
108 }
109
110 if(self->isResizing)
111 {
112 return -1;
113 }
114
115 CHash_grow(self);
116 CHash_at_put_(self, x->k, x->v);
117 return 0;
118 }
119
CHash_insertRecords(CHash * self,unsigned char * oldRecords,size_t oldSize)120 int CHash_insertRecords(CHash *self, unsigned char *oldRecords, size_t oldSize)
121 {
122 size_t i;
123
124 for (i = 0; i < oldSize; i ++)
125 {
126 CHashRecord *r = CRecords_recordAt_(oldRecords, i);
127
128 if (r->k)
129 {
130 if(CHash_at_put_(self, r->k, r->v)) return 1;
131 }
132 }
133 return 0;
134 }
135
CHash_resizeTo_(CHash * self,size_t newSize)136 int CHash_resizeTo_(CHash *self, size_t newSize)
137 {
138 unsigned char *oldRecords = self->records;
139 size_t oldSize = self->size;
140
141 self->isResizing = 1;
142
143 //printf("%p resizeTo %i/%i %i%%\n", (void *)self, self->keyCount, self->size, (int)(100.0*CHash_density(self)));
144
145 do
146 {
147 self->size = newSize;
148 self->records = io_calloc(1, sizeof(CHashRecord) * self->size);
149 self->keyCount = 0;
150 CHash_updateMask(self);
151 if(CHash_insertRecords(self, oldRecords, oldSize) == 0)
152 {
153 self->isResizing = 0;
154 }
155 else
156 {
157 //printf("%p grow collision %i/%i\n", (void *)self, self->keyCount, self->size);
158 newSize *= 2;
159 io_free(self->records);
160 }
161 } while(self->isResizing);
162
163 io_free(oldRecords);
164 return 0;
165 }
166
CHash_grow(CHash * self)167 void CHash_grow(CHash *self)
168 {
169 CHash_resizeTo_(self, self->size * 2);
170 }
171
CHash_shrink(CHash * self)172 void CHash_shrink(CHash *self)
173 {
174 //printf("%p shrink %i/%i\n", (void *)self, self->keyCount, self->size);
175 //CHash_resizeTo_(self, self->size / 2);
176 }
177
CHash_removeKey_(CHash * self,void * k)178 void CHash_removeKey_(CHash *self, void *k)
179 {
180 CHashRecord *r1 = CHash_record1_(self, k);
181 CHashRecord *r2;
182
183 if(r1->k && self->equals(k, r1->k))
184 {
185 r1->k = 0x0;
186 r1->v = 0x0;
187 self->keyCount --;
188 CHash_shrinkIfNeeded(self);
189 return;
190 }
191
192 r2 = CHash_record2_(self, k);
193
194 if(r2->k && self->equals(k, r2->k))
195 {
196 r2->k = 0x0;
197 r2->v = 0x0;
198 self->keyCount --;
199 CHash_shrinkIfNeeded(self);
200 return;
201 }
202 }
203
CHash_clear(CHash * self)204 void CHash_clear(CHash *self)
205 {
206 memset(self->records, 0x0, self->size * sizeof(CHashRecord));
207 self->keyCount = 0;
208 CHash_shrinkIfNeeded(self);
209 }
210
CHash_size(CHash * self)211 size_t CHash_size(CHash *self) // actually the keyCount
212 {
213 return self->keyCount;
214 }
215
216 // ----------------------------
217
CHash_memorySize(CHash * self)218 size_t CHash_memorySize(CHash *self)
219 {
220 return sizeof(CHash) + self->size * sizeof(CHashRecord);
221 }
222
CHash_compact(CHash * self)223 void CHash_compact(CHash *self)
224 {
225 }
226
CHash_density(CHash * self)227 float CHash_density(CHash *self)
228 {
229 float kc = (float)self->keyCount;
230 float size = (float)self->size;
231 return kc/size;
232 }
233
234