4 * Created on: 16 mars 2011
10 #include "xbt/misc.h" /* SG_BEGIN_DECL */
11 #include "xbt/mallocator.h"
14 #include "xbt_modinter.h"
17 #define DJB2_HASH_FUNCTION
18 //#define FNV_HASH_FUNCTION
20 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_lib, xbt,
21 "Libraries provide the same functionalities than hash tables");
23 xbt_mallocator_t lib_mallocator = NULL;
25 /*####[ Private prototypes ]#################################################*/
26 static void *lib_mallocator_new_f(void);
27 static void lib_mallocator_free_f(void *dict);
28 static void lib_mallocator_reset_f(void *dict);
30 static void xbt_lib_set_ext(xbt_lib_t lib,const char *key,
31 int key_len, int level, void *data);
33 static unsigned int xbt_lib_hash_ext(const char *str,
35 static unsigned int xbt_lib_hash(const char *str);
36 static void xbt_lib_rehash(xbt_lib_t lib);
39 static xbt_lib_cursor_t xbt_lib_cursor_new(const xbt_lib_t lib);
40 static void xbt_lib_cursor_rewind(xbt_lib_cursor_t cursor);
41 static void xbt_lib_cursor_free(xbt_lib_cursor_t * cursor);
43 /*####[ Code ]###############################################################*/
45 void xbt_lib_preinit(void)
47 if (lib_mallocator != NULL) {
48 xbt_mallocator_free(lib_mallocator);
51 lib_mallocator = xbt_mallocator_new(256,
53 lib_mallocator_free_f,
54 lib_mallocator_reset_f);
57 void xbt_lib_postexit(void)
59 if (lib_mallocator != NULL) {
60 xbt_mallocator_free(lib_mallocator);
61 lib_mallocator = NULL;
65 static xbt_libelm_t xbt_libelm_new(const char *key,
67 unsigned int hash_code,
68 void *content,int level, int level_numbers)
70 xbt_libelm_t element = xbt_malloc0(sizeof (s_xbt_libelm_t) + sizeof(void *)*(level_numbers-1));
72 element->key = xbt_new(char, key_len + 1);
73 memcpy((void *) element->key, (void *) key, key_len);
74 element->key[key_len] = '\0';
76 element->key_len = key_len;
77 element->hash_code = hash_code;
79 (&(element->content))[level] = content;
85 xbt_lib_t xbt_lib_new(void)
88 lib = xbt_mallocator_get(lib_mallocator);
89 lib->table_size = 127;
90 lib->table = xbt_new0(xbt_libelm_t, lib->table_size + 1);
99 void xbt_lib_free(xbt_lib_t * lib)
102 xbt_libelm_t current, previous;
106 // if ( *dict ) xbt_dict_dump_sizes(*dict);
108 if (lib != NULL && *lib != NULL) {
109 table_size = (*lib)->table_size;
110 table = (*lib)->table;
112 for (i = 0; (*lib)->count && i <= table_size; i++) {
114 while (current != NULL) {
116 current = current->next;
117 xbt_free(previous->key);
118 for(j=0; j< (*lib)->levels; j++)
119 if((&(previous->content))[j])
120 (*lib)->free_f[j]( (&(previous->content))[j]);
126 xbt_free((*lib)->free_f);
127 xbt_mallocator_release(lib_mallocator, *lib);
132 int xbt_lib_add_level(xbt_lib_t lib, void_f_pvoid_t free_f)
134 XBT_DEBUG("xbt_lib_add_level");
136 lib->free_f = realloc(lib->free_f,sizeof(void_f_pvoid_t)*(lib->levels+1));
137 lib->free_f[lib->levels]=free_f;
138 return lib->levels++;
141 void xbt_lib_set(xbt_lib_t lib, const char *name, int level, void *obj)
143 XBT_INFO("xbt_lib_set key '%s' with object '%p'",name,obj);
144 xbt_lib_set_ext(lib, name, strlen(name),level, obj);
147 void *xbt_lib_get_or_null(xbt_lib_t lib, const char *key, int level)
149 unsigned int hash_code = xbt_lib_hash(key);
150 xbt_libelm_t current;
152 if(!lib) xbt_die("Lib is NULL!");
154 current = lib->table[hash_code & lib->table_size];
155 while (current != NULL &&
156 (hash_code != current->hash_code || strcmp(key, current->key)))
157 current = current->next;
162 return (&(current->content))[level];
165 static void *lib_mallocator_new_f(void)
167 return xbt_new(s_xbt_lib_t, 1);
170 static void lib_mallocator_free_f(void *lib)
175 static void lib_mallocator_reset_f(void *lib)
177 /* nothing to do because all fields are
178 * initialized in xbt_dict_new
182 void xbt_lib_reset(xbt_lib_t *lib)
184 XBT_INFO("xbt_lib_reset");
186 xbt_libelm_t current, next;
188 int levels = l->levels;
189 if(!(*lib)) xbt_die("Lib is NULL!");
194 for (i = 0; i <= l->table_size; i++) {
195 current = l->table[i];
197 next = current->next;
198 xbt_free(current->key);
199 for(j=0; j< levels; j++)
200 if((&(current->content))[j] && (l->free_f[j]))
201 l->free_f[j]((&(current->content))[j]);
214 int xbt_lib_length(xbt_lib_t lib)
216 if(!lib) xbt_die("Lib is NULL!");
220 static void xbt_lib_set_ext(xbt_lib_t lib,
227 unsigned int hash_code = xbt_lib_hash_ext(key, key_len);
229 xbt_libelm_t current, previous = NULL;
230 if(!lib) xbt_die("Lib is NULL!");
232 XBT_DEBUG("ADD '%.*s' hash = '%d', size = '%d', & = '%d' to level : %d",
237 hash_code & lib->table_size,
240 current = lib->table[hash_code & lib->table_size];
241 while (current != NULL &&
242 (hash_code != current->hash_code || key_len != current->key_len
243 || memcmp(key, current->key, key_len))) {
245 current = current->next;
248 if (current == NULL) {/* this key doesn't exist yet */
249 current = xbt_libelm_new(key, key_len, hash_code, data,level,lib->levels);
251 if (previous == NULL) {
252 lib->table[hash_code & lib->table_size] = current;
254 if ((lib->fill * 100) / (lib->table_size + 1) > MAX_FILL_PERCENT)
257 previous->next = current;
261 if( (&(current->content))[level] == NULL )/* this key exist but level is empty */
263 (&(current->content))[level] = data;
266 {/* there is already an element with the same key: overwrite it */
267 XBT_INFO("Replace %.*s by %.*s under key %.*s",
268 key_len, (char *) (&(current->content))[level],
269 key_len, (char *) data, key_len, (char *) key);
270 if (current->content != NULL) {
271 free((&(current->content))[level]);
273 (&(current->content))[level] = data;
278 * Returns the hash code of a string.
280 static unsigned int xbt_lib_hash_ext(const char *str,
285 #ifdef DJB2_HASH_FUNCTION
286 /* fast implementation of djb2 algorithm */
288 register unsigned int hash = 5381;
292 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
294 # elif defined(FNV_HASH_FUNCTION)
295 register unsigned int hash = 0x811c9dc5;
296 unsigned char *bp = (unsigned char *) str; /* start of buffer */
297 unsigned char *be = bp + str_len; /* beyond end of buffer */
300 /* multiply by the 32 bit FNV magic prime mod 2^32 */
302 (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) +
305 /* xor the bottom with the current octet */
306 hash ^= (unsigned int) *bp++;
310 register unsigned int hash = 0;
313 hash += (*str) * (*str);
321 static unsigned int xbt_lib_hash(const char *str)
323 #ifdef DJB2_HASH_FUNCTION
324 /* fast implementation of djb2 algorithm */
326 register unsigned int hash = 5381;
328 while ((c = *str++)) {
329 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
332 # elif defined(FNV_HASH_FUNCTION)
333 register unsigned int hash = 0x811c9dc5;
336 /* multiply by the 32 bit FNV magic prime mod 2^32 */
338 (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) +
341 /* xor the bottom with the current byte */
342 hash ^= (unsigned int) *str++;
346 register unsigned int hash = 0;
349 hash += (*str) * (*str);
356 static void xbt_lib_rehash(xbt_lib_t lib)
358 xbt_die("xbt_lib_rehash not yet implemented!");
361 void xbt_lib_cursor_first(const xbt_lib_t lib,
362 xbt_lib_cursor_t * cursor)
364 XBT_DEBUG("xbt_lib_cursor_first");
366 XBT_DEBUG("Create the cursor on first use");
367 *cursor = xbt_lib_cursor_new(lib);
369 xbt_lib_cursor_rewind(*cursor);
371 if (lib != NULL && (*cursor)->current == NULL) {
372 xbt_lib_cursor_step(*cursor); /* find the first element */
376 static xbt_lib_cursor_t xbt_lib_cursor_new(const xbt_lib_t lib)
378 xbt_lib_cursor_t res = NULL;
380 res = xbt_new(s_xbt_lib_cursor_t, 1);
383 xbt_lib_cursor_rewind(res);
388 static void xbt_lib_cursor_rewind(xbt_lib_cursor_t cursor)
390 XBT_DEBUG("xbt_lib_cursor_rewind");
394 if (cursor->lib != NULL) {
395 cursor->current = cursor->lib->table[0];
397 cursor->current = NULL;
401 int xbt_lib_cursor_get_or_free(xbt_lib_cursor_t * cursor,
402 char **key, void **data)
405 xbt_libelm_t current;
407 XBT_DEBUG("xbt_lib_get_or_free");
409 if (!cursor || !(*cursor))
412 current = (*cursor)->current;
413 if (current == NULL) { /* no data left */
414 xbt_lib_cursor_free(cursor);
419 *data = &(current->content);
423 static void xbt_lib_cursor_free(xbt_lib_cursor_t * cursor)
431 void xbt_lib_cursor_step(xbt_lib_cursor_t cursor)
433 xbt_libelm_t current;
436 XBT_DEBUG("xbt_lib_cursor_step");
439 current = cursor->current;
442 if (cursor->lib != NULL) {
444 if (current != NULL) {
445 XBT_DEBUG("current is not null, take the next element");
446 current = current->next;
447 XBT_DEBUG("next element: %p", current);
450 while (current == NULL && ++line <= cursor->lib->table_size) {
451 XBT_DEBUG("current is NULL, take the next line");
452 current = cursor->lib->table[line];
453 XBT_DEBUG("element in the next line: %p", current);
455 XBT_DEBUG("search finished, current = %p, line = %d", current, line);
457 cursor->current = current;