usermode/library/common/cuckoo_hash/CHash.c

00001 //metadoc CHash copyright Steve Dekorte 2009
00002 //metadoc CHash license BSD revised
00003 //metadoc CHash notes Suggestion to use cuckoo hash and original implementation by Marc Fauconneau 
00004 
00005 #define CHASH_C
00006 #include "CHash.h"
00007 #undef CHASH_C
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 
00013 CHash *CHash_new(void)
00014 {
00015         CHash *self = (CHash *)io_calloc(1, sizeof(CHash));
00016         CHash_setSize_(self, 8);
00017         return self;
00018 }
00019 
00020 void CHash_copy_(CHash *self, const CHash *other)
00021 {
00022         io_free(self->records);
00023         memcpy(self, other, sizeof(CHash));
00024         self->records = malloc(self->size * sizeof(CHashRecord));
00025         memcpy(self->records, other->records, self->size * sizeof(CHashRecord));
00026 }
00027 
00028 CHash *CHash_clone(CHash *self)
00029 {
00030         CHash *other = CHash_new();
00031         CHash_copy_(other, self);
00032         return other;
00033 }
00034 
00035 void CHash_setSize_(CHash *self, size_t size)
00036 {
00037         self->records = realloc(self->records, size * sizeof(CHashRecord));
00038         
00039         if(size > self->size)
00040         {               
00041                 memset(self->records + self->size * sizeof(CHashRecord), 
00042                         0x0, (size - self->size) * sizeof(CHashRecord));
00043         }
00044         
00045         self->size = size;
00046         
00047         CHash_updateMask(self);
00048         //CHash_show(self);
00049 }
00050 
00051 void CHash_updateMask(CHash *self)
00052 {
00053         self->mask = (intptr_t)(self->size - 1);
00054 }
00055 
00056 void CHash_show(CHash *self)
00057 {
00058         size_t i;
00059         
00060         printf("CHash records:\n");
00061         for(i = 0; i < self->size; i++)
00062         {
00063                 CHashRecord *r = CRecords_recordAt_(self->records, i);
00064                 printf("  %i: %p %p\n", (int)i, r->k, r->v);
00065         }
00066 }
00067 
00068 void CHash_free(CHash *self)
00069 {
00070         io_free(self->records);
00071         io_free(self);
00072 }
00073 
00074 void CHash_setHash1Func_(CHash *self, CHashHashFunc *f)
00075 {
00076         self->hash1 = f;
00077 }
00078 
00079 void CHash_setHash2Func_(CHash *self, CHashHashFunc *f)
00080 {
00081         self->hash2 = f;
00082 }
00083 
00084 void CHash_setEqualFunc_(CHash *self, CHashEqualFunc *f)
00085 {
00086         self->equals = f;
00087 }
00088 
00089 int CHash_insert_(CHash *self, CHashRecord *x)
00090 {       
00091         int n;
00092         
00093         for (n = 0; n < CHASH_MAXLOOP; n ++)
00094         { 
00095                 CHashRecord *r;
00096                 
00097                 //pos = self->hash1(x->k) & self->mask;
00098                 //printf("1 x->k = %p-> %i\n", x->k, pos);
00099                 r = CHash_record1_(self, x->k);
00100                 CHashRecord_swapWith_(x, r); //x ↔ T1 [h1 (x)] 
00101                 if(x->k == 0x0) { self->keyCount ++; return 0; }
00102 
00103                 //pos = self->hash2(x->k) & self->mask;
00104                 //printf("2 x->k = %p-> %i\n\n", x->k, pos);             
00105                 r = CHash_record2_(self, x->k);
00106                 CHashRecord_swapWith_(x, r); //x ↔ T2 [h2 (x)] 
00107                 if(x->k == 0x0) { self->keyCount ++; return 0; }
00108         }
00109         
00110         if(self->isResizing) 
00111         {
00112                 return -1;
00113         }
00114         
00115         CHash_grow(self); 
00116         CHash_at_put_(self, x->k, x->v);
00117         return 0;
00118 }
00119 
00120 int CHash_insertRecords(CHash *self, unsigned char *oldRecords, size_t oldSize)
00121 {
00122         size_t i;
00123         
00124         for (i = 0; i < oldSize; i ++)
00125         {
00126                 CHashRecord *r = CRecords_recordAt_(oldRecords, i);
00127                 
00128                 if (r->k)
00129                 {
00130                         if(CHash_at_put_(self, r->k, r->v)) return 1;
00131                 }
00132         }
00133         return 0;
00134 }
00135 
00136 int CHash_resizeTo_(CHash *self, size_t newSize)
00137 {
00138         unsigned char *oldRecords = self->records;
00139         size_t oldSize = self->size;
00140 
00141         self->isResizing = 1;
00142 
00143         //printf("%p resizeTo %i/%i %i%%\n", (void *)self, self->keyCount, self->size, (int)(100.0*CHash_density(self)));
00144                 
00145         do
00146         {
00147                 self->size = newSize;
00148                 self->records = io_calloc(1, sizeof(CHashRecord) * self->size);
00149                 self->keyCount = 0;
00150                 CHash_updateMask(self);
00151                 if(CHash_insertRecords(self, oldRecords, oldSize) == 0)
00152                 {
00153                         self->isResizing = 0;
00154                 }
00155                 else
00156                 {
00157                         //printf("%p grow collision %i/%i\n", (void *)self, self->keyCount, self->size);
00158                         newSize *= 2;
00159                         io_free(self->records);
00160                 }
00161         } while(self->isResizing);
00162         
00163         io_free(oldRecords);
00164         return 0;
00165 }
00166 
00167 void CHash_grow(CHash *self)
00168 {
00169         CHash_resizeTo_(self, self->size * 2);
00170 }
00171 
00172 void CHash_shrink(CHash *self)
00173 {
00174         //printf("%p shrink %i/%i\n", (void *)self, self->keyCount, self->size);
00175         //CHash_resizeTo_(self, self->size / 2);
00176 }
00177 
00178 void CHash_removeKey_(CHash *self, void *k)
00179 {
00180         CHashRecord *r1 = CHash_record1_(self, k);
00181         CHashRecord *r2;
00182         
00183         if(r1->k && self->equals(k, r1->k))
00184         {
00185                 r1->k = 0x0;
00186                 r1->v = 0x0;
00187                 self->keyCount --;
00188                 CHash_shrinkIfNeeded(self);
00189                 return;
00190         }
00191         
00192         r2 = CHash_record2_(self, k);
00193         
00194         if(r2->k && self->equals(k, r2->k))
00195         {
00196                 r2->k = 0x0;
00197                 r2->v = 0x0;
00198                 self->keyCount --;
00199                 CHash_shrinkIfNeeded(self);
00200                 return;
00201         }
00202 }
00203 
00204 void CHash_clear(CHash *self)
00205 {
00206         memset(self->records, 0x0, self->size * sizeof(CHashRecord));
00207         self->keyCount = 0;
00208         CHash_shrinkIfNeeded(self);
00209 }
00210 
00211 size_t CHash_size(CHash *self) // actually the keyCount
00212 {
00213         return self->keyCount;
00214 }
00215 
00216 // ----------------------------
00217 
00218 size_t CHash_memorySize(CHash *self)
00219 {
00220         return sizeof(CHash) + self->size * sizeof(CHashRecord);
00221 }
00222 
00223 void CHash_compact(CHash *self)
00224 {
00225 }
00226 
00227 float CHash_density(CHash *self)
00228 {
00229         float kc = (float)self->keyCount;
00230         float size = (float)self->size;
00231         return kc/size;
00232 }
00233 

Generated on Sat Apr 23 11:43:34 2011 for Mnemosyne by  doxygen 1.4.7