summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-05-22 18:52:22 +0200
committerThomas Haller <thaller@redhat.com>2015-07-29 22:34:34 +0200
commitec92ecedae28c9b7e78c2de5bc378fc7afc9eaf0 (patch)
treebeb603992a706c15aeb4086124c53ec067752b02
parent4f98910848bddc4761b5b9264cebf40fc2ec6c55 (diff)
downloadNetworkManager-ec92ecedae28c9b7e78c2de5bc378fc7afc9eaf0.tar.gz
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"))
-rw-r--r--libnm-core/nm-core-internal.h10
-rw-r--r--libnm-core/nm-utils.c99
-rw-r--r--libnm-core/tests/test-general.c49
3 files changed, 158 insertions, 0 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 2ff9e5348e..ac61737e47 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -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
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index f6a9e5a05a..fec3999bce 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -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
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index e8e96bb756..dfe591298e 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -4282,6 +4282,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);