00001
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #include "defines.h"
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <sys/types.h>
00033 #include <stddef.h>
00034
00035 #include "hashlib.h"
00036
00037
00038 #ifndef DOXYGEN
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #define mix(a,b,c) \
00072 { \
00073 a -= b; a -= c; a ^= (c>>13); \
00074 b -= c; b -= a; b ^= (a<<8); \
00075 c -= a; c -= b; c ^= (b>>13); \
00076 a -= b; a -= c; a ^= (c>>12); \
00077 b -= c; b -= a; b ^= (a<<16); \
00078 c -= a; c -= b; c ^= (b>>5); \
00079 a -= b; a -= c; a ^= (c>>3); \
00080 b -= c; b -= a; b ^= (a<<10); \
00081 c -= a; c -= b; c ^= (b>>15); \
00082 }
00083
00084 #endif
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 ub4 lookup(register ub1 *k,register ub4 length,register ub4 level) {
00115 register ub4 a,b,c,len;
00116
00117
00118 len = length;
00119 a = b = 0x9e3779b9;
00120 c = level;
00121
00122
00123 while (len >= 12) {
00124 a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
00125 b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
00126 c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
00127 mix(a,b,c);
00128 k += 12; len -= 12;
00129 }
00130
00131
00132 c += length;
00133 switch(len) {
00134 case 11: c+=((ub4)k[10]<<24);
00135 case 10: c+=((ub4)k[9]<<16);
00136 case 9 : c+=((ub4)k[8]<<8);
00137
00138 case 8 : b+=((ub4)k[7]<<24);
00139 case 7 : b+=((ub4)k[6]<<16);
00140 case 6 : b+=((ub4)k[5]<<8);
00141 case 5 : b+=k[4];
00142 case 4 : a+=((ub4)k[3]<<24);
00143 case 3 : a+=((ub4)k[2]<<16);
00144 case 2 : a+=((ub4)k[1]<<8);
00145 case 1 : a+=k[0];
00146
00147 }
00148 mix(a,b,c);
00149
00150 return c;
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 t_cf_hash *cf_hash_new(t_cf_hash_cleanup cl) {
00176 t_cf_hash *hsh = malloc(sizeof(t_cf_hash));
00177 ub4 elems = hashsize(CF_HASH_SIZE);
00178
00179 if(!hsh) return NULL;
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 hsh->tablesize = CF_HASH_SIZE;
00192
00193
00194
00195
00196
00197 hsh->table = calloc(elems,sizeof(t_cf_hash));
00198
00199 hsh->destroy = cl;
00200
00201 return hsh;
00202 }
00203
00204 #ifndef DOXYGEN
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 t_cf_hash_entry *_cf_hash_save(unsigned char *key,size_t keylen,void *data,size_t datalen,ub4 hashval) {
00218 t_cf_hash_entry *ent = malloc(sizeof(t_cf_hash_entry));
00219
00220 if(!ent) return NULL;
00221
00222
00223
00224
00225
00226
00227 ent->hashval = hashval;
00228
00229
00230
00231
00232 ent->key = malloc((keylen + 1) * sizeof(unsigned char));
00233 if(!ent->key) return NULL;
00234
00235 memcpy(ent->key,key,keylen);
00236 ent->key[keylen] = 0;
00237 ent->keylen = keylen;
00238
00239
00240
00241
00242 if(datalen) {
00243 ent->data = malloc(datalen);
00244 ent->stat = 0;
00245 if(!ent->data) return NULL;
00246
00247 memcpy(ent->data,data,datalen);
00248 }
00249 else {
00250 ent->stat = 1;
00251 ent->data = data;
00252 }
00253
00254 ent->prev = NULL;
00255 ent->next = NULL;
00256
00257 return ent;
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 void _cf_hash_split(t_cf_hash *hsh,unsigned char *key,size_t keylen,void *data,size_t datalen,ub4 hval) {
00277 ub4 elems,oelems,i,hval_short;
00278 t_cf_hash_entry *elem,*elem1;
00279
00280 oelems = hashsize(hsh->tablesize);
00281 elems = hashsize(++(hsh->tablesize));
00282
00283
00284
00285
00286 hsh->table = realloc(hsh->table,elems * sizeof(t_cf_hash_entry **));
00287
00288
00289
00290
00291
00292 memset(&hsh->table[oelems],0,oelems * sizeof(t_cf_hash_entry **));
00293
00294
00295
00296
00297
00298 for(i=0;i<oelems;i++) {
00299
00300
00301
00302 if(!hsh->table[i]) continue;
00303
00304
00305
00306
00307 for(elem=hsh->table[i];elem;elem=elem1) {
00308 elem1 = elem->next;
00309
00310
00311
00312
00313
00314 if((elem->hashval & (elems - 1)) != i) {
00315
00316
00317
00318
00319
00320 if(elem->prev) {
00321 elem->prev->next = elem->next;
00322 }
00323 else {
00324 hsh->table[i] = elem->next;
00325 }
00326
00327
00328
00329
00330
00331
00332 if(elem->next) {
00333 elem->next->prev = elem->prev;
00334 }
00335
00336
00337
00338
00339 elem->next = hsh->table[elem->hashval & (elems - 1)];
00340 elem->prev = NULL;
00341 hsh->table[elem->hashval & (elems - 1)] = elem;
00342
00343 if(elem->next) elem->next->prev = elem;
00344 }
00345 }
00346 }
00347
00348
00349
00350
00351
00352
00353 hval_short = hval & (elems - 1);
00354 if(hsh->table[hval_short]) {
00355 for(elem1=hsh->table[hval_short];elem1->next;elem1=elem1->next);
00356 elem1->next = _cf_hash_save(key,keylen,data,datalen,hval);
00357 elem1->next->prev = elem1;
00358 }
00359 else {
00360 hsh->table[hval_short] = _cf_hash_save(key,keylen,data,datalen,hval);
00361 }
00362
00363 }
00364 #endif
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 int cf_hash_set(t_cf_hash *hsh,unsigned char *key,size_t keylen,void *data,size_t datalen) {
00383 ub4 hval,hval_short;
00384 t_cf_hash_entry *ent,*prev;
00385 int doubles;
00386
00387
00388
00389
00390 hval = lookup(key,keylen,0);
00391
00392
00393
00394
00395
00396 hval_short = hval & hashmask(hsh->tablesize);
00397
00398 ent = hsh->table[hval_short];
00399
00400 if(ent) {
00401 for(doubles=0,prev=NULL;ent;doubles++,ent=ent->next) {
00402
00403
00404
00405 if(ent->hashval == hval && strcmp(ent->key,key) == 0) {
00406 if(ent->stat == 0) {
00407 if(hsh->destroy) hsh->destroy(ent->data);
00408 free(ent->data);
00409 }
00410
00411 ent->data = malloc(datalen);
00412 if(!ent->data) return 0;
00413 memcpy(ent->data,data,datalen);
00414
00415 return 1;
00416 }
00417
00418 prev = ent;
00419 }
00420
00421
00422
00423
00424 if(doubles > CF_HASH_MAX_DOUBLES) {
00425 _cf_hash_split(hsh,key,keylen,data,datalen,hval);
00426 }
00427 else {
00428 prev->next = _cf_hash_save(key,keylen,data,datalen,hval);
00429 prev->next->prev = prev;
00430 }
00431
00432 return 1;
00433 }
00434 else {
00435 hsh->table[hval_short] = _cf_hash_save(key,keylen,data,datalen,hval);
00436 return 1;
00437 }
00438
00439 return 0;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 int cf_hash_set_static(t_cf_hash *hsh,unsigned char *key,size_t keylen,void *data) {
00458 ub4 hval,hval_short;
00459 t_cf_hash_entry *ent,*prev;
00460 int doubles;
00461
00462
00463
00464
00465 hval = lookup(key,keylen,0);
00466
00467
00468
00469
00470
00471 hval_short = hval & hashmask(hsh->tablesize);
00472
00473 ent = hsh->table[hval_short];
00474
00475 if(ent) {
00476 for(doubles=0,prev=NULL;ent;doubles++,ent=ent->next) {
00477
00478
00479
00480 if(ent->hashval == hval && strcmp(ent->key,key) == 0) {
00481 if(ent->stat == 0) {
00482 if(hsh->destroy) hsh->destroy(ent->data);
00483 free(ent->data);
00484 }
00485
00486 ent->data = data;
00487 ent->stat = 1;
00488
00489 return 1;
00490 }
00491
00492 prev = ent;
00493 }
00494
00495
00496
00497
00498 if(doubles > CF_HASH_MAX_DOUBLES) {
00499 _cf_hash_split(hsh,key,keylen,data,0,hval);
00500 }
00501 else {
00502 prev->next = _cf_hash_save(key,keylen,data,0,hval);
00503 prev->next->prev = prev;
00504 }
00505
00506 return 1;
00507 }
00508 else {
00509 hsh->table[hval_short] = _cf_hash_save(key,keylen,data,0,hval);
00510 return 1;
00511 }
00512
00513 return 0;
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 void *cf_hash_get(t_cf_hash *hsh,unsigned char *key,size_t keylen) {
00528 ub4 hval,hval_short;
00529 t_cf_hash_entry *ent;
00530
00531 hval = lookup(key,keylen,0);
00532 hval_short = hval & hashmask(hsh->tablesize);
00533
00534 if(hsh->table[hval_short]) {
00535 for(ent = hsh->table[hval_short];ent && (ent->hashval != hval || strcmp(ent->key,key) != 0);ent=ent->next);
00536
00537 if(ent) return ent->data;
00538 }
00539
00540 return NULL;
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 int cf_hash_entry_delete(t_cf_hash *hsh,unsigned char *key,size_t keylen) {
00556 ub4 hval,hval_short;
00557 t_cf_hash_entry *ent;
00558
00559 hval = lookup(key,keylen,0);
00560 hval_short = hval & hashmask(hsh->tablesize);
00561
00562 if(hsh->table[hval_short]) {
00563 for(ent = hsh->table[hval_short];ent && (ent->hashval != hval || strcmp(ent->key,key) != 0);ent=ent->next);
00564
00565 if(ent) {
00566 if(ent->stat == 0) {
00567 if(hsh->destroy) hsh->destroy(ent->data);
00568 free(ent->data);
00569 }
00570 free(ent->key);
00571
00572 if(ent->prev) {
00573 ent->prev->next = ent->next;
00574 }
00575 else {
00576 hsh->table[hval_short] = ent->next;
00577 }
00578 if(ent->next) {
00579 ent->next->prev = ent->prev;
00580 }
00581
00582 free(ent);
00583
00584 return 1;
00585 }
00586 }
00587
00588 return 0;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 void cf_hash_destroy(t_cf_hash *hsh) {
00602 ub4 elems = hashsize(hsh->tablesize);
00603 ub4 i;
00604 t_cf_hash_entry *ent,*ent1;
00605
00606 for(i=0;i<elems;i++) {
00607 if(hsh->table[i]) {
00608 for(ent = hsh->table[i];ent;ent=ent1) {
00609 if(ent->stat == 0) {
00610 if(hsh->destroy) hsh->destroy(ent->data);
00611 free(ent->data);
00612 }
00613
00614 ent1 = ent->next;
00615
00616 free(ent->key);
00617 free(ent);
00618 }
00619 }
00620 }
00621
00622 free(hsh->table);
00623 free(hsh);
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655