12 #include "dictionary.h"
14 // ----------------------------------------------------------------------------
17 static int name_value_iterator(avl *a) { if(a) {}; return 0; }
19 static int name_value_compare(void* a, void* b) {
20 if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
21 else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
22 else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
25 #define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
26 #define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
28 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
29 NAME_VALUE *result = NULL, tmp;
30 tmp.hash = (hash)?hash:simple_hash(name);
31 tmp.name = (char *)name;
34 avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
38 static void dictionary_read_lock(DICTIONARY *dict) {
39 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED)))
40 pthread_rwlock_rdlock(&dict->rwlock);
43 static void dictionary_write_lock(DICTIONARY *dict) {
44 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED)))
45 pthread_rwlock_wrlock(&dict->rwlock);
48 static void dictionary_unlock(DICTIONARY *dict) {
49 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED)))
50 pthread_rwlock_unlock(&dict->rwlock);
53 // ----------------------------------------------------------------------------
55 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
56 debug(D_DICTIONARY, "Creating name value entry for name '%s', value '%s'.", name, value);
58 NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
59 if(unlikely(!nv)) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
61 nv->name = strdup(name);
62 if(unlikely(!nv->name))
63 fatal("Cannot allocate name_value.name of size %z", strlen(name));
65 nv->hash = (hash)?hash:simple_hash(nv->name);
67 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
70 nv->value = malloc(value_len);
71 if (unlikely(!nv->value))
72 fatal("Cannot allocate name_value.value of size %z", value_len);
74 memcpy(nv->value, value, value_len);
77 dictionary_write_lock(dict);
80 dictionary_name_value_index_add_nolock(dict, nv);
84 dictionary_unlock(dict);
89 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
90 debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
92 dictionary_name_value_index_del_nolock(dict, nv);
98 if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE))
104 // ----------------------------------------------------------------------------
106 DICTIONARY *dictionary_create(uint32_t flags) {
107 debug(D_DICTIONARY, "Creating dictionary.");
109 DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
110 if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
112 avl_init(&dict->values_index, name_value_compare);
113 pthread_rwlock_init(&dict->rwlock, NULL);
120 void dictionary_destroy(DICTIONARY *dict) {
121 debug(D_DICTIONARY, "Destroying dictionary.");
123 dictionary_write_lock(dict);
125 while(dict->values_index.root)
126 dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
128 dictionary_unlock(dict);
133 // ----------------------------------------------------------------------------
135 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
136 debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
138 uint32_t hash = simple_hash(name);
140 dictionary_read_lock(dict);
141 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
142 dictionary_unlock(dict);
145 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
147 pthread_rwlock_wrlock(&dict->rwlock);
148 nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
151 fatal("Cannot create name_value.");
153 dictionary_unlock(dict);
156 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
158 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
161 void *value = malloc(value_len),
164 if(unlikely(!nv->value))
165 fatal("Cannot allocate value of size %z", value_len);
167 memcpy(value, value, value_len);
177 void *dictionary_get(DICTIONARY *dict, const char *name) {
178 debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
180 dictionary_read_lock(dict);
181 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
182 dictionary_unlock(dict);
185 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
189 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
193 void dictionary_del(DICTIONARY *dict, const char *name) {
194 debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
196 dictionary_read_lock(dict);
197 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
198 dictionary_unlock(dict);
201 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
205 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
206 pthread_rwlock_wrlock(&dict->rwlock);
207 dictionary_name_value_destroy_nolock(dict, nv);
208 dictionary_unlock(dict);