00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <assert.h>
00005
00006 #include "str.h"
00007 #include "cser.h"
00008
00009 #define __HASH__IMPLEMENTATION__
00010 #include "hash.h"
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #ifdef KEY_INT
00050 #define hashCode(x) (x)
00051 #define keyEqual(a,b) (a) == (b)
00052 #define keyCopy(d,s) (d) = (s)
00053 #define destroyKey(k)
00054 #elif defined(KEY_STRING)
00055 #define hashCode(x) str_hash_code(x)
00056 #define keyEqual(a,b) (!strcmp(a,b))
00057 #define keyCopy(d,s) (d) = strdup(s)
00058 #define destroyKey(k) free(k)
00059 #elif defined(KEY_DSI)
00060 #define hashCode(x) (abs(x.work*1000000+x.task))
00061 #define keyEqual(a,b) ( ((a).work==(b).work) && ((a).task==(b).task) )
00062 #define keyCopy(d,s) (d) = (s)
00063 #define destroyKey(k)
00064 #else
00065 #error "Not implemented"
00066 #endif
00067
00068
00069 #ifdef VAL_INT
00070 #define NO_VALUE -1
00071 #endif
00072 #ifdef VAL_VOID
00073 #define NO_VALUE NULL
00074 #endif
00075 #ifdef VAL_FLOAT
00076 #define NO_VALUE 0
00077 #endif
00078
00079 #ifdef KEY_INT
00080 #define KEY_NULL -1
00081 #elif defined(KEY_STRING)
00082 #define KEY_NULL NULL
00083 #elif defined(KEY_DSI)
00084 #define KEY_NULL {-1, -1}
00085 #endif
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 HASH_TYPE *HASH_CREATE(int sz) {
00096 HASH_TYPE *hash = (HASH_TYPE *)malloc(sizeof(HASH_TYPE));
00097 hash->tam = sz;
00098 hash->colisoes = 0;
00099 hash->chaves = 0;
00100 if (sz > 0) {
00101 hash->entradas = (LISTA_TYPE **)calloc(sz, sizeof(LISTA_TYPE *));
00102 } else {
00103 hash->entradas = NULL;
00104 }
00105 #ifdef VAL_VOID
00106 hash->serValVoid = NULL;
00107 hash->deserValVoid = NULL;
00108 #endif
00109
00110 return hash;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120 POS_HANDLER_TYPE HASH_ADD(HASH_TYPE *h, KEY_TYPE key) {
00121 if (h->tam < 3) {
00122 HASH_REHASH(h, 3);
00123 } else {
00124 float collisions = (float)h->colisoes;
00125 float size = (float)h->tam;
00126
00127 if ( (collisions/size) > MAX_COLISIONS_FACTOR) {
00128 float newSize = size * REHASH_MULTIPLIER;
00129 HASH_REHASH(h, (int)newSize);
00130 }
00131 }
00132
00133 int pos = hashCode(key) % (h->tam);
00134 LISTA_TYPE **ptr_lista = &(h->entradas[pos]);
00135 LISTA_TYPE *ptr_item = NULL;
00136
00137 for (; (*ptr_lista)!=NULL; ptr_lista = &((*ptr_lista)->next) ) {
00138 if (keyEqual( (*ptr_lista)->key, key )) {
00139
00140 return *ptr_lista;
00141 }
00142 }
00143
00144
00145 h->chaves++;
00146
00147
00148
00149 if (h->entradas[pos] != NULL) {
00150 h->colisoes++;
00151 }
00152
00153 ptr_item = (LISTA_TYPE *) malloc(sizeof(LISTA_TYPE));
00154 keyCopy(ptr_item->key, key);
00155 ptr_item->val = NO_VALUE;
00156 ptr_item->next = NULL;
00157
00158 *ptr_lista = ptr_item;
00159 return ptr_item;
00160 }
00161
00162
00163
00164
00165 POS_HANDLER_TYPE HASH_GET(HASH_TYPE *h, KEY_TYPE key) {
00166 if (h->tam > 0) {
00167 int pos = hashCode(key) % (h->tam);
00168 LISTA_TYPE *ptr_lista = h->entradas[pos];
00169
00170 for (; ptr_lista!=NULL; ptr_lista = ptr_lista->next) {
00171 if (keyEqual( ptr_lista->key, key )) {
00172
00173 return ptr_lista;
00174 }
00175 }
00176 }
00177
00178 return NULL;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187 int HASH_REMOVE(HASH_TYPE *h, KEY_TYPE removedKey) {
00188 #ifndef VAL_INT
00189 if (h == NULL) return -1;
00190 #endif
00191 if (h->tam > 0) {
00192 int pos = hashCode(removedKey) % (h->tam);
00193 LISTA_TYPE *ptr_lista = h->entradas[pos];
00194 LISTA_TYPE **ptr_ant = &(h->entradas[pos]);
00195
00196
00197 while (ptr_lista != NULL) {
00198 if (keyEqual( ptr_lista->key, removedKey )) {
00199 *ptr_ant = ptr_lista->next;
00200 free(ptr_lista);
00201 h->chaves--;
00202 return 0;
00203 }
00204
00205 ptr_ant = &(ptr_lista->next);
00206 ptr_lista = ptr_lista->next;
00207 }
00208 return -1;
00209 }
00210 return -1;
00211 }
00212
00213
00214
00215
00216 void HASH_DESTROY(HASH_TYPE *h) {
00217 int i;
00218
00219 for (i=0; i<h->tam; i++) {
00220 if (h->entradas[i] != NULL) {
00221 LISTA_DESTROY(h->entradas[i]);
00222 }
00223 }
00224
00225 free(h->entradas);
00226 free(h);
00227 }
00228
00229
00230
00231
00232 void HASH_CLEAN(HASH_TYPE *h) {
00233 int i;
00234
00235 for (i=0; i<h->tam; i++) {
00236 if (h->entradas[i] != NULL) {
00237 LISTA_DESTROY(h->entradas[i]);
00238 h->entradas[i] = NULL;
00239 }
00240 }
00241 }
00242
00243
00244
00245
00246 void HASH_REHASH(HASH_TYPE *h, int newSize) {
00247 LISTA_TYPE **newHash = (LISTA_TYPE **)calloc(newSize, sizeof(LISTA_TYPE *));
00248 ITERATOR_TYPE *oldHashIt = CREATE_ITERATOR(h, 1);
00249 POS_HANDLER_TYPE oldPos = ITERATOR_NEXT(oldHashIt, h);
00250 int collisions = 0;
00251 int newPos = -1;
00252
00253 while (oldPos != NULL) {
00254 newPos = hashCode(posGetKey(oldPos)) % (newSize);
00255 LISTA_TYPE **ptr_lista = &(newHash[newPos]);
00256 LISTA_TYPE *ptr_item = NULL;
00257
00258 while ((*ptr_lista)!=NULL) {
00259 ptr_lista = &((*ptr_lista)->next);
00260 }
00261
00262
00263
00264 if (newHash[newPos] != NULL) {
00265 collisions++;
00266 }
00267
00268 ptr_item = (LISTA_TYPE *) malloc(sizeof(LISTA_TYPE));
00269 keyCopy(ptr_item->key, posGetKey(oldPos));
00270 ptr_item->val = posGetValue(oldPos);
00271 ptr_item->next = NULL;
00272
00273 *ptr_lista = ptr_item;
00274
00275
00276 oldPos = ITERATOR_NEXT(oldHashIt, h);
00277 }
00278
00279 if (h->entradas != NULL) {
00280 free(h->entradas);
00281 }
00282 h->tam = newSize;
00283 h->colisoes = collisions;
00284 h->entradas = newHash;
00285 }
00286
00287 int HASH_SERIALIZE(FILE *outputFile, HASH_TYPE *hash){
00288 WRITE_NUM(outputFile, "numKeys", hash->chaves);
00289
00290 #ifdef DEBUG
00291 char header[] = "-#Hash-";
00292 WRITE_BYTES(outputFile, header, strlen(header));
00293 #endif
00294
00295 ITERATOR_TYPE *it = CREATE_ITERATOR(hash, 0);
00296 POS_HANDLER_TYPE pos = NULL;
00297 for (pos = ITERATOR_NEXT(it, hash); pos != NULL; pos = ITERATOR_NEXT(it, hash)) {
00298 WRITE_KEY(outputFile, hash, pos);
00299 WRITE_VALUE(outputFile, hash, pos);
00300 }
00301 ITERATOR_DESTROY(it, hash);
00302
00303 #ifdef DEBUG
00304 char footer[] = "-#HashEnd-";
00305 WRITE_BYTES(outputFile, footer, strlen(footer));
00306 #endif
00307
00308 return 0;
00309 }
00310
00311 int HASH_DESERIALIZE(FILE *inputFile, HASH_TYPE *hash){
00312 int i = 0, chaves = -1;
00313 READ_BEGIN(inputFile);
00314
00315 READ_NUM("numKeys", chaves);
00316 assert(chaves != -1);
00317
00318
00319 #ifdef DEBUG
00320 char header[] = "-#Hash-";
00321 char *buf = malloc(strlen(header)+1);
00322 READ_BYTES(inputFile, buf, strlen(header));
00323 buf[strlen(header)] = '\0';
00324
00325 if (strcmp(header, buf)) {
00326
00327 assert(0 == strcmp(header, buf));
00328 }
00329 free(buf);
00330 #endif
00331
00332 POS_HANDLER_TYPE tmpPos = malloc(sizeof(LISTA_TYPE));
00333 POS_HANDLER_TYPE hashPos = NULL;
00334 for (i=0; i<chaves; i++) {
00335 READ_KEY(inputFile, hash, tmpPos);
00336 READ_VALUE(inputFile, hash, tmpPos);
00337
00338 hashPos = HASH_ADD(hash, posGetKey(tmpPos));
00339 posSetValue(hashPos, posGetValue(tmpPos));
00340 }
00341 free(tmpPos);
00342 READ_END
00343
00344 #ifdef DEBUG
00345 char footer[] = "-#HashEnd-";
00346
00347
00348 char *buf = (char *)malloc(strlen(footer)+1);
00349 READ_BYTES(inputFile, buf, strlen(footer));
00350 buf[strlen(footer)] = '\0';
00351
00352 if (strcmp(footer, buf)) {
00353
00354 assert(0 == strcmp(footer, buf));
00355 }
00356 free(buf);
00357 #endif
00358
00359 return 0;
00360 }
00361
00362
00363 int WRITE_KEY(FILE *outputFile, HASH_TYPE *hash, POS_HANDLER_TYPE pos) {
00364
00365 #ifdef DEBUG
00366 char header[] = "-#Tuple-";
00367 WRITE_BYTES(outputFile, header, strlen(header));
00368 #endif
00369
00370 #ifdef KEY_INT
00371 WRITE_NUM(outputFile, "key", posGetKey(pos));
00372 #elif defined(KEY_STRING)
00373 WRITE_STR(outputFile, "key", posGetKey(pos));
00374 #elif defined(KEY_DSI)
00375 WRITE_NUM(outputFile, "work", posGetKey(pos).work);
00376 WRITE_NUM(outputFile, "task", posGetKey(pos).task);
00377 #else
00378 #error "Not implemented"
00379 #endif
00380
00381 return 0;
00382 }
00383
00384
00385 int READ_KEY(FILE *inputFile, HASH_TYPE *hash, POS_HANDLER_TYPE pos){
00386 KEY_TYPE key = KEY_NULL;
00387
00388 #ifdef DEBUG
00389 char header[] = "-#Tuple-";
00390 char *buf = malloc(strlen(header)+1);
00391 READ_BYTES(inputFile, buf, strlen(header));
00392 buf[strlen(header)] = '\0';
00393
00394 if (strcmp(header, buf)) {
00395
00396 assert(0 == strcmp(header, buf));
00397 }
00398 free(buf);
00399 #endif
00400
00401 READ_BEGIN(inputFile);
00402 #ifdef KEY_INT
00403 READ_NUM("key", key);
00404 #elif defined(KEY_STRING)
00405 READ_STR("key", key);
00406 #elif defined(KEY_DSI)
00407 READ_NUM("work", key.work);
00408 READ_NUM("task", key.task);
00409 #else
00410 #error "Not implemented"
00411 #endif
00412 READ_END
00413 pos->key=key;
00414
00415 return 0;
00416 }
00417
00418 int WRITE_VALUE(FILE *outputFile, HASH_TYPE *hash, POS_HANDLER_TYPE pos) {
00419 #ifdef DEBUG
00420 char header[] = "-#Value-";
00421 WRITE_BYTES(outputFile, header, strlen(header));
00422 #endif
00423
00424
00425 #ifdef VAL_INT
00426 WRITE_NUM(outputFile, "value", posGetValue(pos));
00427 #endif
00428 #ifdef VAL_VOID
00429
00430 hash->serValVoid(outputFile, posGetValue(pos));
00431 #endif
00432 #ifdef VAL_FLOAT
00433 WRITE_FLOAT(outputFile, "value", posGetValue(pos));
00434 #endif
00435
00436 #ifdef DEBUG
00437 char footer[] = "-#TupleEnd-";
00438 WRITE_BYTES(outputFile, footer, strlen(footer));
00439 #endif
00440
00441 return 0;
00442 }
00443
00444 int READ_VALUE(FILE *inputFile, HASH_TYPE *hash, POS_HANDLER_TYPE pos) {
00445 #ifdef DEBUG
00446 char header[] = "-#Value-";
00447 char *buf = malloc(strlen(header)+1);
00448 READ_BYTES(inputFile, buf, strlen(header));
00449 buf[strlen(header)] = '\0';
00450
00451 if (strcmp(header, buf)) {
00452
00453 assert(0 == strcmp(header, buf));
00454 }
00455 free(buf);
00456 #endif
00457
00458
00459 posSetValue(pos, NO_VALUE);
00460
00461 #ifdef VAL_VOID
00462
00463 posSetValue(pos, hash->deserValVoid(inputFile));
00464 #else
00465
00466 READ_BEGIN(inputFile);
00467 #ifdef VAL_INT
00468 READ_NUM("value", posGetValue(pos));
00469 #endif
00470 #ifdef VAL_FLOAT
00471 READ_FLOAT("value", posGetValue(pos));
00472 #endif
00473 READ_END
00474
00475 #endif // ifdef VAL_VOID
00476
00477
00478 #ifdef DEBUG
00479 char footer[] = "-#TupleEnd-";
00480 buf = malloc(strlen(footer)+1);
00481 READ_BYTES(inputFile, buf, strlen(footer));
00482 buf[strlen(footer)] = '\0';
00483
00484 if (strcmp(footer, buf)) {
00485
00486 assert(0 == strcmp(footer, buf));
00487 }
00488 free(buf);
00489 #endif
00490
00491 return 0;
00492 }
00493
00494 #ifdef VAL_VOID
00495 void SET_SERIALIZER_VAL_VOID(HASH_TYPE *hash, hashSerializeValVoid *serializer, hashDeserializeValVoid *deserializer) {
00496 hash->serValVoid = serializer;
00497 hash->deserValVoid = deserializer;
00498 }
00499 #endif
00500
00501
00502
00503
00504
00505
00506
00507 void LISTA_DESTROY(LISTA_TYPE *l) {
00508 if (l->next != NULL) {
00509 LISTA_DESTROY(l->next);
00510 }
00511 destroyKey(l->key);
00512
00513 free(l);
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 ITERATOR_TYPE *CREATE_ITERATOR(HASH_TYPE *hash, int is_destructor) {
00528 ITERATOR_TYPE *hdi = (ITERATOR_TYPE *) malloc(sizeof(ITERATOR_TYPE));
00529
00530 hdi->is_destructor = is_destructor;
00531 hdi->entr_atual = -1;
00532 hdi->elem_atual = NULL;
00533
00534 return hdi;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 POS_HANDLER_TYPE ITERATOR_NEXT(ITERATOR_TYPE *hdi, HASH_TYPE *hash) {
00548 if (hdi->elem_atual != NULL) {
00549 hdi->elem_atual = hdi->elem_atual->next;
00550 }
00551 if (hdi->is_destructor && hdi->elem_atual==NULL && hdi->entr_atual >=0) {
00552 LISTA_DESTROY(hash->entradas[hdi->entr_atual]);
00553 hash->entradas[hdi->entr_atual] = NULL;
00554 }
00555 while (hdi->elem_atual == NULL) {
00556 hdi->entr_atual++;
00557
00558 if (hdi->entr_atual >= hash->tam) return NULL;
00559 hdi->elem_atual = hash->entradas[hdi->entr_atual];
00560 }
00561
00562 #ifdef DEBUG
00563 if (hdi->elem_atual == NULL) {
00564 if (hdi->entr_atual < hash->tam) {
00565 printf("%s(%d): Deu pau!!! Vai retornar NULL sem o hash ter acabado\n", __FILE__, __LINE__);
00566 exit(1);
00567 }
00568 }
00569 #endif
00570 return hdi->elem_atual;
00571 }
00572
00573
00574
00575
00576
00577
00578
00579 void ITERATOR_DESTROY(ITERATOR_TYPE *hdi, HASH_TYPE *hash) {
00580 if (hdi->is_destructor && hdi->entr_atual<hash->tam && hdi->entr_atual >=0 && hdi->elem_atual==NULL) {
00581 LISTA_DESTROY(hash->entradas[hdi->entr_atual]);
00582 hash->entradas[hdi->entr_atual] = NULL;
00583 }
00584 free(hdi);
00585 }
00586