hashtable.c (jansson-2.13.1.tar.bz2) | : | hashtable.c (jansson-2.14.tar.bz2) | ||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
typedef struct hashtable_pair pair_t; | typedef struct hashtable_pair pair_t; | |||
typedef struct hashtable_bucket bucket_t; | typedef struct hashtable_bucket bucket_t; | |||
extern volatile uint32_t hashtable_seed; | extern volatile uint32_t hashtable_seed; | |||
/* Implementation of the hash function */ | /* Implementation of the hash function */ | |||
#include "lookup3.h" | #include "lookup3.h" | |||
#define list_to_pair(list_) container_of(list_, pair_t, list) | #define list_to_pair(list_) container_of(list_, pair_t, list) | |||
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) | #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) | |||
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hash table_seed)) | #define hash_str(key, len) ((size_t)hashlittle((key), len, hashtable_se ed)) | |||
static JSON_INLINE void list_init(list_t *list) { | static JSON_INLINE void list_init(list_t *list) { | |||
list->next = list; | list->next = list; | |||
list->prev = list; | list->prev = list; | |||
} | } | |||
static JSON_INLINE void list_insert(list_t *list, list_t *node) { | static JSON_INLINE void list_insert(list_t *list, list_t *node) { | |||
node->next = list; | node->next = list; | |||
node->prev = list->prev; | node->prev = list->prev; | |||
list->prev->next = node; | list->prev->next = node; | |||
skipping to change at line 72 | skipping to change at line 72 | |||
if (bucket_is_empty(hashtable, bucket)) { | if (bucket_is_empty(hashtable, bucket)) { | |||
list_insert(&hashtable->list, list); | list_insert(&hashtable->list, list); | |||
bucket->first = bucket->last = list; | bucket->first = bucket->last = list; | |||
} else { | } else { | |||
list_insert(bucket->first, list); | list_insert(bucket->first, list); | |||
bucket->first = list; | bucket->first = list; | |||
} | } | |||
} | } | |||
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, | static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, | |||
const char *key, size_t hash) { | const char *key, size_t key_len, size_t hash) { | |||
list_t *list; | list_t *list; | |||
pair_t *pair; | pair_t *pair; | |||
if (bucket_is_empty(hashtable, bucket)) | if (bucket_is_empty(hashtable, bucket)) | |||
return NULL; | return NULL; | |||
list = bucket->first; | list = bucket->first; | |||
while (1) { | while (1) { | |||
pair = list_to_pair(list); | pair = list_to_pair(list); | |||
if (pair->hash == hash && strcmp(pair->key, key) == 0) | if (pair->hash == hash && pair->key_len == key_len && | |||
memcmp(pair->key, key, key_len) == 0) | ||||
return pair; | return pair; | |||
if (list == bucket->last) | if (list == bucket->last) | |||
break; | break; | |||
list = list->next; | list = list->next; | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
/* returns 0 on success, -1 if key was not found */ | /* returns 0 on success, -1 if key was not found */ | |||
static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash | static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_ | |||
) { | len, | |||
size_t hash) { | ||||
pair_t *pair; | pair_t *pair; | |||
bucket_t *bucket; | bucket_t *bucket; | |||
size_t index; | size_t index; | |||
index = hash & hashmask(hashtable->order); | index = hash & hashmask(hashtable->order); | |||
bucket = &hashtable->buckets[index]; | bucket = &hashtable->buckets[index]; | |||
pair = hashtable_find_pair(hashtable, bucket, key, hash); | pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); | |||
if (!pair) | if (!pair) | |||
return -1; | return -1; | |||
if (&pair->list == bucket->first && &pair->list == bucket->last) | if (&pair->list == bucket->first && &pair->list == bucket->last) | |||
bucket->first = bucket->last = &hashtable->list; | bucket->first = bucket->last = &hashtable->list; | |||
else if (&pair->list == bucket->first) | else if (&pair->list == bucket->first) | |||
bucket->first = pair->list.next; | bucket->first = pair->list.next; | |||
else if (&pair->list == bucket->last) | else if (&pair->list == bucket->last) | |||
skipping to change at line 196 | skipping to change at line 198 | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
void hashtable_close(hashtable_t *hashtable) { | void hashtable_close(hashtable_t *hashtable) { | |||
hashtable_do_clear(hashtable); | hashtable_do_clear(hashtable); | |||
jsonp_free(hashtable->buckets); | jsonp_free(hashtable->buckets); | |||
} | } | |||
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { | static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t | |||
hash) { | ||||
pair_t *pair; | ||||
/* offsetof(...) returns the size of pair_t without the last, | ||||
flexible member. This way, the correct amount is | ||||
allocated. */ | ||||
if (key_len >= (size_t)-1 - offsetof(pair_t, key)) { | ||||
/* Avoid an overflow if the key is very long */ | ||||
return NULL; | ||||
} | ||||
pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1); | ||||
if (!pair) | ||||
return NULL; | ||||
pair->hash = hash; | ||||
memcpy(pair->key, key, key_len); | ||||
pair->key[key_len] = '\0'; | ||||
pair->key_len = key_len; | ||||
pair->value = value; | ||||
list_init(&pair->list); | ||||
list_init(&pair->ordered_list); | ||||
return pair; | ||||
} | ||||
int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, | ||||
json_t *value) { | ||||
pair_t *pair; | pair_t *pair; | |||
bucket_t *bucket; | bucket_t *bucket; | |||
size_t hash, index; | size_t hash, index; | |||
/* rehash if the load ratio exceeds 1 */ | /* rehash if the load ratio exceeds 1 */ | |||
if (hashtable->size >= hashsize(hashtable->order)) | if (hashtable->size >= hashsize(hashtable->order)) | |||
if (hashtable_do_rehash(hashtable)) | if (hashtable_do_rehash(hashtable)) | |||
return -1; | return -1; | |||
hash = hash_str(key); | hash = hash_str(key, key_len); | |||
index = hash & hashmask(hashtable->order); | index = hash & hashmask(hashtable->order); | |||
bucket = &hashtable->buckets[index]; | bucket = &hashtable->buckets[index]; | |||
pair = hashtable_find_pair(hashtable, bucket, key, hash); | pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); | |||
if (pair) { | if (pair) { | |||
json_decref(pair->value); | json_decref(pair->value); | |||
pair->value = value; | pair->value = value; | |||
} else { | } else { | |||
/* offsetof(...) returns the size of pair_t without the last, | pair = init_pair(value, key, key_len, hash); | |||
flexible member. This way, the correct amount is | ||||
allocated. */ | ||||
size_t len = strlen(key); | ||||
if (len >= (size_t)-1 - offsetof(pair_t, key)) { | ||||
/* Avoid an overflow if the key is very long */ | ||||
return -1; | ||||
} | ||||
pair = jsonp_malloc(offsetof(pair_t, key) + len + 1); | ||||
if (!pair) | if (!pair) | |||
return -1; | return -1; | |||
pair->hash = hash; | ||||
strncpy(pair->key, key, len + 1); | ||||
pair->value = value; | ||||
list_init(&pair->list); | ||||
list_init(&pair->ordered_list); | ||||
insert_to_bucket(hashtable, bucket, &pair->list); | insert_to_bucket(hashtable, bucket, &pair->list); | |||
list_insert(&hashtable->ordered_list, &pair->ordered_list); | list_insert(&hashtable->ordered_list, &pair->ordered_list); | |||
hashtable->size++; | hashtable->size++; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
void *hashtable_get(hashtable_t *hashtable, const char *key) { | void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) { | |||
pair_t *pair; | pair_t *pair; | |||
size_t hash; | size_t hash; | |||
bucket_t *bucket; | bucket_t *bucket; | |||
hash = hash_str(key); | hash = hash_str(key, key_len); | |||
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; | bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; | |||
pair = hashtable_find_pair(hashtable, bucket, key, hash); | pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); | |||
if (!pair) | if (!pair) | |||
return NULL; | return NULL; | |||
return pair->value; | return pair->value; | |||
} | } | |||
int hashtable_del(hashtable_t *hashtable, const char *key) { | int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) { | |||
size_t hash = hash_str(key); | size_t hash = hash_str(key, key_len); | |||
return hashtable_do_del(hashtable, key, hash); | return hashtable_do_del(hashtable, key, key_len, hash); | |||
} | } | |||
void hashtable_clear(hashtable_t *hashtable) { | void hashtable_clear(hashtable_t *hashtable) { | |||
size_t i; | size_t i; | |||
hashtable_do_clear(hashtable); | hashtable_do_clear(hashtable); | |||
for (i = 0; i < hashsize(hashtable->order); i++) { | for (i = 0; i < hashsize(hashtable->order); i++) { | |||
hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->l ist; | hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->l ist; | |||
} | } | |||
list_init(&hashtable->list); | list_init(&hashtable->list); | |||
list_init(&hashtable->ordered_list); | list_init(&hashtable->ordered_list); | |||
hashtable->size = 0; | hashtable->size = 0; | |||
} | } | |||
void *hashtable_iter(hashtable_t *hashtable) { | void *hashtable_iter(hashtable_t *hashtable) { | |||
return hashtable_iter_next(hashtable, &hashtable->ordered_list); | return hashtable_iter_next(hashtable, &hashtable->ordered_list); | |||
} | } | |||
void *hashtable_iter_at(hashtable_t *hashtable, const char *key) { | void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) { | |||
pair_t *pair; | pair_t *pair; | |||
size_t hash; | size_t hash; | |||
bucket_t *bucket; | bucket_t *bucket; | |||
hash = hash_str(key); | hash = hash_str(key, key_len); | |||
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; | bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; | |||
pair = hashtable_find_pair(hashtable, bucket, key, hash); | pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); | |||
if (!pair) | if (!pair) | |||
return NULL; | return NULL; | |||
return &pair->ordered_list; | return &pair->ordered_list; | |||
} | } | |||
void *hashtable_iter_next(hashtable_t *hashtable, void *iter) { | void *hashtable_iter_next(hashtable_t *hashtable, void *iter) { | |||
list_t *list = (list_t *)iter; | list_t *list = (list_t *)iter; | |||
if (list->next == &hashtable->ordered_list) | if (list->next == &hashtable->ordered_list) | |||
return NULL; | return NULL; | |||
return list->next; | return list->next; | |||
} | } | |||
void *hashtable_iter_key(void *iter) { | void *hashtable_iter_key(void *iter) { | |||
pair_t *pair = ordered_list_to_pair((list_t *)iter); | pair_t *pair = ordered_list_to_pair((list_t *)iter); | |||
return pair->key; | return pair->key; | |||
} | } | |||
size_t hashtable_iter_key_len(void *iter) { | ||||
pair_t *pair = ordered_list_to_pair((list_t *)iter); | ||||
return pair->key_len; | ||||
} | ||||
void *hashtable_iter_value(void *iter) { | void *hashtable_iter_value(void *iter) { | |||
pair_t *pair = ordered_list_to_pair((list_t *)iter); | pair_t *pair = ordered_list_to_pair((list_t *)iter); | |||
return pair->value; | return pair->value; | |||
} | } | |||
void hashtable_iter_set(void *iter, json_t *value) { | void hashtable_iter_set(void *iter, json_t *value) { | |||
pair_t *pair = ordered_list_to_pair((list_t *)iter); | pair_t *pair = ordered_list_to_pair((list_t *)iter); | |||
json_decref(pair->value); | json_decref(pair->value); | |||
pair->value = value; | pair->value = value; | |||
End of changes. 19 change blocks. | ||||
34 lines changed or deleted | 57 lines changed or added |