diff options
-rw-r--r-- | ChangeLog.adoc | 1 | ||||
-rw-r--r-- | ReleaseNotes.adoc | 11 | ||||
-rw-r--r-- | doc/en/weechat_plugin_api.en.adoc | 9 | ||||
-rw-r--r-- | doc/fr/weechat_plugin_api.fr.adoc | 11 | ||||
-rw-r--r-- | doc/it/weechat_plugin_api.it.adoc | 13 | ||||
-rw-r--r-- | doc/ja/weechat_plugin_api.ja.adoc | 12 | ||||
-rw-r--r-- | doc/sr/weechat_plugin_api.sr.adoc | 12 | ||||
-rw-r--r-- | src/core/wee-hashtable.c | 181 | ||||
-rw-r--r-- | src/core/wee-hashtable.h | 6 | ||||
-rw-r--r-- | tests/unit/core/test-core-hashtable.cpp | 404 |
10 files changed, 554 insertions, 106 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc index 21b17d98b..36bd24665 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -21,6 +21,7 @@ https://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes] New features:: * core: add option "certs" in command /debug + * api: remember insertion order in hashtables * api: add keys/values with tags in output of irc_message_parse_to_hashtable (issue #1654) * irc: implement IRCv3.2 SASL authentication, add command /auth, reconnect by default to the server in case of SASL authentication failure (issue #413) * irc: add support of capability "message-tags" and TAGMSG messages (issue #1654) diff --git a/ReleaseNotes.adoc b/ReleaseNotes.adoc index c453006c2..ca8623cea 100644 --- a/ReleaseNotes.adoc +++ b/ReleaseNotes.adoc @@ -20,6 +20,17 @@ https://weechat.org/files/changelog/ChangeLog-devel.html[ChangeLog] [[v3.3]] == Version 3.3 (under dev) +[[v3.3_ordered_hashtables]] +=== Ordered hashtables + +Hashtables entries are now ordered by creation date, the following functions +are now returning entries sorted by insertion order: + +* hashtable_map +* hashtable_map_string +* hashtable_get_string (all properties except "keys_sorted" and "keys_values_sorted") +* hashtable_add_to_infolist + [[v3.3_irc_default_capabilities]] === IRC default capabilities diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index e2e089d0c..c91069732 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -5220,7 +5220,8 @@ This function is not available in scripting API. _WeeChat ≥ 0.3.3._ -Call a function on all hashtable entries. +Call a function on all hashtable entries, by insertion order in the hashtable +(from oldest to newest one). Prototype: @@ -5264,7 +5265,8 @@ This function is not available in scripting API. _WeeChat ≥ 0.3.7._ -Call a function on all hashtable entries, sending keys and values as strings. +Call a function on all hashtable entries, by insertion order in the hashtable +(from oldest to newest one), sending keys and values as strings. Prototype: @@ -5478,7 +5480,8 @@ This function is not available in scripting API. _WeeChat ≥ 0.3.3._ -Add hashtable items to an infolist item. +Add hashtable items to an infolist item, by insertion order in the hashtable +(from oldest to newest one). Prototype: diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index 2dc757f35..b6281f3c4 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -5298,7 +5298,8 @@ Cette fonction n'est pas disponible dans l'API script. _WeeChat ≥ 0.3.3._ -Appeller une fonction pour chaque entrée d'une table de hachage. +Appeller une fonction pour chaque entrée d'une table de hachage, par ordre +d'insertion dans la table de hachage (de la plus ancienne à la plus récente). Prototype : @@ -5343,8 +5344,9 @@ Cette fonction n'est pas disponible dans l'API script. _WeeChat ≥ 0.3.7._ -Appeller une fonction pour chaque entrée d'une table de hachage, en envoyant les -clés et valeurs sous forme de chaînes. +Appeller une fonction pour chaque entrée d'une table de hachage, par ordre +d'insertion dans la table de hachage (de la plus ancienne à la plus récente), +en envoyant les clés et valeurs sous forme de chaînes. Prototype : @@ -5563,7 +5565,8 @@ Cette fonction n'est pas disponible dans l'API script. _WeeChat ≥ 0.3.3._ -Ajouter les éléments d'une table de hachage dans un objet infolist. +Ajouter les éléments d'une table de hachage dans un objet infolist, par ordre +d'insertion dans la table de hachage (de la plus ancienne à la plus récente). Prototype : diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index f99fe73cf..5b2db4819 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -5410,7 +5410,9 @@ Questa funzione non è disponibile nelle API per lo scripting. _WeeChat ≥ 0.3.3._ -Chiama una funzione su tutte le voci della tabella hash. +// TRANSLATION MISSING +Chiama una funzione su tutte le voci della tabella hash, by insertion order +in the hashtable (from oldest to newest one). Prototipo: @@ -5454,8 +5456,9 @@ Questa funzione non è disponibile nelle API per lo scripting. _WeeChat ≥ 0.3.7._ -Chiama una funzione su tutte le voci della tabella hash, inviando chiavi e -valori come stringhe. +// TRANSLATION MISSING +Chiama una funzione su tutte le voci della tabella hash, by insertion order +in the hashtable (from oldest to newest one), inviando chiavi e valori come stringhe. Prototipo: @@ -5674,7 +5677,9 @@ Questa funzione non è disponibile nelle API per lo scripting. _WeeChat ≥ 0.3.3._ -Aggiunge elementi della tabella hash ad un elemento della lista info. +// TRANSLATION MISSING +Aggiunge elementi della tabella hash ad un elemento della lista info, by insertion +order in the hashtable (from oldest to newest one). Prototipo: diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index a833c0233..cc4cf1c6b 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -5269,7 +5269,9 @@ if (weechat_hashtable_has_key (hashtable, "my_key")) _WeeChat バージョン 0.3.3 以上で利用可。_ -ハッシュテーブルのすべてのエントリに対して関数を呼び出す。 +// TRANSLATION MISSING +ハッシュテーブルのすべてのエントリに対して関数を呼び出す, +by insertion order in the hashtable (from oldest to newest one). プロトタイプ: @@ -5313,7 +5315,9 @@ weechat_hashtable_map (hashtable, &map_cb, NULL); _WeeChat バージョン 0.3.7 以上で利用可。_ -ハッシュテーブルのすべてのエントリに対して関数を呼び出す、キーと値を文字列として関数に渡す。 +// TRANSLATION MISSING +Call a function on all hashtable entries, by insertion order in the hashtable +(from oldest to newest one), sending keys and values as strings. プロトタイプ: @@ -5527,7 +5531,9 @@ weechat_hashtable_set_pointer (hashtable, "callback_free_key", &my_free_key_cb); _WeeChat バージョン 0.3.3 以上で利用可。_ -ハッシュテーブルの要素をインフォリスト要素に追加 +// TRANSLATION MISSING +ハッシュテーブルの要素をインフォリスト要素に追加, by insertion order in the hashtable +(from oldest to newest one). プロトタイプ: diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index 12539794a..e023350aa 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -5057,7 +5057,9 @@ if (weechat_hashtable_has_key (hashtable, "my_key")) _WeeChat ≥ 0.3.3._ -Позива функцију над свим ставкама хеш табеле. +// TRANSLATION MISSING +Позива функцију над свим ставкама хеш табеле, by insertion order in the hashtable +(from oldest to newest one). Прототип: @@ -5101,7 +5103,9 @@ weechat_hashtable_map (hashtable, &map_cb, NULL); _WeeChat ≥ 0.3.7._ -Позива функцију над свим ставкама хеш табеле и шаље јој кључеве и вредности као стрингове. +// TRANSLATION MISSING +Call a function on all hashtable entries, by insertion order in the hashtable +(from oldest to newest one), sending keys and values as strings. Прототип: @@ -5311,7 +5315,9 @@ weechat_hashtable_set_pointer (hashtable, "callback_free_key", &my_free_key_cb); _WeeChat ≥ 0.3.3._ -Додаје ставе хеш табеле у ставку инфо листе. +// TRANSLATION MISSING +Додаје ставе хеш табеле у ставку инфо листе, by insertion order in the hashtable +(from oldest to newest one). Прототип: diff --git a/src/core/wee-hashtable.c b/src/core/wee-hashtable.c index 0d6ed2602..72743750d 100644 --- a/src/core/wee-hashtable.c +++ b/src/core/wee-hashtable.c @@ -228,6 +228,8 @@ hashtable_new (int size, new_hashtable->htable[i] = NULL; } new_hashtable->items_count = 0; + new_hashtable->oldest_item = NULL; + new_hashtable->newest_item = NULL; new_hashtable->callback_hash_key = (callback_hash_key) ? callback_hash_key : &hashtable_hash_key_default_cb; @@ -439,6 +441,15 @@ hashtable_set_with_size (struct t_hashtable *hashtable, hashtable->htable[hash] = new_item; } + /* keep items ordered by date of creation */ + if (hashtable->newest_item) + (hashtable->newest_item)->next_created_item = new_item; + else + hashtable->oldest_item = new_item; + new_item->prev_created_item = hashtable->newest_item; + new_item->next_created_item = NULL; + hashtable->newest_item = new_item; + hashtable->items_count++; return new_item; @@ -574,26 +585,22 @@ hashtable_map (struct t_hashtable *hashtable, t_hashtable_map *callback_map, void *callback_map_data) { - int i; - struct t_hashtable_item *ptr_item, *ptr_next_item; + struct t_hashtable_item *ptr_item, *ptr_next_created_item; if (!hashtable) return; - for (i = 0; i < hashtable->size; i++) + ptr_item = hashtable->oldest_item; + while (ptr_item) { - ptr_item = hashtable->htable[i]; - while (ptr_item) - { - ptr_next_item = ptr_item->next_item; + ptr_next_created_item = ptr_item->next_created_item; - (void) (callback_map) (callback_map_data, - hashtable, - ptr_item->key, - ptr_item->value); + (void) (callback_map) (callback_map_data, + hashtable, + ptr_item->key, + ptr_item->value); - ptr_item = ptr_next_item; - } + ptr_item = ptr_next_created_item; } } @@ -606,41 +613,37 @@ hashtable_map_string (struct t_hashtable *hashtable, t_hashtable_map_string *callback_map, void *callback_map_data) { - int i; - struct t_hashtable_item *ptr_item, *ptr_next_item; + struct t_hashtable_item *ptr_item, *ptr_next_created_item; const char *str_key, *str_value; char *key, *value; if (!hashtable) return; - for (i = 0; i < hashtable->size; i++) + ptr_item = hashtable->oldest_item; + while (ptr_item) { - ptr_item = hashtable->htable[i]; - while (ptr_item) - { - ptr_next_item = ptr_item->next_item; + ptr_next_created_item = ptr_item->next_created_item; - str_key = hashtable_to_string (hashtable->type_keys, - ptr_item->key); - key = (str_key) ? strdup (str_key) : NULL; + str_key = hashtable_to_string (hashtable->type_keys, + ptr_item->key); + key = (str_key) ? strdup (str_key) : NULL; - str_value = hashtable_to_string (hashtable->type_values, - ptr_item->value); - value = (str_value) ? strdup (str_value) : NULL; + str_value = hashtable_to_string (hashtable->type_values, + ptr_item->value); + value = (str_value) ? strdup (str_value) : NULL; - (void) (callback_map) (callback_map_data, - hashtable, - key, - value); + (void) (callback_map) (callback_map_data, + hashtable, + key, + value); - if (key) - free (key); - if (value) - free (value); + if (key) + free (key); + if (value) + free (value); - ptr_item = ptr_next_item; - } + ptr_item = ptr_next_created_item; } } @@ -675,6 +678,9 @@ hashtable_dup (struct t_hashtable *hashtable) { struct t_hashtable *new_hashtable; + if (!hashtable) + return NULL; + new_hashtable = hashtable_new (hashtable->size, hashtable_type_string[hashtable->type_keys], hashtable_type_string[hashtable->type_values], @@ -724,6 +730,9 @@ hashtable_get_list_keys (struct t_hashtable *hashtable) { struct t_weelist *weelist; + if (!hashtable) + return NULL; + weelist = weelist_new (); if (weelist) hashtable_map (hashtable, &hashtable_get_list_keys_map_cb, weelist); @@ -1044,7 +1053,7 @@ hashtable_add_to_infolist (struct t_hashtable *hashtable, struct t_infolist_item *infolist_item, const char *prefix) { - int i, item_number; + int item_number; struct t_hashtable_item *ptr_item; char option_name[128]; @@ -1052,52 +1061,50 @@ hashtable_add_to_infolist (struct t_hashtable *hashtable, return 0; item_number = 0; - for (i = 0; i < hashtable->size; i++) + ptr_item = hashtable->oldest_item; + while (ptr_item) { - for (ptr_item = hashtable->htable[i]; ptr_item; - ptr_item = ptr_item->next_item) + snprintf (option_name, sizeof (option_name), + "%s_name_%05d", prefix, item_number); + if (!infolist_new_var_string (infolist_item, option_name, + hashtable_to_string (hashtable->type_keys, + ptr_item->key))) + return 0; + snprintf (option_name, sizeof (option_name), + "%s_value_%05d", prefix, item_number); + switch (hashtable->type_values) { - snprintf (option_name, sizeof (option_name), - "%s_name_%05d", prefix, item_number); - if (!infolist_new_var_string (infolist_item, option_name, - hashtable_to_string (hashtable->type_keys, - ptr_item->key))) - return 0; - snprintf (option_name, sizeof (option_name), - "%s_value_%05d", prefix, item_number); - switch (hashtable->type_values) - { - case HASHTABLE_INTEGER: - if (!infolist_new_var_integer (infolist_item, option_name, - *((int *)ptr_item->value))) - return 0; - break; - case HASHTABLE_STRING: - if (!infolist_new_var_string (infolist_item, option_name, - (const char *)ptr_item->value)) - return 0; - break; - case HASHTABLE_POINTER: - if (!infolist_new_var_pointer (infolist_item, option_name, - ptr_item->value)) - return 0; - break; - case HASHTABLE_BUFFER: - if (!infolist_new_var_buffer (infolist_item, option_name, - ptr_item->value, - ptr_item->value_size)) - return 0; - break; - case HASHTABLE_TIME: - if (!infolist_new_var_time (infolist_item, option_name, - *((time_t *)ptr_item->value))) - return 0; - break; - case HASHTABLE_NUM_TYPES: - break; - } - item_number++; + case HASHTABLE_INTEGER: + if (!infolist_new_var_integer (infolist_item, option_name, + *((int *)ptr_item->value))) + return 0; + break; + case HASHTABLE_STRING: + if (!infolist_new_var_string (infolist_item, option_name, + (const char *)ptr_item->value)) + return 0; + break; + case HASHTABLE_POINTER: + if (!infolist_new_var_pointer (infolist_item, option_name, + ptr_item->value)) + return 0; + break; + case HASHTABLE_BUFFER: + if (!infolist_new_var_buffer (infolist_item, option_name, + ptr_item->value, + ptr_item->value_size)) + return 0; + break; + case HASHTABLE_TIME: + if (!infolist_new_var_time (infolist_item, option_name, + *((time_t *)ptr_item->value))) + return 0; + break; + case HASHTABLE_NUM_TYPES: + break; } + item_number++; + ptr_item = ptr_item->next_created_item; } return 1; } @@ -1203,6 +1210,16 @@ hashtable_remove_item (struct t_hashtable *hashtable, hashtable_free_value (hashtable, item); hashtable_free_key (hashtable, item); + /* remove item from ordered list (by date of creation) */ + if (item->prev_created_item) + (item->prev_created_item)->next_created_item = item->next_created_item; + if (item->next_created_item) + (item->next_created_item)->prev_created_item = item->prev_created_item; + if (hashtable->oldest_item == item) + hashtable->oldest_item = item->next_created_item; + if (hashtable->newest_item == item) + hashtable->newest_item = item->prev_created_item; + /* remove item from list */ if (item->prev_item) (item->prev_item)->next_item = item->next_item; @@ -1287,6 +1304,8 @@ hashtable_print_log (struct t_hashtable *hashtable, const char *name) log_printf (" size . . . . . . . . . : %d", hashtable->size); log_printf (" htable . . . . . . . . : 0x%lx", hashtable->htable); log_printf (" items_count. . . . . . : %d", hashtable->items_count); + log_printf (" oldest_item. . . . . . : 0x%lx", hashtable->oldest_item); + log_printf (" newest_item. . . . . . : 0x%lx", hashtable->newest_item); log_printf (" type_keys. . . . . . . : %d (%s)", hashtable->type_keys, hashtable_type_string[hashtable->type_keys]); @@ -1350,6 +1369,8 @@ hashtable_print_log (struct t_hashtable *hashtable, const char *name) log_printf (" value_size . . . . : %d", ptr_item->value_size); log_printf (" prev_item. . . . . : 0x%lx", ptr_item->prev_item); log_printf (" next_item. . . . . : 0x%lx", ptr_item->next_item); + log_printf (" prev_created_item. : 0x%lx", ptr_item->prev_created_item); + log_printf (" next_created_item. : 0x%lx", ptr_item->next_created_item); } } } diff --git a/src/core/wee-hashtable.h b/src/core/wee-hashtable.h index 860a7f8da..90c943776 100644 --- a/src/core/wee-hashtable.h +++ b/src/core/wee-hashtable.h @@ -117,6 +117,10 @@ struct t_hashtable_item int value_size; /* size of value (in bytes) */ struct t_hashtable_item *prev_item; /* link to previous item */ struct t_hashtable_item *next_item; /* link to next item */ + /* previous/next item by order of creation in the hashtable */ + struct t_hashtable_item *prev_created_item; + struct t_hashtable_item *next_created_item; + }; struct t_hashtable @@ -125,6 +129,8 @@ struct t_hashtable struct t_hashtable_item **htable; /* table to map hashes with linked */ /* lists */ int items_count; /* number of items in hashtable */ + struct t_hashtable_item *oldest_item; /* oldest item in hashtable */ + struct t_hashtable_item *newest_item; /* newest item in hashtable */ /* type for keys and values */ enum t_hashtable_type type_keys; /* type for keys: int/str/pointer */ diff --git a/tests/unit/core/test-core-hashtable.cpp b/tests/unit/core/test-core-hashtable.cpp index abcaec2ca..2e209847c 100644 --- a/tests/unit/core/test-core-hashtable.cpp +++ b/tests/unit/core/test-core-hashtable.cpp @@ -25,6 +25,8 @@ extern "C" { #include <string.h> #include "src/core/wee-hashtable.h" +#include "src/core/wee-infolist.h" +#include "src/core/wee-list.h" #include "src/plugins/plugin.h" } @@ -34,8 +36,27 @@ extern "C" #define HASHTABLE_TEST_KEY_LONG_HASH 11232856562070989738ULL #define HASHTABLE_TEST_VALUE "this is a value" +char *test_map_string = NULL; + TEST_GROUP(CoreHashtable) { + struct t_hashtable *get_weechat_hashtable () + { + struct t_hashtable *hashtable; + + hashtable = hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + hashtable_set (hashtable, "weechat", "the first item"); + hashtable_set (hashtable, "light", "item2"); + hashtable_set (hashtable, "fast", "item3"); + hashtable_set (hashtable, "extensible", "item4"); + hashtable_set (hashtable, "chat", "item5"); + hashtable_set (hashtable, "client", "last item"); + return hashtable; + } }; /* @@ -121,6 +142,8 @@ TEST(CoreHashtable, New) LONGS_EQUAL(32, hashtable->size); CHECK(hashtable->htable); LONGS_EQUAL(0, hashtable->items_count); + POINTERS_EQUAL(NULL, hashtable->oldest_item); + POINTERS_EQUAL(NULL, hashtable->newest_item); LONGS_EQUAL(HASHTABLE_STRING, hashtable->type_keys); LONGS_EQUAL(HASHTABLE_INTEGER, hashtable->type_values); POINTERS_EQUAL(&test_hashtable_hash_key_cb, hashtable->callback_hash_key); @@ -169,23 +192,31 @@ TEST(CoreHashtable, SetGetRemove) item = hashtable_set (hashtable, str_key, NULL); CHECK(item); LONGS_EQUAL(1, hashtable->items_count); + CHECK(hashtable->oldest_item); + CHECK(hashtable->newest_item); STRCMP_EQUAL(str_key, (const char *)item->key); LONGS_EQUAL(strlen (str_key) + 1, item->key_size); POINTERS_EQUAL(NULL, item->value); LONGS_EQUAL(0, item->value_size); POINTERS_EQUAL(NULL, item->prev_item); POINTERS_EQUAL(NULL, item->next_item); + POINTERS_EQUAL(NULL, item->prev_created_item); + POINTERS_EQUAL(NULL, item->next_created_item); /* set a string value for the same key */ item = hashtable_set (hashtable, str_key, str_value); CHECK(item); LONGS_EQUAL(1, hashtable->items_count); + CHECK(hashtable->oldest_item); + CHECK(hashtable->newest_item); STRCMP_EQUAL(str_key, (const char *)item->key); LONGS_EQUAL(strlen (str_key) + 1, item->key_size); STRCMP_EQUAL(str_value, (const char *)item->value); LONGS_EQUAL(strlen (str_value) + 1, item->value_size); POINTERS_EQUAL(NULL, item->prev_item); POINTERS_EQUAL(NULL, item->next_item); + POINTERS_EQUAL(NULL, item->prev_created_item); + POINTERS_EQUAL(NULL, item->next_created_item); /* get item */ item = hashtable_get_item (hashtable, str_key, &hash); @@ -208,6 +239,8 @@ TEST(CoreHashtable, SetGetRemove) /* delete an item */ hashtable_remove (hashtable, str_key); LONGS_EQUAL(0, hashtable->items_count); + POINTERS_EQUAL(NULL, hashtable->oldest_item); + POINTERS_EQUAL(NULL, hashtable->newest_item); /* add an item with size in hashtable */ item = hashtable_set_with_size (hashtable, @@ -215,6 +248,8 @@ TEST(CoreHashtable, SetGetRemove) str_value, strlen (str_value) + 1); CHECK(item); LONGS_EQUAL(1, hashtable->items_count); + CHECK(hashtable->oldest_item); + CHECK(hashtable->newest_item); STRCMP_EQUAL(str_key, (const char *)item->key); LONGS_EQUAL(strlen (str_key) + 1, item->key_size); STRCMP_EQUAL(str_value, (const char *)item->value); @@ -223,6 +258,15 @@ TEST(CoreHashtable, SetGetRemove) /* add another item */ hashtable_set (hashtable, "xxx", "zzz"); LONGS_EQUAL(2, hashtable->items_count); + CHECK(hashtable->oldest_item); + CHECK(hashtable->newest_item); + CHECK(hashtable->oldest_item != hashtable->newest_item); + CHECK(hashtable->oldest_item->next_created_item == hashtable->newest_item); + STRCMP_EQUAL(str_key, (const char *)hashtable->oldest_item->key); + STRCMP_EQUAL("xxx", + (const char *)hashtable->oldest_item->next_created_item->key); + STRCMP_EQUAL("xxx", + (const char *)hashtable->newest_item->key); /* * test duplication of hashtable and check that duplicated content is @@ -273,7 +317,17 @@ TEST(CoreHashtable, SetGetRemove) /* remove all items */ hashtable_remove_all (hashtable); + POINTERS_EQUAL(NULL, hashtable->htable[0]); + POINTERS_EQUAL(NULL, hashtable->htable[1]); + POINTERS_EQUAL(NULL, hashtable->htable[2]); + POINTERS_EQUAL(NULL, hashtable->htable[3]); + POINTERS_EQUAL(NULL, hashtable->htable[4]); + POINTERS_EQUAL(NULL, hashtable->htable[5]); + POINTERS_EQUAL(NULL, hashtable->htable[6]); + POINTERS_EQUAL(NULL, hashtable->htable[7]); LONGS_EQUAL(0, hashtable->items_count); + POINTERS_EQUAL(NULL, hashtable->oldest_item); + POINTERS_EQUAL(NULL, hashtable->newest_item); /* free hashtables */ hashtable_free (hashtable); @@ -313,13 +367,13 @@ TEST(CoreHashtable, SetGetRemove) CHECK(item); POINTERS_EQUAL(item, hashtable->htable[7]); - item = hashtable_set (hashtable, "fast", NULL); + item = hashtable_set (hashtable, "light", NULL); CHECK(item); POINTERS_EQUAL(item, hashtable->htable[3]); - item = hashtable_set (hashtable, "light", NULL); + item = hashtable_set (hashtable, "fast", NULL); CHECK(item); - POINTERS_EQUAL(item, hashtable->htable[3]->next_item); + POINTERS_EQUAL(item, hashtable->htable[3]); item = hashtable_set (hashtable, "extensible", NULL); CHECK(item); @@ -333,32 +387,335 @@ TEST(CoreHashtable, SetGetRemove) CHECK(item); POINTERS_EQUAL(item, hashtable->htable[6]); + /* check items by order of creation */ + ptr_item = hashtable->oldest_item; + STRCMP_EQUAL("weechat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("light", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("fast", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("client", (const char *)ptr_item->key); + STRCMP_EQUAL("client", (const char *)hashtable->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + /* remove items and check again by order of creation */ + hashtable_remove (hashtable, "fast"); + LONGS_EQUAL(5, hashtable->items_count); + ptr_item = hashtable->oldest_item; + STRCMP_EQUAL("weechat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("light", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("client", (const char *)ptr_item->key); + STRCMP_EQUAL("client", (const char *)hashtable->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + hashtable_remove (hashtable, "light"); + LONGS_EQUAL(4, hashtable->items_count); + ptr_item = hashtable->oldest_item; + STRCMP_EQUAL("weechat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("client", (const char *)ptr_item->key); + STRCMP_EQUAL("client", (const char *)hashtable->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + hashtable_remove (hashtable, "weechat"); + LONGS_EQUAL(3, hashtable->items_count); + ptr_item = hashtable->oldest_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("client", (const char *)ptr_item->key); + STRCMP_EQUAL("client", (const char *)hashtable->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + hashtable_remove (hashtable, "client"); + LONGS_EQUAL(2, hashtable->items_count); + ptr_item = hashtable->oldest_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + STRCMP_EQUAL("chat", (const char *)hashtable->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + /* check current content of hashtable */ + POINTERS_EQUAL(NULL, hashtable->htable[0]); + POINTERS_EQUAL(NULL, hashtable->htable[1]); + STRCMP_EQUAL("extensible", (const char *)hashtable->htable[2]->key); + POINTERS_EQUAL(NULL, hashtable->htable[3]); + POINTERS_EQUAL(NULL, hashtable->htable[4]); + STRCMP_EQUAL("chat", (const char *)hashtable->htable[5]->key); + POINTERS_EQUAL(NULL, hashtable->htable[6]); + POINTERS_EQUAL(NULL, hashtable->htable[7]); + /* free hashtable */ hashtable_free (hashtable); } +void +test_hashtable_map_string_cb (void *data, + struct t_hashtable *hashtable, + const char *key, const char *value) +{ + /* make C++ compiler happy */ + (void) hashtable; + (void) data; + + if (test_map_string[0]) + strcat (test_map_string, ";"); + strcat (test_map_string, key); + strcat (test_map_string, ":"); + strcat (test_map_string, value); +} + /* * Tests functions: - * hashtable_map * hashtable_map_string */ -TEST(CoreHashtable, Map) +TEST(CoreHashtable, MapString) { - /* TODO: write tests */ + struct t_hashtable *hashtable; + int value_int; + void *value_ptr; + time_t value_time; + char result[1024], value_buffer[3] = { 0x01, 0x05, 0x09 }; + + test_map_string = (char *)malloc (1024); + + /* string -> string */ + test_map_string[0] = '\0'; + hashtable = get_weechat_hashtable (); + hashtable_map_string (hashtable, &test_hashtable_map_string_cb, NULL); + STRCMP_EQUAL("weechat:the first item;light:item2;fast:item3;" + "extensible:item4;chat:item5;client:last item", + test_map_string); + + /* integer -> pointer */ + test_map_string[0] = '\0'; + hashtable = hashtable_new (8, + WEECHAT_HASHTABLE_INTEGER, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + value_int = 123; + value_ptr = (void *)0x123abc; + hashtable_set (hashtable, &value_int, value_ptr); + value_int = 45678; + value_ptr = (void *)0xdef789; + hashtable_set (hashtable, &value_int, value_ptr); + hashtable_map_string (hashtable, &test_hashtable_map_string_cb, NULL); + STRCMP_EQUAL("123:0x123abc;45678:0xdef789", test_map_string); + + /* time -> buffer */ + test_map_string[0] = '\0'; + hashtable = hashtable_new (8, + WEECHAT_HASHTABLE_TIME, + WEECHAT_HASHTABLE_BUFFER, + NULL, + NULL); + value_time = 1624693124; + hashtable_set_with_size (hashtable, + &value_time, 0, + value_buffer, sizeof (value_buffer)); + hashtable_map_string (hashtable, &test_hashtable_map_string_cb, NULL); + snprintf (result, sizeof (result), + "1624693124:0x%lx", + (unsigned long)(hashtable->newest_item->value)); + STRCMP_EQUAL(result, test_map_string); + + free (test_map_string); +} + +/* + * Tests functions: + * hashtable_map + * hashtable_dup + */ + +TEST(CoreHashtable, Dup) +{ + struct t_hashtable *hashtable, *hashtable2; + struct t_hashtable_item *ptr_item; + + hashtable = get_weechat_hashtable (); + + POINTERS_EQUAL(NULL, hashtable_dup (NULL)); + + hashtable2 = hashtable_dup (hashtable); + + LONGS_EQUAL(6, hashtable2->items_count); + ptr_item = hashtable2->oldest_item; + STRCMP_EQUAL("weechat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("light", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("fast", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("extensible", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("chat", (const char *)ptr_item->key); + ptr_item = ptr_item->next_created_item; + STRCMP_EQUAL("client", (const char *)ptr_item->key); + STRCMP_EQUAL("client", (const char *)hashtable2->newest_item->key); + ptr_item = ptr_item->next_created_item; + POINTERS_EQUAL(NULL, ptr_item); + + hashtable_free (hashtable); + hashtable_free (hashtable2); } /* * Tests functions: * hashtable_get_list_keys + */ + +TEST(CoreHashtable, GetListKeys) +{ + struct t_hashtable *hashtable; + struct t_weelist *list_keys; + + hashtable = get_weechat_hashtable (); + + POINTERS_EQUAL(NULL, hashtable_get_list_keys (NULL)); + + list_keys = hashtable_get_list_keys (hashtable); + CHECK(list_keys); + STRCMP_EQUAL("chat", weelist_string (weelist_get (list_keys, 0))); + STRCMP_EQUAL("client", weelist_string (weelist_get (list_keys, 1))); + STRCMP_EQUAL("extensible", weelist_string (weelist_get (list_keys, 2))); + STRCMP_EQUAL("fast", weelist_string (weelist_get (list_keys, 3))); + STRCMP_EQUAL("light", weelist_string (weelist_get (list_keys, 4))); + STRCMP_EQUAL("weechat", weelist_string (weelist_get (list_keys, 5))); + + hashtable_free (hashtable); +} + +/* + * Tests functions: * hashtable_get_integer + */ + +TEST(CoreHashtable, GetInteger) +{ + struct t_hashtable *hashtable; + + hashtable = get_weechat_hashtable (); + + LONGS_EQUAL(0, hashtable_get_integer (NULL, NULL)); + LONGS_EQUAL(0, hashtable_get_integer (hashtable, NULL)); + LONGS_EQUAL(0, hashtable_get_integer (hashtable, "")); + LONGS_EQUAL(0, hashtable_get_integer (hashtable, "unknown")); + + LONGS_EQUAL(8, hashtable_get_integer (hashtable, "size")); + LONGS_EQUAL(6, hashtable_get_integer (hashtable, "items_count")); + + hashtable_free (hashtable); +} + +/* + * Tests functions: * hashtable_get_string + */ + +TEST(CoreHashtable, GetString) +{ + struct t_hashtable *hashtable; + + hashtable = get_weechat_hashtable (); + + POINTERS_EQUAL(NULL, hashtable_get_string (NULL, NULL)); + POINTERS_EQUAL(NULL, hashtable_get_string (hashtable, NULL)); + POINTERS_EQUAL(NULL, hashtable_get_string (hashtable, "")); + POINTERS_EQUAL(NULL, hashtable_get_string (hashtable, "unknown")); + + STRCMP_EQUAL("string", hashtable_get_string (hashtable, "type_keys")); + STRCMP_EQUAL("string", hashtable_get_string (hashtable, "type_values")); + STRCMP_EQUAL("weechat,light,fast,extensible,chat,client", + hashtable_get_string (hashtable, "keys")); + STRCMP_EQUAL("chat,client,extensible,fast,light,weechat", + hashtable_get_string (hashtable, "keys_sorted")); + STRCMP_EQUAL("the first item,item2,item3,item4,item5,last item", + hashtable_get_string (hashtable, "values")); + STRCMP_EQUAL("weechat:the first item,light:item2,fast:item3," + "extensible:item4,chat:item5,client:last item", + hashtable_get_string (hashtable, "keys_values")); + STRCMP_EQUAL("chat:item5,client:last item,extensible:item4,fast:item3," + "light:item2,weechat:the first item", + hashtable_get_string (hashtable, "keys_values_sorted")); + + hashtable_free (hashtable); +} + +/* + * Test callback freeing key (it does nothing). + */ + +void +test_hashtable_free_key (struct t_hashtable *hashtable, void *key) +{ + /* make C++ compiler happy */ + (void) hashtable; + (void) key; +} + +/* + * Test callback freeing value (it does nothing). + */ + +void +test_hashtable_free_value (struct t_hashtable *hashtable, + const void *key, void *value) +{ + /* make C++ compiler happy */ + (void) hashtable; + (void) key; + (void) value; +} + +/* + * Tests functions: * hashtable_set_pointer */ -TEST(CoreHashtable, Properties) +TEST(CoreHashtable, SetPointer) { - /* TODO: write tests */ + struct t_hashtable *hashtable; + + hashtable = get_weechat_hashtable (); + + hashtable_set_pointer (NULL, NULL, NULL); + hashtable_set_pointer (hashtable, NULL, NULL); + hashtable_set_pointer (hashtable, "", NULL); + hashtable_set_pointer (hashtable, "unknown", NULL); + + hashtable_set_pointer (hashtable, + "callback_free_key", (void *)&test_hashtable_free_key); + POINTERS_EQUAL(&test_hashtable_free_key, hashtable->callback_free_key); + hashtable_set_pointer (hashtable, + "callback_free_value", (void *)&test_hashtable_free_value); + POINTERS_EQUAL(&test_hashtable_free_value, hashtable->callback_free_value); + + hashtable_free (hashtable); } /* @@ -369,7 +726,36 @@ TEST(CoreHashtable, Properties) TEST(CoreHashtable, Infolist) { - /* TODO: write tests */ + struct t_hashtable *hashtable; + struct t_infolist *infolist; + struct t_infolist_item *infolist_item; + + hashtable = get_weechat_hashtable (); + + infolist = infolist_new (NULL); + infolist_item = infolist_new_item (infolist); + + LONGS_EQUAL(0, hashtable_add_to_infolist (NULL, NULL, NULL)); + LONGS_EQUAL(0, hashtable_add_to_infolist (hashtable, NULL, NULL)); + LONGS_EQUAL(0, hashtable_add_to_infolist (hashtable, infolist_item, NULL)); + + LONGS_EQUAL(1, hashtable_add_to_infolist (hashtable, infolist_item, "test")); + + infolist_reset_item_cursor (infolist); + infolist_next (infolist); + + STRCMP_EQUAL("weechat", infolist_string (infolist, "test_name_00000")); + STRCMP_EQUAL("the first item", infolist_string (infolist, "test_value_00000")); + STRCMP_EQUAL("light", infolist_string (infolist, "test_name_00001")); + STRCMP_EQUAL("item2", infolist_string (infolist, "test_value_00001")); + STRCMP_EQUAL("fast", infolist_string (infolist, "test_name_00002")); + STRCMP_EQUAL("item3", infolist_string (infolist, "test_value_00002")); + STRCMP_EQUAL("extensible", infolist_string (infolist, "test_name_00003")); + STRCMP_EQUAL("item4", infolist_string (infolist, "test_value_00003")); + STRCMP_EQUAL("chat", infolist_string (infolist, "test_name_00004")); + STRCMP_EQUAL("item5", infolist_string (infolist, "test_value_00004")); + STRCMP_EQUAL("client", infolist_string (infolist, "test_name_00005")); + STRCMP_EQUAL("last item", infolist_string (infolist, "test_value_00005")); } /* |