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