mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 10:20:11 +01:00
libnm: add NMUtilsStrStrDictKey utility
When having a hash-of-hashes where each hash is indexed by a name,
(such as GKeyFile), you can either implement it as a hash-of-hashes
or define your own version of indexes that pack both levels of names
into one key.
This is an implementation of such a key. Use it as:
GHashTable *hash = g_hash_table_new_full (_nm_utils_strstrdictkey_hash,
_nm_utils_strstrdictkey_equal,
g_free, _destroy_value);
and create keys via:
NMUtilsStrStrDictKey *k = _nm_utils_strstrdictkey_create (s1, s2);
For lookup you can use static strings (note that the static string
might increase the size of the binary):
g_hash_table_contains (hash, _nm_utils_strstrdictkey_static ("outer", "inner"))
This commit is contained in:
parent
4f98910848
commit
ec92ecedae
3 changed files with 158 additions and 0 deletions
|
|
@ -202,4 +202,14 @@ int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
|
|||
|
||||
/***********************************************************/
|
||||
|
||||
typedef struct _NMUtilsStrStrDictKey NMUtilsStrStrDictKey;
|
||||
guint _nm_utils_strstrdictkey_hash (gconstpointer a);
|
||||
gboolean _nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b);
|
||||
NMUtilsStrStrDictKey *_nm_utils_strstrdictkey_create (const char *v1, const char *v2);
|
||||
|
||||
#define _nm_utils_strstrdictkey_static(v1, v2) \
|
||||
( (NMUtilsStrStrDictKey *) ("\03" v1 "\0" v2 "") )
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3488,6 +3488,105 @@ nm_utils_bond_mode_string_to_int (const char *mode)
|
|||
|
||||
/**********************************************************************************************/
|
||||
|
||||
#define STRSTRDICTKEY_V1_SET 0x01
|
||||
#define STRSTRDICTKEY_V2_SET 0x02
|
||||
#define STRSTRDICTKEY_ALL_SET 0x03
|
||||
|
||||
struct _NMUtilsStrStrDictKey {
|
||||
char type;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
guint
|
||||
_nm_utils_strstrdictkey_hash (gconstpointer a)
|
||||
{
|
||||
const NMUtilsStrStrDictKey *k = a;
|
||||
const signed char *p;
|
||||
guint32 h = 5381;
|
||||
|
||||
if (k) {
|
||||
if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
|
||||
g_return_val_if_reached (0);
|
||||
|
||||
h = (h << 5) + h + k->type;
|
||||
if (k->type & STRSTRDICTKEY_ALL_SET) {
|
||||
p = (void *) k->data;
|
||||
for (; *p != '\0'; p++)
|
||||
h = (h << 5) + h + *p;
|
||||
if (k->type == STRSTRDICTKEY_ALL_SET) {
|
||||
/* the key contains two strings. Continue... */
|
||||
h = (h << 5) + h + '\0';
|
||||
for (p++; *p != '\0'; p++)
|
||||
h = (h << 5) + h + *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const NMUtilsStrStrDictKey *k1 = a;
|
||||
const NMUtilsStrStrDictKey *k2 = b;
|
||||
|
||||
if (k1 == k2)
|
||||
return TRUE;
|
||||
if (!k1 || !k2)
|
||||
return FALSE;
|
||||
|
||||
if (k1->type != k2->type)
|
||||
return FALSE;
|
||||
|
||||
if (k1->type & STRSTRDICTKEY_ALL_SET) {
|
||||
if (strcmp (k1->data, k2->data) != 0)
|
||||
return FALSE;
|
||||
|
||||
if (k1->type == STRSTRDICTKEY_ALL_SET) {
|
||||
gsize l = strlen (k1->data) + 1;
|
||||
|
||||
return strcmp (&k1->data[l], &k2->data[l]) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NMUtilsStrStrDictKey *
|
||||
_nm_utils_strstrdictkey_create (const char *v1, const char *v2)
|
||||
{
|
||||
char type = 0;
|
||||
gsize l1 = 0, l2 = 0;
|
||||
NMUtilsStrStrDictKey *k;
|
||||
|
||||
if (!v1 && !v2)
|
||||
return g_malloc0 (1);
|
||||
|
||||
/* we need to distinguish between ("",NULL) and (NULL,"").
|
||||
* Thus, in @type we encode which strings we have present
|
||||
* as not-NULL. */
|
||||
if (v1) {
|
||||
type |= STRSTRDICTKEY_V1_SET;
|
||||
l1 = strlen (v1) + 1;
|
||||
}
|
||||
if (v2) {
|
||||
type |= STRSTRDICTKEY_V2_SET;
|
||||
l2 = strlen (v2) + 1;
|
||||
}
|
||||
|
||||
k = g_malloc (G_STRUCT_OFFSET (NMUtilsStrStrDictKey, data) + l1 + l2);
|
||||
k->type = type;
|
||||
if (v1)
|
||||
memcpy (&k->data[0], v1, l1);
|
||||
if (v2)
|
||||
memcpy (&k->data[l1], v2, l2);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/**********************************************************************************************/
|
||||
|
||||
/* _nm_utils_ascii_str_to_int64:
|
||||
*
|
||||
* A wrapper for g_ascii_strtoll, that checks whether the whole string
|
||||
|
|
|
|||
|
|
@ -4281,6 +4281,54 @@ test_nm_utils_ascii_str_to_int64 (void)
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
test_nm_utils_strstrdictkey ()
|
||||
{
|
||||
#define _VALUES_STATIC(_v1, _v2) { .v1 = _v1, .v2 = _v2, .v_static = _nm_utils_strstrdictkey_static (_v1, _v2), }
|
||||
const struct {
|
||||
const char *v1;
|
||||
const char *v2;
|
||||
NMUtilsStrStrDictKey *v_static;
|
||||
} *val1, *val2, values[] = {
|
||||
{ NULL, NULL },
|
||||
{ "", NULL },
|
||||
{ NULL, "" },
|
||||
{ "a", NULL },
|
||||
{ NULL, "a" },
|
||||
_VALUES_STATIC ("", ""),
|
||||
_VALUES_STATIC ("a", ""),
|
||||
_VALUES_STATIC ("", "a"),
|
||||
_VALUES_STATIC ("a", "b"),
|
||||
};
|
||||
guint i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (values); i++) {
|
||||
gs_free NMUtilsStrStrDictKey *key1 = NULL;
|
||||
|
||||
val1 = &values[i];
|
||||
|
||||
key1 = _nm_utils_strstrdictkey_create (val1->v1, val1->v2);
|
||||
if (val1->v_static) {
|
||||
g_assert (_nm_utils_strstrdictkey_equal (key1, val1->v_static));
|
||||
g_assert (_nm_utils_strstrdictkey_equal (val1->v_static, key1));
|
||||
g_assert_cmpint (_nm_utils_strstrdictkey_hash (key1), ==, _nm_utils_strstrdictkey_hash (val1->v_static));
|
||||
}
|
||||
|
||||
for (j = 0; j < G_N_ELEMENTS (values); j++) {
|
||||
gs_free NMUtilsStrStrDictKey *key2 = NULL;
|
||||
|
||||
val2 = &values[j];
|
||||
key2 = _nm_utils_strstrdictkey_create (val2->v1, val2->v2);
|
||||
if (i != j) {
|
||||
g_assert (!_nm_utils_strstrdictkey_equal (key1, key2));
|
||||
g_assert (!_nm_utils_strstrdictkey_equal (key2, key1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
test_nm_utils_dns_option_validate_do (char *option, gboolean ipv6, const NMUtilsDNSOptionDesc *descs,
|
||||
gboolean exp_result, char *exp_name, gboolean exp_value)
|
||||
|
|
@ -4764,6 +4812,7 @@ int main (int argc, char **argv)
|
|||
g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two);
|
||||
g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert);
|
||||
g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search);
|
||||
g_test_add_func ("/core/general/_nm_utils_strstrdictkey", test_nm_utils_strstrdictkey);
|
||||
|
||||
g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate);
|
||||
g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue