├── Makefile ├── README.md ├── obj └── .gitkeep ├── src ├── djbhash.c └── djbhash.h └── test.c /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -o obj/djbhash.o -fPIC -c src/djbhash.c 3 | gcc -shared -o obj/libdjbhash.so obj/djbhash.o 4 | 5 | install: 6 | cp obj/*.so /usr/local/lib 7 | cp src/*.h /usr/local/include 8 | 9 | clean: 10 | rm -f obj/* 11 | rm -f djbhash 12 | 13 | test: 14 | gcc -o djbhash test.c src/djbhash.c -Isrc/ -g 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##djbhash - A simple c hash implementation using the DJB string hashing function. 2 | 3 | ### Usage: 4 | #### Initializing the hash table. 5 | ```c 6 | // The hash table object. 7 | struct djbhash hash; 8 | 9 | // Initialize the hash. 10 | djbhash_init( &hash ); 11 | ``` 12 | 13 | #### Adding an item to the hash. 14 | ```c 15 | /* djbhash_set( &, , , , ( optional). 16 | * 17 | * Supported data types 18 | * ===================== 19 | * DJBHASH_INT => int 20 | * DJBHASH_DOUBLE => double (or float) 21 | * DJBHASH_CHAR => char 22 | * DJBHASH_STRING => char *, const char * 23 | * DJBHASH_ARRAY => int * (When used, must also pass the count parameter) 24 | * DJBHASH_HASH => another djbhash object. 25 | * DJBHASH_OTHER => generic void *, use with caution!. 26 | */ 27 | 28 | // Item with int value. 29 | int temp = ( 10 ); 30 | djbhash_set( &hash, "int", &temp, DJBHASH_INT ); 31 | 32 | // Item with a double value. 33 | double temp2 = 3.14159; 34 | djbhash_set( &hash, "double", &temp2, DJBHASH_DOUBLE ); 35 | 36 | // Item with a char value. 37 | char temp3 = 'a'; 38 | djbhash_set( &hash, "char", &temp3, DJBHASH_CHAR ); 39 | 40 | // Item with a string value. 41 | djbhash_set( &hash, "string", "bar", DJBHASH_STRING ); 42 | 43 | // Item with an array value - notice the additional param. 44 | int temp_arr[] = { 8, 6, 7, 5, 3, 0, 9 }; 45 | djbhash_set( &hash, "array", temp_arr, DJBHASH_ARRAY, 7 ); 46 | 47 | // An embedded hash within this hash. 48 | struct djbhash temp_hash; 49 | djbhash_init( &temp_hash ); 50 | djbhash_set( &temp_hash, "foo", "bar", DJBHASH_STRING ); 51 | djbhash_set( &temp_hash, "baz", temp_arr, DJBHASH_ARRAY, 7 ); 52 | djbhash_set( &hash, "hash", &temp_hash, DJBHASH_HASH ); 53 | 54 | // Item with a different data type. 55 | // suppose you declared: struct test_struct { int a; int b; }; 56 | struct test_struct test; 57 | test.a = 10; 58 | test.b = 5; 59 | djbhash_set( &hash, "other", test, DJBHASH_OTHER ); 60 | ``` 61 | 62 | #### Finding an item in the hash. 63 | ```c 64 | // Pointer to the hash item. 65 | struct djbhash_node *item; 66 | void *value; 67 | 68 | // Add an item to find. 69 | djbhash_set( &hash, "foo", "bar", DJBHASH_STRING ); 70 | 71 | // Find and print the item. 72 | item = djbhash_find( &hash, "foo" ); 73 | value = item->value; 74 | djbhash_print( item ); 75 | 76 | // Search for an item that doesn't exist: 77 | char *missing = "missing"; 78 | if ( ( item = djbhash_find( &hash, missing ) ) == NULL ) 79 | printf( "%s: No such item!\n", missing ); 80 | ``` 81 | 82 | ### Removing an item in the hash. 83 | ```c 84 | djbhash_remove( &hash, "int" ); 85 | if ( djbhash_find( &hash, "int" ) == NULL ) 86 | printf( "item removedn" ); 87 | ``` 88 | 89 | ### Print all items in the hash. 90 | ```c 91 | djbhash_dump( &hash ); 92 | ``` 93 | 94 | ### Iterate through all items in the hash. 95 | ```c 96 | item = djbhash_iterate( &hash ); 97 | while ( item ) 98 | { 99 | djbhash_print( item ); 100 | item = djbhash_iterate( &hash ); 101 | } 102 | ``` 103 | 104 | ### Getting a JSON formated string of the hash. 105 | ```c 106 | char *json = djbhash_to_json( &hash ); 107 | printf( "JSON: %s\n", json ); 108 | free( json ); 109 | json = NULL; 110 | ``` 111 | 112 | ### Reset the iterator to the first item. 113 | ```c 114 | djbhash_reset_iterator( &hash ); 115 | ``` 116 | 117 | #### Cleanup: 118 | ```c 119 | // Remove all items and free memory. 120 | djbhash_destroy( &hash ); 121 | ``` 122 | 123 | ### For a full example, see test.c. 124 | -------------------------------------------------------------------------------- /obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdi/djbhash/885b9266601a32ee0edc52091be4813e83210c8f/obj/.gitkeep -------------------------------------------------------------------------------- /src/djbhash.c: -------------------------------------------------------------------------------- 1 | #include "djbhash.h" 2 | 3 | // Convert an integer to string. 4 | unsigned char *djbhash_int_to_a( int number ) 5 | { 6 | unsigned char *ascii; 7 | ascii = calloc( 32, sizeof( unsigned char ) ); 8 | sprintf( ascii, "%d", number ); 9 | return ascii; 10 | } 11 | 12 | // Convert a double into a string. 13 | unsigned char *djbhash_double_to_a( double number ) 14 | { 15 | unsigned char *ascii; 16 | ascii = calloc( 32, sizeof( unsigned char ) ); 17 | sprintf( ascii, "%f", number ); 18 | return ascii; 19 | } 20 | 21 | // Return a JSON formated array string. 22 | unsigned char *djbhash_json_array( int *array, int count ) 23 | { 24 | int i, j; 25 | int digits, digit, value; 26 | unsigned char *json; 27 | unsigned char *part; 28 | unsigned int length, pos, size; 29 | 30 | json = calloc( 3, sizeof( unsigned char ) ); 31 | json[0] = '['; 32 | pos = 1; 33 | size = 1; 34 | for ( i = 0; i < count; i++ ) 35 | { 36 | part = djbhash_int_to_a( array[i] ); 37 | length = strlen( part ); 38 | size += length + 2; 39 | json = realloc( json, sizeof( unsigned char ) * size ); 40 | for ( j = pos; j < size; j++ ) 41 | json[j] = '\0'; 42 | 43 | for ( j = 0; j < length; j++ ) 44 | json[j + pos] = part[j]; 45 | pos += length; 46 | 47 | if ( i < count - 1 ) 48 | json[pos++] = ','; 49 | free( part ); 50 | part = NULL; 51 | } 52 | json[pos] = ']'; 53 | return json; 54 | } 55 | 56 | // Return an escaped version of a string. 57 | unsigned char *djbhash_escaped( unsigned char *data ) 58 | { 59 | unsigned char *escaped; 60 | unsigned char *ptr; 61 | int iter; 62 | 63 | escaped = calloc( strlen( data ) * 2 + 2, sizeof( unsigned char ) ); 64 | escaped[0] = '"'; 65 | iter = 1; 66 | ptr = data; 67 | while ( *ptr != '\0' ) 68 | { 69 | switch ( *ptr ) 70 | { 71 | case '\n': 72 | escaped[iter++] = '\\'; 73 | escaped[iter++] = 'n'; 74 | break; 75 | case '\t': 76 | escaped[iter++] = '\\'; 77 | escaped[iter++] = 't'; 78 | break; 79 | case '\r': 80 | escaped[iter++] = '\\'; 81 | escaped[iter++] = 'r'; 82 | break; 83 | case '\f': 84 | escaped[iter++] = '\\'; 85 | escaped[iter++] = 'f'; 86 | break; 87 | case '"': 88 | escaped[iter++] = '\\'; 89 | escaped[iter++] = '"'; 90 | break; 91 | case '\\': 92 | escaped[iter++] = '\\'; 93 | escaped[iter++] = '\\'; 94 | break; 95 | default: 96 | escaped[iter++] = *ptr; 97 | break; 98 | } 99 | *ptr++; 100 | } 101 | escaped[iter] = '"'; 102 | return escaped; 103 | } 104 | 105 | // Print an item in JSON format. 106 | unsigned char *djbhash_value_to_json( struct djbhash_node *item ) 107 | { 108 | int i; 109 | int *arr_ptr; 110 | unsigned char *json, *str; 111 | int length; 112 | 113 | switch ( item->data_type ) 114 | { 115 | case DJBHASH_INT: 116 | json = djbhash_int_to_a( *( int * )item->value ); 117 | break; 118 | case DJBHASH_DOUBLE: 119 | json = djbhash_double_to_a( *( double * )item->value ); 120 | break; 121 | case DJBHASH_CHAR: 122 | str = calloc( 2, sizeof( unsigned char ) ); 123 | str[0] = *( unsigned char * )item->value; 124 | json = djbhash_escaped( str ); 125 | free( str ); 126 | str = NULL; 127 | break; 128 | case DJBHASH_STRING: 129 | json = djbhash_escaped( ( unsigned char * )item->value ); 130 | break; 131 | case DJBHASH_ARRAY: 132 | json = djbhash_json_array( ( int * )item->value, item->count ); 133 | break; 134 | case DJBHASH_HASH: 135 | json = djbhash_to_json( ( struct djbhash * )item->value ); 136 | break; 137 | default: 138 | length = strlen( "UNKOWN" ); 139 | json = calloc( length + 1, sizeof( unsigned char ) ); 140 | memcpy( json, "UNKNOWN", length ); 141 | } 142 | return json; 143 | } 144 | 145 | // Return a JSON formatted string containing the hash. 146 | unsigned char *djbhash_to_json( struct djbhash *hash ) 147 | { 148 | int i, j; 149 | unsigned char *json; 150 | unsigned char *key, *value; 151 | unsigned int length, pos, size; 152 | struct djbhash_node *iter; 153 | 154 | json = calloc( 3, sizeof( unsigned char ) ); 155 | json[0] = '{'; 156 | pos = 1; 157 | size = 1; 158 | djbhash_reset_iterator( hash ); 159 | iter = djbhash_iterate( hash ); 160 | while ( iter ) 161 | { 162 | key = djbhash_escaped( iter->key ); 163 | length = strlen( key ); 164 | 165 | // Reallocate memory and set it to null. 166 | size += length + 3; 167 | json = realloc( json, sizeof( unsigned char ) * size ); 168 | for ( j = pos; j < size; j++ ) 169 | json[j] = '\0'; 170 | 171 | // Add the key in quotes to the string. 172 | for ( j = 0; j < length; j++ ) 173 | json[j + pos] = key[j]; 174 | pos += length; 175 | 176 | // Now the value: 177 | value = djbhash_value_to_json( iter ); 178 | length = strlen( value ); 179 | size += length + 1; 180 | json = realloc( json, sizeof( unsigned char ) * size ); 181 | for ( j = pos; j < size; j++ ) 182 | json[j] = '\0'; 183 | json[pos++] = ':'; 184 | 185 | for ( j = 0; j < length; j++ ) 186 | json[j + pos] = value[j]; 187 | pos += length; 188 | iter = djbhash_iterate( hash ); 189 | if ( iter != NULL ) 190 | json[pos++] = ','; 191 | 192 | free( key ); 193 | key = NULL; 194 | free( value ); 195 | value = NULL; 196 | } 197 | djbhash_reset_iterator( hash ); 198 | json[pos] = '}'; 199 | return json; 200 | } 201 | 202 | // Print an items' data. 203 | void djbhash_print_value( struct djbhash_node *item ) 204 | { 205 | // String containing JSON formatted value. 206 | unsigned char *json; 207 | 208 | json = djbhash_value_to_json( item ); 209 | printf( "%s", json ); 210 | if ( json != NULL ) 211 | { 212 | free( json ); 213 | json = NULL; 214 | } 215 | printf( "\n" ); 216 | } 217 | 218 | // Print the key value pair. 219 | void djbhash_print( struct djbhash_node *item ) 220 | { 221 | printf( "%s => ", item->key ); 222 | djbhash_print_value( item ); 223 | } 224 | 225 | // Initialize the hash table. 226 | void djbhash_init( struct djbhash *hash ) 227 | { 228 | int i; 229 | hash->buckets = malloc( sizeof( struct djbhash_bucket ) * DJBHASH_MAX_BUCKETS ); 230 | hash->active = malloc( sizeof( int ) * DJBHASH_MAX_BUCKETS ); 231 | hash->active_count = 0; 232 | hash->iter.node = NULL; 233 | hash->iter.last = NULL; 234 | hash->iter.id = 0; 235 | for ( i = 0; i < DJBHASH_MAX_BUCKETS; i++ ) 236 | { 237 | hash->buckets[i].id = i; 238 | hash->buckets[i].list = NULL; 239 | } 240 | } 241 | 242 | // DJB Hash function. 243 | unsigned int djb_hash( char *key, int length ) 244 | { 245 | unsigned int i; 246 | unsigned int hash; 247 | 248 | hash = 5381; 249 | for ( i = 0; i < length; key++, i++ ) 250 | hash = ( ( hash << 5 ) + hash ) + ( *key ); 251 | return hash % DJBHASH_MAX_BUCKETS; 252 | } 253 | 254 | // Find the bucket for the element. 255 | struct djbhash_search djbhash_bin_search( struct djbhash *hash, unsigned int min, unsigned int max, unsigned int bucket_id, char *key, int length ) 256 | { 257 | // Mid-point for search. 258 | unsigned int mid; 259 | // Linked list iterator and parent node. 260 | struct djbhash_node *iter, *parent; 261 | // Return variable. 262 | struct djbhash_search pos; 263 | 264 | // If max is less than min, we didn't find it. 265 | if ( max < min ) 266 | { 267 | pos.bucket_id = min; 268 | pos.found = false; 269 | pos.item = NULL; 270 | pos.parent = NULL; 271 | return pos; 272 | } 273 | 274 | mid = ( min + max ) / 2; 275 | if ( hash->buckets[mid].id > bucket_id ) 276 | return djbhash_bin_search( hash, min, mid - 1, bucket_id, key, length ); 277 | else if ( hash->buckets[mid].id < bucket_id ) 278 | return djbhash_bin_search( hash, mid + 1, max, bucket_id, key, length ); 279 | 280 | // Point our iterator to the first element in this bucket. 281 | iter = hash->buckets[mid].list; 282 | parent = iter; 283 | while ( iter ) 284 | { 285 | // We want to return if the key in the linked list actually matches. 286 | if ( strncmp( iter->key, key, length ) == 0 ) 287 | { 288 | pos.bucket_id = mid; 289 | pos.found = true; 290 | pos.item = iter; 291 | pos.parent = parent; 292 | return pos; 293 | } 294 | parent = iter; 295 | iter = iter->next; 296 | } 297 | 298 | // If we got here, there the item doesn't actually exist, it's just a hash collision. 299 | pos.bucket_id = mid; 300 | pos.found = false; 301 | pos.item = NULL; 302 | pos.parent = parent; 303 | return pos; 304 | } 305 | 306 | // Create our own memory for the item value so we don't have to worry about local values and such. 307 | void *djbhash_value( void *value, int data_type, int count ) 308 | { 309 | int i; 310 | int *temp, *iter; 311 | double *temp2; 312 | unsigned char *temp3; 313 | void *ptr; 314 | struct djbhash *temp4; 315 | struct djbhash_node *item; 316 | unsigned char *str; 317 | int length; 318 | void **temp5; 319 | 320 | switch( data_type ) 321 | { 322 | case DJBHASH_INT: 323 | temp = malloc( sizeof( int ) ); 324 | *temp = *( int * )value; 325 | ptr = temp; 326 | break; 327 | case DJBHASH_DOUBLE: 328 | temp2 = malloc( sizeof( double ) ); 329 | *temp2 = *( double * )value; 330 | ptr = temp2; 331 | break; 332 | case DJBHASH_CHAR: 333 | temp3 = malloc( sizeof( unsigned char ) ); 334 | *temp3 = *( unsigned char * )value; 335 | ptr = temp3; 336 | break; 337 | case DJBHASH_STRING: 338 | length = strlen( ( char * )value ); 339 | str = calloc( length + 1, sizeof( unsigned char ) ); 340 | memcpy( str, ( char * )value, length ); 341 | ptr = str; 342 | break; 343 | case DJBHASH_ARRAY: 344 | temp = malloc( sizeof( int ) * count ); 345 | iter = value; 346 | for ( i = 0; i < count; i++ ) 347 | temp[i] = iter[i]; 348 | ptr = temp; 349 | break; 350 | case DJBHASH_HASH: 351 | temp4 = malloc( sizeof( struct djbhash ) ); 352 | djbhash_init( temp4 ); 353 | item = djbhash_iterate( ( struct djbhash * )value ); 354 | while ( item ) 355 | { 356 | djbhash_set( temp4, item->key, item->value, item->data_type, item->count ); 357 | item = djbhash_iterate( ( struct djbhash * )value ); 358 | } 359 | djbhash_reset_iterator( ( struct djbhash * )value ); 360 | ptr = temp4; 361 | break; 362 | default: 363 | ptr = value; 364 | } 365 | return ptr; 366 | } 367 | 368 | // Set the value for an item in the hash table using array hash table. 369 | int djbhash_set( struct djbhash *hash, char *key, void *value, int data_type, ... ) 370 | { 371 | int i; 372 | int chunks; 373 | struct djbhash_search search; 374 | unsigned int bucket_id; 375 | int length; 376 | va_list arg_ptr; 377 | struct djbhash_node *iter, *temp; 378 | int method; 379 | int count; 380 | 381 | // Default invalid data types. 382 | if ( data_type < DJBHASH_INT || data_type > DJBHASH_OTHER_MALLOCD ) 383 | data_type = DJBHASH_STRING; 384 | 385 | // If the data type is an array, track how many items the array has. 386 | if ( data_type == DJBHASH_ARRAY ) 387 | { 388 | va_start( arg_ptr, 1 ); 389 | count = va_arg( arg_ptr, int ); 390 | va_end( arg_ptr ); 391 | } 392 | 393 | // Calculate the key length and bucket ID. 394 | length = strlen( key ); 395 | bucket_id = djb_hash( key, length ); 396 | 397 | // Find our insert/update/append position. 398 | search = djbhash_bin_search( hash, 0, DJBHASH_MAX_BUCKETS - 1, bucket_id, key, length ); 399 | 400 | // If we found the item with this key, we need to just update it. 401 | if ( search.found ) 402 | { 403 | free( search.item->value ); 404 | search.item->value = djbhash_value( value, data_type, count ); 405 | return true; 406 | } 407 | 408 | // Create our hash item. 409 | temp = malloc( sizeof( struct djbhash_node ) ); 410 | temp->key = calloc( length + 1, sizeof( unsigned char ) ); 411 | memcpy( temp->key, key, length ); 412 | temp->value = djbhash_value( value, data_type, count ); 413 | temp->data_type = data_type; 414 | temp->count = count; 415 | temp->next = NULL; 416 | 417 | if ( search.parent == NULL ) 418 | { 419 | hash->buckets[search.bucket_id].list = temp; 420 | hash->active_count++; 421 | hash->active[hash->active_count - 1] = search.bucket_id; 422 | } else 423 | { 424 | search.parent->next = temp; 425 | } 426 | } 427 | 428 | // Find an item in the hash table using linked lists. 429 | struct djbhash_node *djbhash_find( struct djbhash *hash, char *key ) 430 | { 431 | int length; 432 | int bucket_id; 433 | struct djbhash_search search; 434 | struct djbhash_node *searcher; 435 | 436 | length = strlen( key ); 437 | bucket_id = djb_hash( key, length ); 438 | search = djbhash_bin_search( hash, 0, DJBHASH_MAX_BUCKETS - 1, bucket_id, key, length ); 439 | return search.item; 440 | } 441 | 442 | // Remove an item from the hash. 443 | int djbhash_remove( struct djbhash *hash, char *key ) 444 | { 445 | int i, offset; 446 | int length; 447 | int bucket_id; 448 | struct djbhash_search search; 449 | struct djbhash_node *item, *parent, *next; 450 | 451 | length = strlen( key ); 452 | bucket_id = djb_hash( key, length ); 453 | search = djbhash_bin_search( hash, 0, DJBHASH_MAX_BUCKETS - 1, bucket_id, key, length ); 454 | 455 | // If we don't find the item, we obviously can't remove it. 456 | if ( !search.found ) 457 | return false; 458 | 459 | // Otherwise, free the item, and set the parent node's next to the item's next. 460 | item = search.item; 461 | parent = search.parent; 462 | next = search.item->next; 463 | 464 | if ( parent == item ) 465 | { 466 | hash->buckets[search.bucket_id].list = next; 467 | if ( hash->buckets[search.bucket_id].list == NULL ) 468 | { 469 | offset = 0; 470 | // Remove this from active buckets. 471 | for ( i = 0; i < hash->active_count; i++ ) 472 | { 473 | if ( hash->active[i] == search.bucket_id ) 474 | offset = 1; 475 | else 476 | hash->active[i - offset] = hash->active[i]; 477 | } 478 | hash->active_count--; 479 | } 480 | } else 481 | { 482 | parent->next = next; 483 | } 484 | 485 | djbhash_free_node( search.item ); 486 | return true; 487 | } 488 | 489 | // Dump all data in the hash table using linked lists. 490 | void djbhash_dump( struct djbhash *hash ) 491 | { 492 | int i; 493 | struct djbhash_node *iter; 494 | 495 | for ( i = 0; i < hash->active_count; i++ ) 496 | { 497 | iter = hash->buckets[hash->active[i]].list; 498 | while ( iter ) 499 | { 500 | djbhash_print( iter ); 501 | iter = iter->next; 502 | } 503 | } 504 | } 505 | 506 | // Iterate through all hash items one at a time. 507 | struct djbhash_node *djbhash_iterate( struct djbhash *hash ) 508 | { 509 | if ( hash->iter.node == NULL && hash->iter.last == NULL ) 510 | { 511 | if ( hash->active_count > 0 ) 512 | { 513 | hash->iter.node = hash->buckets[hash->active[0]].list; 514 | return hash->iter.node; 515 | } 516 | return NULL; 517 | } else if ( hash->iter.node == NULL ) 518 | return NULL; 519 | 520 | hash->iter.last = hash->iter.node; 521 | hash->iter.node = hash->iter.node->next; 522 | if ( hash->iter.node == NULL ) 523 | { 524 | if ( hash->iter.id == hash->active_count - 1 ) 525 | return NULL; 526 | hash->iter.id++; 527 | hash->iter.node = hash->buckets[hash->active[hash->iter.id]].list; 528 | } 529 | return hash->iter.node; 530 | } 531 | 532 | // Reset iterator. 533 | void djbhash_reset_iterator( struct djbhash *hash ) 534 | { 535 | hash->iter.id = 0; 536 | hash->iter.node = NULL; 537 | hash->iter.last = NULL; 538 | } 539 | 540 | // Free memory used by a node. 541 | void djbhash_free_node( struct djbhash_node *item ) 542 | { 543 | if ( item->key != NULL ) 544 | { 545 | free( item->key ); 546 | item->key = NULL; 547 | } 548 | if ( item->value != NULL && item->data_type != DJBHASH_OTHER && item->data_type != DJBHASH_HASH ) 549 | { 550 | free( item->value ); 551 | item->value = NULL; 552 | } else if ( item->data_type == DJBHASH_HASH ) 553 | { 554 | djbhash_destroy( ( struct djbhash * )item->value ); 555 | free( item->value ); 556 | item->value = NULL; 557 | } 558 | free( item ); 559 | item = NULL; 560 | } 561 | 562 | // Remove all elements from the hash table. 563 | void djbhash_empty( struct djbhash *hash ) 564 | { 565 | int i; 566 | struct djbhash_node *iter; 567 | struct djbhash_node *next; 568 | for ( i = 0; i < DJBHASH_MAX_BUCKETS; i++ ) 569 | { 570 | iter = hash->buckets[i].list; 571 | while ( iter ) 572 | { 573 | next = iter->next; 574 | djbhash_free_node( iter ); 575 | iter = next; 576 | } 577 | } 578 | hash->active_count = 0; 579 | } 580 | 581 | // Remove all elements and frees memory used by the hash table. 582 | void djbhash_destroy( struct djbhash *hash ) 583 | { 584 | djbhash_empty( hash ); 585 | free( hash->buckets ); 586 | hash->buckets = NULL; 587 | free( hash->active ); 588 | hash->active = NULL; 589 | } 590 | -------------------------------------------------------------------------------- /src/djbhash.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef true 7 | #define true 1 8 | #endif 9 | #ifndef false 10 | #define false 0 11 | #endif 12 | 13 | #define DJBHASH_MAX_BUCKETS 65536 14 | 15 | // Node structure 16 | struct djbhash_node { 17 | // Key string. 18 | char *key; 19 | // Generic pointer to value. 20 | void *value; 21 | // Data type for this node. 22 | int data_type; 23 | // If it's an array data type, the number of items. 24 | int count; 25 | // Pointer to the next node in the list. 26 | struct djbhash_node *next; 27 | }; 28 | 29 | // Iterator object. 30 | struct djbhash_iterator { 31 | // Active ID. 32 | int id; 33 | // Node pointer. 34 | struct djbhash_node *node; 35 | // Last pointer. 36 | struct djbhash_node *last; 37 | }; 38 | 39 | // Linked list bucket structure. 40 | struct djbhash_bucket { 41 | // Bucket ID. 42 | unsigned int id; 43 | // Linked list containing items. 44 | struct djbhash_node *list; 45 | }; 46 | 47 | // Linked list structure. 48 | struct djbhash { 49 | // Buckets. 50 | struct djbhash_bucket *buckets; 51 | // List of active buckets. 52 | int *active; 53 | // Number of active buckets. 54 | int active_count; 55 | // Iterator to get through all elements. 56 | struct djbhash_iterator iter; 57 | }; 58 | 59 | // Position when searching for an item. 60 | struct djbhash_search { 61 | // Bucket ID 62 | unsigned int bucket_id; 63 | // Whether or not the item was actually found. 64 | int found; 65 | // The item that matches. 66 | struct djbhash_node *item; 67 | // The parent of the item that matches (for deleting). 68 | struct djbhash_node *parent; 69 | }; 70 | 71 | // Some various return functions. 72 | enum djbhash_data_type { 73 | DJBHASH_INT, 74 | DJBHASH_DOUBLE, 75 | DJBHASH_CHAR, 76 | DJBHASH_STRING, 77 | DJBHASH_ARRAY, 78 | DJBHASH_HASH, 79 | DJBHASH_OTHER, 80 | DJBHASH_OTHER_MALLOCD, 81 | }; 82 | 83 | // Function declarations. 84 | unsigned char *djbhash_int_to_a( int number ); 85 | unsigned char *djbhash_double_to_a( double number ); 86 | unsigned char *djbhash_json_array( int *array, int count ); 87 | unsigned char *djbhash_escaped( unsigned char *data ); 88 | unsigned char *djbhash_value_to_json( struct djbhash_node *item ); 89 | unsigned char *djbhash_to_json( struct djbhash *hash ); 90 | void djbhash_print_value( struct djbhash_node *item ); 91 | void djbhash_print( struct djbhash_node *item ); 92 | void djbhash_init( struct djbhash *hash ); 93 | unsigned int djb_hash( char *key, int length ); 94 | struct djbhash_search djbhash_bin_search( struct djbhash *hash, unsigned int min, unsigned int max, unsigned int bucket_id, char *key, int length ); 95 | void *djbhash_value( void *value, int data_type, int count ); 96 | int djbhash_set( struct djbhash *hash, char *key, void *value, int data_type, ... ); 97 | struct djbhash_node *djbhash_find( struct djbhash *hash, char *key ); 98 | int djbhash_remove( struct djbhash *hash, char *key ); 99 | void djbhash_dump( struct djbhash *hash ); 100 | struct djbhash_node *djbhash_iterate( struct djbhash *hash ); 101 | void djbhash_reset_iterator( struct djbhash *hash ); 102 | void djbhash_free_node( struct djbhash_node *item ); 103 | void djbhash_empty( struct djbhash *hash ); 104 | void djbhash_destroy( struct djbhash *hash ); 105 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include "djbhash.h" 2 | 3 | struct test_struct { 4 | int a; 5 | int b; 6 | }; 7 | 8 | int main( int argc, char *argv[] ) 9 | { 10 | // Hash table structure. 11 | struct djbhash hash; 12 | // Return value from finding a key. 13 | struct djbhash_node *item; 14 | 15 | // Initialize the hash table. 16 | djbhash_init( &hash ); 17 | 18 | // Set hash values with various data types. 19 | int temp = 10; 20 | djbhash_set( &hash, "int", &temp, DJBHASH_INT ); 21 | double temp2 = 3.14159; 22 | djbhash_set( &hash, "double", &temp2, DJBHASH_DOUBLE ); 23 | char temp3 = 'a'; 24 | djbhash_set( &hash, "char", &temp3, DJBHASH_CHAR ); 25 | djbhash_set( &hash, "string", "bar", DJBHASH_STRING ); 26 | int temp_arr[] = { 8, 6, 7, 5, 3, 0, 9 }; 27 | djbhash_set( &hash, "array", temp_arr, DJBHASH_ARRAY, 7 ); 28 | struct djbhash temp_hash; 29 | djbhash_init( &temp_hash ); 30 | djbhash_set( &temp_hash, "foo", "bar", DJBHASH_STRING ); 31 | djbhash_set( &temp_hash, "baz", temp_arr, DJBHASH_ARRAY, 7 ); 32 | djbhash_set( &hash, "hash", &temp_hash, DJBHASH_HASH ); 33 | struct test_struct test; 34 | test.a = 10; 35 | test.b = 11; 36 | djbhash_set( &hash, "other", &test, DJBHASH_OTHER ); 37 | 38 | // Find and print items. 39 | printf( "Finding single items...\n" ); 40 | item = djbhash_find( &hash, "int" ); 41 | djbhash_print( item ); 42 | item = djbhash_find( &hash, "double" ); 43 | djbhash_print( item ); 44 | item = djbhash_find( &hash, "char" ); 45 | djbhash_print( item ); 46 | item = djbhash_find( &hash, "string" ); 47 | djbhash_print( item ); 48 | item = djbhash_find( &hash, "array" ); 49 | djbhash_print( item ); 50 | item = djbhash_find( &hash, "hash" ); 51 | djbhash_print( item ); 52 | item = djbhash_find( &hash, "other" ); 53 | djbhash_print( item ); 54 | 55 | // Remove an item. 56 | printf( "\nRemoving key \"int\"...\n" ); 57 | djbhash_remove( &hash, "int" ); 58 | if ( djbhash_find( &hash, "int" ) == NULL ) 59 | printf( "int removed\n" ); 60 | 61 | // Print all items. 62 | printf( "\nDumping all items...\n" ); 63 | djbhash_dump( &hash ); 64 | 65 | // Iterate through items. 66 | printf( "\nIterating...\n" ); 67 | item = djbhash_iterate( &hash ); 68 | while ( item ) 69 | { 70 | djbhash_print( item ); 71 | item = djbhash_iterate( &hash ); 72 | } 73 | // Reset the iterator. 74 | djbhash_reset_iterator( &hash ); 75 | 76 | // Search for an item that doesn't exist: 77 | char *missing = "missing key"; 78 | printf( "\nSearching for a missing key \"%s\"...\n", missing ); 79 | if ( ( item = djbhash_find( &hash, missing ) ) == NULL ) 80 | printf( "%s: No such item!\n", missing ); 81 | 82 | // Printing a hash as JSON. 83 | char *json = djbhash_to_json( &hash ); 84 | printf( "\nHash to json: %s\n", json ); 85 | free( json ); 86 | json = NULL; 87 | 88 | // Remove all items and free memory. 89 | djbhash_destroy( &temp_hash ); 90 | djbhash_destroy( &hash ); 91 | 92 | return 0; 93 | } 94 | --------------------------------------------------------------------------------