api: remember insertion order in hashtables

This commit is contained in:
Sébastien Helleu 2021-06-26 21:37:02 +02:00
parent 5a59482cc8
commit a48a615613
10 changed files with 554 additions and 106 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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 :

View File

@ -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:

View File

@ -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).
プロトタイプ:

View File

@ -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).
Прототип:

View File

@ -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);
}
}
}

View File

@ -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 */

View File

@ -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_string
*/
TEST(CoreHashtable, MapString)
{
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_map_string
* hashtable_dup
*/
TEST(CoreHashtable, Map)
TEST(CoreHashtable, Dup)
{
/* TODO: write tests */
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"));
}
/*