util: add nm_utils_array_remove_at_indexes() function

This commit is contained in:
Thomas Haller
2015-03-27 11:55:51 +01:00
parent 3179b45412
commit e65639bde9
3 changed files with 175 additions and 0 deletions

View File

@@ -150,6 +150,80 @@ nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_
return dst;
}
void
nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len)
{
gsize elt_size;
guint index_to_delete;
guint i_src;
guint mm_src, mm_dst, mm_len;
gsize i_itd;
guint res_length;
g_return_if_fail (array);
if (!len)
return;
g_return_if_fail (indexes_to_delete);
elt_size = g_array_get_element_size (array);
i_itd = 0;
index_to_delete = indexes_to_delete[0];
if (index_to_delete >= array->len)
g_return_if_reached ();
res_length = array->len - 1;
mm_dst = index_to_delete;
mm_src = index_to_delete;
mm_len = 0;
for (i_src = index_to_delete; i_src < array->len; i_src++) {
if (i_src < index_to_delete)
mm_len++;
else {
/* we require indexes_to_delete to contain non-repeated, ascending
* indexes. Otherwise we would need to presort the indexes. */
while (TRUE) {
guint dd;
if (i_itd + 1 >= len) {
index_to_delete = G_MAXUINT;
break;
}
dd = indexes_to_delete[++i_itd];
if (dd > index_to_delete) {
if (dd >= array->len)
g_warn_if_reached ();
else {
g_assert (res_length > 0);
res_length--;
}
index_to_delete = dd;
break;
}
g_warn_if_reached ();
}
if (mm_len) {
memmove (&array->data[mm_dst * elt_size],
&array->data[mm_src * elt_size],
mm_len * elt_size);
mm_dst += mm_len;
mm_src += mm_len + 1;
mm_len = 0;
} else
mm_src++;
}
}
if (mm_len) {
memmove (&array->data[mm_dst * elt_size],
&array->data[mm_src * elt_size],
mm_len * elt_size);
}
g_array_set_size (array, res_length);
}
int
nm_spawn_process (const char *args, GError **error)

View File

@@ -183,6 +183,8 @@ void nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
GVariant *nm_utils_connection_hash_to_dict (GHashTable *hash);
GHashTable *nm_utils_connection_dict_to_hash (GVariant *dict);
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
void nm_utils_setpgid (gpointer unused);
#endif /* __NETWORKMANAGER_UTILS_H__ */

View File

@@ -330,6 +330,104 @@ test_nm_utils_kill_child (void)
g_test_assert_expected_messages ();
}
/*******************************************/
static void
_remove_at_indexes_init_random_idx (GArray *idx, guint array_len, guint idx_len)
{
GRand *rand = nmtst_get_rand ();
gs_free char *mask = NULL;
guint i, max_test_idx;
g_assert (idx);
g_assert (array_len > 0);
g_assert (idx_len >= 1 && idx_len <= array_len);
mask = g_new0 (char, array_len);
max_test_idx = array_len - 1;
for (i = 0; i < idx_len; i++) {
guint itest;
/* find a index itest that is not yet taken */
if (max_test_idx == 0)
itest = 0;
else
itest = g_rand_int_range (rand, 0, max_test_idx);
while (itest < array_len && mask[itest])
itest++;
g_assert (itest <= max_test_idx);
g_assert (!mask[itest]);
mask[itest] = TRUE;
if (itest == max_test_idx) {
g_assert (max_test_idx > 0 || i == idx_len - 1);
if (max_test_idx == 0)
g_assert_cmpint (i, ==, idx_len - 1);
else {
max_test_idx--;
while (max_test_idx > 0 && mask[max_test_idx])
max_test_idx--;
if (mask[max_test_idx])
g_assert_cmpint (i, ==, idx_len - 1);
}
}
}
g_array_set_size (idx, 0);
for (i = 0; i < array_len; i++) {
if (mask[i])
g_array_append_val (idx, i);
}
g_assert_cmpint (idx->len, ==, idx_len);
}
static void
test_nm_utils_array_remove_at_indexes ()
{
gs_unref_array GArray *idx = NULL, *array = NULL;
gs_unref_hashtable GHashTable *unique = NULL;
guint i_len, i_idx_len, i_rnd, i;
idx = g_array_new (FALSE, FALSE, sizeof (guint));
array = g_array_new (FALSE, FALSE, sizeof (gssize));
unique = g_hash_table_new (NULL, NULL);
for (i_len = 1; i_len < 20; i_len++) {
for (i_idx_len = 1; i_idx_len <= i_len; i_idx_len++) {
for (i_rnd = 0; i_rnd < 20; i_rnd++) {
_remove_at_indexes_init_random_idx (idx, i_len, i_idx_len);
g_array_set_size (array, i_len);
for (i = 0; i < i_len; i++)
g_array_index (array, gssize, i) = i;
nm_utils_array_remove_at_indexes (array, &g_array_index (idx, guint, 0), i_idx_len);
g_hash_table_remove_all (unique);
/* ensure that all the indexes are still unique */
for (i = 0; i < array->len; i++)
g_hash_table_add (unique, GUINT_TO_POINTER (g_array_index (array, gssize, i)));
g_assert_cmpint (g_hash_table_size (unique), ==, array->len);
for (i = 0; i < idx->len; i++)
g_hash_table_add (unique, GUINT_TO_POINTER (g_array_index (idx, guint, i)));
g_assert_cmpint (g_hash_table_size (unique), ==, i_len);
/* ensure proper sort order in array */
for (i = 0; i < array->len; i++) {
gssize i1 = g_array_index (array, gssize, i);
g_assert (i1 >= 0 && i1 < i_len);
if (i > 0) {
gsize i0 = g_array_index (array, gssize, i - 1);
g_assert_cmpint (i0, <, i1);
}
}
}
}
}
}
/*******************************************/
@@ -341,6 +439,7 @@ main (int argc, char **argv)
nmtst_init_assert_logging (&argc, &argv, "DEBUG", "DEFAULT");
g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child);
g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes);
return g_test_run ();
}