Need those
This commit is contained in:
		
							parent
							
								
									c9bee1793c
								
							
						
					
					
						commit
						4ea9f5f2dd
					
				
					 2 changed files with 191 additions and 0 deletions
				
			
		
							
								
								
									
										171
									
								
								src/dict.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/dict.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,171 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <patty/dict.h>
 | 
			
		||||
#include <patty/hash.h>
 | 
			
		||||
 | 
			
		||||
patty_dict *patty_dict_new() {
 | 
			
		||||
    patty_dict *dict;
 | 
			
		||||
 | 
			
		||||
    if ((dict = malloc(sizeof(*dict))) == NULL) {
 | 
			
		||||
        goto error_malloc_dict;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(dict, 0x00, sizeof(*dict));
 | 
			
		||||
 | 
			
		||||
    return dict;
 | 
			
		||||
 | 
			
		||||
error_malloc_dict:
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t hash) {
 | 
			
		||||
    patty_dict_bucket *bucket = &dict->bucket;
 | 
			
		||||
 | 
			
		||||
    int collisions;
 | 
			
		||||
 | 
			
		||||
    for (collisions = 0; collisions < 7; collisions++) {
 | 
			
		||||
        uint32_t mask  = 0x0f << (4 * collisions);
 | 
			
		||||
        uint8_t  index = (hash & mask) >> (4 * collisions);
 | 
			
		||||
 | 
			
		||||
        patty_dict_slot *slot = &bucket->slots[index];
 | 
			
		||||
 | 
			
		||||
        if (slot->hash == 0x00000000) {
 | 
			
		||||
            /*
 | 
			
		||||
             * In this case, we have determined that there is no value in the
 | 
			
		||||
             * dict for the given hash.
 | 
			
		||||
             */
 | 
			
		||||
            return NULL;
 | 
			
		||||
        } else if (slot->hash == hash) {
 | 
			
		||||
            /*
 | 
			
		||||
             * We have found the desired slot, so return that.
 | 
			
		||||
             */
 | 
			
		||||
            return slot;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Otherwise, look for the next bucket, if present.
 | 
			
		||||
         */
 | 
			
		||||
        bucket = (patty_dict_bucket *)slot->next;
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * If there is no next bucket available, then return null.
 | 
			
		||||
         */
 | 
			
		||||
        if (bucket == NULL) {
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bucket_each_slot(int level, patty_dict_bucket *bucket, patty_dict_callback callback, void *ctx) {
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (level > 7) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<PATTY_DICT_BUCKET_SIZE; i++) {
 | 
			
		||||
        patty_dict_slot *slot = &bucket->slots[i];
 | 
			
		||||
 | 
			
		||||
        if (slot->key != NULL && slot->keysz > 0) {
 | 
			
		||||
            if (callback(slot->key, slot->keysz, slot->value, ctx) < 0) {
 | 
			
		||||
                goto error_callback;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (slot->next) {
 | 
			
		||||
            return bucket_each_slot(level+1, (patty_dict_bucket *)slot->next, callback, ctx);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
error_callback:
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int patty_dict_each(patty_dict *dict, patty_dict_callback callback, void *ctx) {
 | 
			
		||||
    return bucket_each_slot(0, &dict->bucket, callback, ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *patty_dict_get(patty_dict *dict, void *key, size_t keysz) {
 | 
			
		||||
    patty_dict_slot *slot;
 | 
			
		||||
 | 
			
		||||
    uint32_t hash = patty_hash(key, keysz);
 | 
			
		||||
 | 
			
		||||
    if ((slot = patty_dict_slot_find(dict, hash)) == NULL) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return slot->value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value) {
 | 
			
		||||
    patty_dict_bucket *bucket = &dict->bucket;
 | 
			
		||||
 | 
			
		||||
    uint32_t hash = patty_hash(key, keysz);
 | 
			
		||||
 | 
			
		||||
    int collisions;
 | 
			
		||||
 | 
			
		||||
    for (collisions = 0; collisions < 7; collisions++) {
 | 
			
		||||
        uint32_t mask  = 0x0f << (4 * collisions);
 | 
			
		||||
        uint8_t  index = (hash & mask) >> (4 * collisions);
 | 
			
		||||
 | 
			
		||||
        patty_dict_slot *slot = &bucket->slots[index];
 | 
			
		||||
 | 
			
		||||
        if (slot->hash == 0x00000000 && slot->key == NULL) {
 | 
			
		||||
            /*
 | 
			
		||||
             * We have found an empty hash slot, so let's store the value.
 | 
			
		||||
             */
 | 
			
		||||
            slot->hash  = hash;
 | 
			
		||||
            slot->key   = key;
 | 
			
		||||
            slot->keysz = keysz;
 | 
			
		||||
            slot->value = value;
 | 
			
		||||
 | 
			
		||||
            return value;
 | 
			
		||||
        } else if (slot->hash == hash) {
 | 
			
		||||
            /*
 | 
			
		||||
             * Otherwise, we've found an existing slot, so let's update that
 | 
			
		||||
             * and bail.
 | 
			
		||||
             */
 | 
			
		||||
            return slot->value = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Take a look to see if there is a next bucket in the chain.
 | 
			
		||||
         */
 | 
			
		||||
        bucket = (patty_dict_bucket *)slot->next;
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * If there is no next bucket available, then create one.
 | 
			
		||||
         */
 | 
			
		||||
        if (bucket == NULL) {
 | 
			
		||||
            if ((bucket = malloc(sizeof(*bucket))) == NULL) {
 | 
			
		||||
                goto error_malloc_bucket;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            memset(bucket, 0x00, sizeof(*bucket));
 | 
			
		||||
 | 
			
		||||
            slot->next = (patty_dict_slot *)bucket;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
error_malloc_bucket:
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dict_item_release(void *key, size_t keysz, void *value, void *ctx) {
 | 
			
		||||
    free(value);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void patty_dict_destroy(patty_dict *dict) {
 | 
			
		||||
    (void)patty_dict_each(dict, dict_item_release, NULL);
 | 
			
		||||
 | 
			
		||||
    free(dict);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/hash.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/hash.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <patty/hash.h>
 | 
			
		||||
 | 
			
		||||
uint32_t patty_hash(void *key, size_t size) {
 | 
			
		||||
    uint32_t hash = 0, i;
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<size; i++) {
 | 
			
		||||
        hash += ((uint8_t *)key)[i];
 | 
			
		||||
        hash += (hash << 10);
 | 
			
		||||
        hash ^= (hash >>  6);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hash += (hash << 3);
 | 
			
		||||
    hash ^= (hash >> 11);
 | 
			
		||||
    hash += (hash << 15);
 | 
			
		||||
 | 
			
		||||
    return hash;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue